aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc')
-rw-r--r--src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc239
1 files changed, 239 insertions, 0 deletions
diff --git a/src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc b/src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc
new file mode 100644
index 0000000000..191b2e1466
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/DebugShowInput.cc
@@ -0,0 +1,239 @@
+// Copyright (c) 2015 Ryan Prichard
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+#include "DebugShowInput.h"
+
+#include <windows.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string>
+
+#include "../shared/StringBuilder.h"
+#include "InputMap.h"
+
+namespace {
+
+struct Flag {
+ DWORD value;
+ const char *text;
+};
+
+static const Flag kButtonStates[] = {
+ { FROM_LEFT_1ST_BUTTON_PRESSED, "1" },
+ { FROM_LEFT_2ND_BUTTON_PRESSED, "2" },
+ { FROM_LEFT_3RD_BUTTON_PRESSED, "3" },
+ { FROM_LEFT_4TH_BUTTON_PRESSED, "4" },
+ { RIGHTMOST_BUTTON_PRESSED, "R" },
+};
+
+static const Flag kControlKeyStates[] = {
+ { CAPSLOCK_ON, "CapsLock" },
+ { ENHANCED_KEY, "Enhanced" },
+ { LEFT_ALT_PRESSED, "LAlt" },
+ { LEFT_CTRL_PRESSED, "LCtrl" },
+ { NUMLOCK_ON, "NumLock" },
+ { RIGHT_ALT_PRESSED, "RAlt" },
+ { RIGHT_CTRL_PRESSED, "RCtrl" },
+ { SCROLLLOCK_ON, "ScrollLock" },
+ { SHIFT_PRESSED, "Shift" },
+};
+
+static const Flag kMouseEventFlags[] = {
+ { DOUBLE_CLICK, "Double" },
+ { 8/*MOUSE_HWHEELED*/, "HWheel" },
+ { MOUSE_MOVED, "Move" },
+ { MOUSE_WHEELED, "Wheel" },
+};
+
+static void writeFlags(StringBuilder &out, DWORD flags,
+ const char *remainderName,
+ const Flag *table, size_t tableSize,
+ char pre, char sep, char post) {
+ DWORD remaining = flags;
+ bool wroteSomething = false;
+ for (size_t i = 0; i < tableSize; ++i) {
+ const Flag &f = table[i];
+ if ((f.value & flags) == f.value) {
+ if (!wroteSomething && pre != '\0') {
+ out << pre;
+ } else if (wroteSomething && sep != '\0') {
+ out << sep;
+ }
+ out << f.text;
+ wroteSomething = true;
+ remaining &= ~f.value;
+ }
+ }
+ if (remaining != 0) {
+ if (!wroteSomething && pre != '\0') {
+ out << pre;
+ } else if (wroteSomething && sep != '\0') {
+ out << sep;
+ }
+ out << remainderName << "(0x" << hexOfInt(remaining) << ')';
+ wroteSomething = true;
+ }
+ if (wroteSomething && post != '\0') {
+ out << post;
+ }
+}
+
+template <size_t n>
+static void writeFlags(StringBuilder &out, DWORD flags,
+ const char *remainderName,
+ const Flag (&table)[n],
+ char pre, char sep, char post) {
+ writeFlags(out, flags, remainderName, table, n, pre, sep, post);
+}
+
+} // anonymous namespace
+
+std::string controlKeyStatePrefix(DWORD controlKeyState) {
+ StringBuilder sb;
+ writeFlags(sb, controlKeyState,
+ "keyState", kControlKeyStates, '\0', '-', '-');
+ return sb.str_moved();
+}
+
+std::string mouseEventToString(const MOUSE_EVENT_RECORD &mer) {
+ const uint16_t buttons = mer.dwButtonState & 0xFFFF;
+ const int16_t wheel = mer.dwButtonState >> 16;
+ StringBuilder sb;
+ sb << "pos=" << mer.dwMousePosition.X << ','
+ << mer.dwMousePosition.Y;
+ writeFlags(sb, mer.dwControlKeyState, "keyState", kControlKeyStates, ' ', ' ', '\0');
+ writeFlags(sb, mer.dwEventFlags, "flags", kMouseEventFlags, ' ', ' ', '\0');
+ writeFlags(sb, buttons, "buttons", kButtonStates, ' ', ' ', '\0');
+ if (wheel != 0) {
+ sb << " wheel=" << wheel;
+ }
+ return sb.str_moved();
+}
+
+void debugShowInput(bool enableMouse, bool escapeInput) {
+ HANDLE conin = GetStdHandle(STD_INPUT_HANDLE);
+ DWORD origConsoleMode = 0;
+ if (!GetConsoleMode(conin, &origConsoleMode)) {
+ fprintf(stderr, "Error: could not read console mode -- "
+ "is STDIN a console handle?\n");
+ exit(1);
+ }
+ DWORD restoreConsoleMode = origConsoleMode;
+ if (enableMouse && !(restoreConsoleMode & ENABLE_EXTENDED_FLAGS)) {
+ // We need to disable QuickEdit mode, because it blocks mouse events.
+ // If ENABLE_EXTENDED_FLAGS wasn't originally in the console mode, then
+ // we have no way of knowning whether QuickEdit or InsertMode are
+ // currently enabled. Enable them both (eventually), because they're
+ // sensible defaults. This case shouldn't happen typically. See
+ // misc/EnableExtendedFlags.txt.
+ restoreConsoleMode |= ENABLE_EXTENDED_FLAGS;
+ restoreConsoleMode |= ENABLE_QUICK_EDIT_MODE;
+ restoreConsoleMode |= ENABLE_INSERT_MODE;
+ }
+ DWORD newConsoleMode = restoreConsoleMode;
+ newConsoleMode &= ~ENABLE_PROCESSED_INPUT;
+ newConsoleMode &= ~ENABLE_LINE_INPUT;
+ newConsoleMode &= ~ENABLE_ECHO_INPUT;
+ newConsoleMode |= ENABLE_WINDOW_INPUT;
+ if (enableMouse) {
+ newConsoleMode |= ENABLE_MOUSE_INPUT;
+ newConsoleMode &= ~ENABLE_QUICK_EDIT_MODE;
+ } else {
+ newConsoleMode &= ~ENABLE_MOUSE_INPUT;
+ }
+ if (escapeInput) {
+ // As of this writing (2016-06-05), Microsoft has shipped two preview
+ // builds of Windows 10 (14316 and 14342) that include a new "Windows
+ // Subsystem for Linux" that runs Ubuntu in a new subsystem. Running
+ // bash in this subsystem requires the non-legacy console mode, and the
+ // console input buffer is put into a special mode where escape
+ // sequences are written into the console input buffer. This mode is
+ // enabled with the 0x200 flag, which is as-yet undocumented.
+ // See https://github.com/rprichard/winpty/issues/82.
+ newConsoleMode |= 0x200;
+ }
+ if (!SetConsoleMode(conin, newConsoleMode)) {
+ fprintf(stderr, "Error: could not set console mode "
+ "(0x%x -> 0x%x -> 0x%x)\n",
+ static_cast<unsigned int>(origConsoleMode),
+ static_cast<unsigned int>(newConsoleMode),
+ static_cast<unsigned int>(restoreConsoleMode));
+ exit(1);
+ }
+ printf("\nPress any keys -- Ctrl-D exits\n\n");
+ INPUT_RECORD records[32];
+ DWORD actual = 0;
+ bool finished = false;
+ while (!finished &&
+ ReadConsoleInputW(conin, records, 32, &actual) && actual >= 1) {
+ StringBuilder sb;
+ for (DWORD i = 0; i < actual; ++i) {
+ const INPUT_RECORD &record = records[i];
+ if (record.EventType == KEY_EVENT) {
+ const KEY_EVENT_RECORD &ker = record.Event.KeyEvent;
+ InputMap::Key key = {
+ ker.wVirtualKeyCode,
+ ker.uChar.UnicodeChar,
+ static_cast<uint16_t>(ker.dwControlKeyState),
+ };
+ sb << "key: " << (ker.bKeyDown ? "dn" : "up")
+ << " rpt=" << ker.wRepeatCount
+ << " scn=" << (ker.wVirtualScanCode ? "0x" : "") << hexOfInt(ker.wVirtualScanCode)
+ << ' ' << key.toString() << '\n';
+ if ((ker.dwControlKeyState &
+ (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) &&
+ ker.wVirtualKeyCode == 'D') {
+ finished = true;
+ break;
+ } else if (ker.wVirtualKeyCode == 0 &&
+ ker.wVirtualScanCode == 0 &&
+ ker.uChar.UnicodeChar == 4) {
+ // Also look for a zeroed-out Ctrl-D record generated for
+ // ENABLE_VIRTUAL_TERMINAL_INPUT.
+ finished = true;
+ break;
+ }
+ } else if (record.EventType == MOUSE_EVENT) {
+ const MOUSE_EVENT_RECORD &mer = record.Event.MouseEvent;
+ sb << "mouse: " << mouseEventToString(mer) << '\n';
+ } else if (record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
+ const WINDOW_BUFFER_SIZE_RECORD &wbsr =
+ record.Event.WindowBufferSizeEvent;
+ sb << "buffer-resized: dwSize=("
+ << wbsr.dwSize.X << ','
+ << wbsr.dwSize.Y << ")\n";
+ } else if (record.EventType == MENU_EVENT) {
+ const MENU_EVENT_RECORD &mer = record.Event.MenuEvent;
+ sb << "menu-event: commandId=0x"
+ << hexOfInt(mer.dwCommandId) << '\n';
+ } else if (record.EventType == FOCUS_EVENT) {
+ const FOCUS_EVENT_RECORD &fer = record.Event.FocusEvent;
+ sb << "focus: " << (fer.bSetFocus ? "gained" : "lost") << '\n';
+ }
+ }
+
+ const auto str = sb.str_moved();
+ fwrite(str.data(), 1, str.size(), stdout);
+ fflush(stdout);
+ }
+ SetConsoleMode(conin, restoreConsoleMode);
+}