int ConsoleInput::scanInput()

in src/agent/ConsoleInput.cc [380:486]


int ConsoleInput::scanInput(std::vector<INPUT_RECORD> &records,
                            const char *input,
                            int inputSize,
                            bool isEof)
{
    ASSERT(inputSize >= 1);

    // Ctrl-C.
    //
    // In processed mode, use GenerateConsoleCtrlEvent so that Ctrl-C handlers
    // are called.  GenerateConsoleCtrlEvent unfortunately doesn't interrupt
    // ReadConsole calls[1].  Using WM_KEYDOWN/UP fixes the ReadConsole
    // problem, but breaks in background window stations/desktops.
    //
    // In unprocessed mode, there's an entry for Ctrl-C in the SimpleEncoding
    // table in DefaultInputMap.
    //
    // [1] https://github.com/rprichard/winpty/issues/116
    if (input[0] == '\x03' && (inputConsoleMode() & ENABLE_PROCESSED_INPUT)) {
        flushInputRecords(records);
        trace("Ctrl-C");
        const BOOL ret = GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
        trace("GenerateConsoleCtrlEvent: %d", ret);
        return 1;
    }

    if (input[0] == '\x1B') {
        // Attempt to match the Device Status Report (DSR) reply.
        int dsrLen = matchDsr(input, inputSize);
        if (dsrLen > 0) {
            trace("Received a DSR reply");
            m_dsrSent = false;
            return dsrLen;
        } else if (!isEof && dsrLen == -1) {
            // Incomplete DSR match.
            trace("Incomplete DSR match");
            return -1;
        }

        int mouseLen = scanMouseInput(records, input, inputSize);
        if (mouseLen > 0 || (!isEof && mouseLen == -1)) {
            return mouseLen;
        }
    }

    // Search the input map.
    InputMap::Key match;
    bool incomplete;
    int matchLen = m_inputMap.lookupKey(input, inputSize, match, incomplete);
    if (!isEof && incomplete) {
        // Incomplete match -- need more characters (or wait for a
        // timeout to signify flushed input).
        trace("Incomplete escape sequence");
        return -1;
    } else if (matchLen > 0) {
        uint32_t winCodePointDn = match.unicodeChar;
        if ((match.keyState & LEFT_CTRL_PRESSED) && (match.keyState & LEFT_ALT_PRESSED)) {
            winCodePointDn = '\0';
        }
        uint32_t winCodePointUp = winCodePointDn;
        if (match.keyState & LEFT_ALT_PRESSED) {
            winCodePointUp = '\0';
        }
        appendKeyPress(records, match.virtualKey,
                       winCodePointDn, winCodePointUp, match.keyState,
                       match.unicodeChar, match.keyState);
        return matchLen;
    }

    // Recognize Alt-<character>.
    //
    // This code doesn't match Alt-ESC, which is encoded as `ESC ESC`, but
    // maybe it should.  I was concerned that pressing ESC rapidly enough could
    // accidentally trigger Alt-ESC.  (e.g. The user would have to be faster
    // than the DSR flushing mechanism or use a decrepit terminal.  The user
    // might be on a slow network connection.)
    if (input[0] == '\x1B' && inputSize >= 2 && input[1] != '\x1B') {
        const int len = utf8CharLength(input[1]);
        if (len > 0) {
            if (1 + len > inputSize) {
                // Incomplete character.
                trace("Incomplete UTF-8 character in Alt-<Char>");
                return -1;
            }
            appendUtf8Char(records, &input[1], len, true);
            return 1 + len;
        }
    }

    // A UTF-8 character.
    const int len = utf8CharLength(input[0]);
    if (len == 0) {
        static bool debugInput = isTracingEnabled() && hasDebugFlag("input");
        if (debugInput) {
            trace("Discarding invalid input byte: %02X",
                static_cast<unsigned char>(input[0]));
        }
        return 1;
    }
    if (len > inputSize) {
        // Incomplete character.
        trace("Incomplete UTF-8 character");
        return -1;
    }
    appendUtf8Char(records, &input[0], len, false);
    return len;
}