void debugShowInput()

in src/agent/DebugShowInput.cc [132:239]


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);
}