| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include "ConsoleInput.h" |
| |
|
| | #include <stdio.h> |
| | #include <string.h> |
| |
|
| | #include <algorithm> |
| | #include <string> |
| |
|
| | #include "../include/winpty_constants.h" |
| |
|
| | #include "../shared/DebugClient.h" |
| | #include "../shared/StringBuilder.h" |
| | #include "../shared/UnixCtrlChars.h" |
| |
|
| | #include "ConsoleInputReencoding.h" |
| | #include "DebugShowInput.h" |
| | #include "DefaultInputMap.h" |
| | #include "DsrSender.h" |
| | #include "UnicodeEncoding.h" |
| | #include "Win32Console.h" |
| |
|
| | |
| | #ifndef MAPVK_VK_TO_VSC |
| | #define MAPVK_VK_TO_VSC 0 |
| | #endif |
| |
|
| | namespace { |
| |
|
| | struct MouseRecord { |
| | bool release; |
| | int flags; |
| | COORD coord; |
| |
|
| | std::string toString() const; |
| | }; |
| |
|
| | std::string MouseRecord::toString() const { |
| | StringBuilder sb(40); |
| | sb << "pos=" << coord.X << ',' << coord.Y |
| | << " flags=0x" << hexOfInt(flags); |
| | if (release) { |
| | sb << " release"; |
| | } |
| | return sb.str_moved(); |
| | } |
| |
|
| | const unsigned int kIncompleteEscapeTimeoutMs = 1000u; |
| |
|
| | #define CHECK(cond) \ |
| | do { \ |
| | if (!(cond)) { return 0; } \ |
| | } while(0) |
| |
|
| | #define ADVANCE() \ |
| | do { \ |
| | pch++; \ |
| | if (pch == stop) { return -1; } \ |
| | } while(0) |
| |
|
| | #define SCAN_INT(out, maxLen) \ |
| | do { \ |
| | (out) = 0; \ |
| | CHECK(isdigit(*pch)); \ |
| | const char *begin = pch; \ |
| | do { \ |
| | CHECK(pch - begin + 1 < maxLen); \ |
| | (out) = (out) * 10 + *pch - '0'; \ |
| | ADVANCE(); \ |
| | } while (isdigit(*pch)); \ |
| | } while(0) |
| |
|
| | #define SCAN_SIGNED_INT(out, maxLen) \ |
| | do { \ |
| | bool negative = false; \ |
| | if (*pch == '-') { \ |
| | negative = true; \ |
| | ADVANCE(); \ |
| | } \ |
| | SCAN_INT(out, maxLen); \ |
| | if (negative) { \ |
| | (out) = -(out); \ |
| | } \ |
| | } while(0) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | static int matchDsr(const char *input, int inputSize) |
| | { |
| | int32_t dummy = 0; |
| | const char *pch = input; |
| | const char *stop = input + inputSize; |
| | CHECK(*pch == '\x1B'); ADVANCE(); |
| | CHECK(*pch == '['); ADVANCE(); |
| | SCAN_INT(dummy, 8); |
| | CHECK(*pch == ';'); ADVANCE(); |
| | SCAN_INT(dummy, 8); |
| | CHECK(*pch == 'R'); |
| | return pch - input + 1; |
| | } |
| |
|
| | static int matchMouseDefault(const char *input, int inputSize, |
| | MouseRecord &out) |
| | { |
| | const char *pch = input; |
| | const char *stop = input + inputSize; |
| | CHECK(*pch == '\x1B'); ADVANCE(); |
| | CHECK(*pch == '['); ADVANCE(); |
| | CHECK(*pch == 'M'); ADVANCE(); |
| | out.flags = (*pch - 32) & 0xFF; ADVANCE(); |
| | out.coord.X = (*pch - '!') & 0xFF; |
| | ADVANCE(); |
| | out.coord.Y = (*pch - '!') & 0xFF; |
| | out.release = false; |
| | return pch - input + 1; |
| | } |
| |
|
| | static int matchMouse1006(const char *input, int inputSize, MouseRecord &out) |
| | { |
| | const char *pch = input; |
| | const char *stop = input + inputSize; |
| | int32_t temp; |
| | CHECK(*pch == '\x1B'); ADVANCE(); |
| | CHECK(*pch == '['); ADVANCE(); |
| | CHECK(*pch == '<'); ADVANCE(); |
| | SCAN_INT(out.flags, 8); |
| | CHECK(*pch == ';'); ADVANCE(); |
| | SCAN_SIGNED_INT(temp, 8); out.coord.X = temp - 1; |
| | CHECK(*pch == ';'); ADVANCE(); |
| | SCAN_SIGNED_INT(temp, 8); out.coord.Y = temp - 1; |
| | CHECK(*pch == 'M' || *pch == 'm'); |
| | out.release = (*pch == 'm'); |
| | return pch - input + 1; |
| | } |
| |
|
| | static int matchMouse1015(const char *input, int inputSize, MouseRecord &out) |
| | { |
| | const char *pch = input; |
| | const char *stop = input + inputSize; |
| | int32_t temp; |
| | CHECK(*pch == '\x1B'); ADVANCE(); |
| | CHECK(*pch == '['); ADVANCE(); |
| | SCAN_INT(out.flags, 8); out.flags -= 32; |
| | CHECK(*pch == ';'); ADVANCE(); |
| | SCAN_SIGNED_INT(temp, 8); out.coord.X = temp - 1; |
| | CHECK(*pch == ';'); ADVANCE(); |
| | SCAN_SIGNED_INT(temp, 8); out.coord.Y = temp - 1; |
| | CHECK(*pch == 'M'); |
| | out.release = false; |
| | return pch - input + 1; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | static int matchMouseRecord(const char *input, int inputSize, MouseRecord &out) |
| | { |
| | memset(&out, 0, sizeof(out)); |
| | int ret; |
| | if ((ret = matchMouse1006(input, inputSize, out)) != 0) { return ret; } |
| | if ((ret = matchMouse1015(input, inputSize, out)) != 0) { return ret; } |
| | if ((ret = matchMouseDefault(input, inputSize, out)) != 0) { return ret; } |
| | return 0; |
| | } |
| |
|
| | #undef CHECK |
| | #undef ADVANCE |
| | #undef SCAN_INT |
| |
|
| | } |
| |
|
| | ConsoleInput::ConsoleInput(HANDLE conin, int mouseMode, DsrSender &dsrSender, |
| | Win32Console &console) : |
| | m_console(console), |
| | m_conin(conin), |
| | m_mouseMode(mouseMode), |
| | m_dsrSender(dsrSender) |
| | { |
| | addDefaultEntriesToInputMap(m_inputMap); |
| | if (hasDebugFlag("dump_input_map")) { |
| | m_inputMap.dumpInputMap(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | DWORD mode = 0; |
| | if (!GetConsoleMode(conin, &mode)) { |
| | trace("Agent startup: GetConsoleMode failed"); |
| | } else { |
| | mode |= ENABLE_EXTENDED_FLAGS; |
| | mode |= ENABLE_INSERT_MODE; |
| | if (m_mouseMode == WINPTY_MOUSE_MODE_AUTO) { |
| | mode |= ENABLE_QUICK_EDIT_MODE; |
| | } else { |
| | mode &= ~ENABLE_QUICK_EDIT_MODE; |
| | } |
| | if (!SetConsoleMode(conin, mode)) { |
| | trace("Agent startup: SetConsoleMode failed"); |
| | } |
| | } |
| |
|
| | updateInputFlags(true); |
| | } |
| |
|
| | void ConsoleInput::writeInput(const std::string &input) |
| | { |
| | if (input.size() == 0) { |
| | return; |
| | } |
| |
|
| | if (isTracingEnabled()) { |
| | static bool debugInput = hasDebugFlag("input"); |
| | if (debugInput) { |
| | std::string dumpString; |
| | for (size_t i = 0; i < input.size(); ++i) { |
| | const char ch = input[i]; |
| | const char ctrl = decodeUnixCtrlChar(ch); |
| | if (ctrl != '\0') { |
| | dumpString += '^'; |
| | dumpString += ctrl; |
| | } else { |
| | dumpString += ch; |
| | } |
| | } |
| | dumpString += " ("; |
| | for (size_t i = 0; i < input.size(); ++i) { |
| | if (i > 0) { |
| | dumpString += ' '; |
| | } |
| | const unsigned char uch = input[i]; |
| | char buf[32]; |
| | winpty_snprintf(buf, "%02X", uch); |
| | dumpString += buf; |
| | } |
| | dumpString += ')'; |
| | trace("input chars: %s", dumpString.c_str()); |
| | } |
| | } |
| |
|
| | m_byteQueue.append(input); |
| | doWrite(false); |
| | if (!m_byteQueue.empty() && !m_dsrSent) { |
| | trace("send DSR"); |
| | m_dsrSender.sendDsr(); |
| | m_dsrSent = true; |
| | } |
| | m_lastWriteTick = GetTickCount(); |
| | } |
| |
|
| | void ConsoleInput::flushIncompleteEscapeCode() |
| | { |
| | if (!m_byteQueue.empty() && |
| | (GetTickCount() - m_lastWriteTick) > kIncompleteEscapeTimeoutMs) { |
| | doWrite(true); |
| | m_byteQueue.clear(); |
| | } |
| | } |
| |
|
| | void ConsoleInput::updateInputFlags(bool forceTrace) |
| | { |
| | const DWORD mode = inputConsoleMode(); |
| | const bool newFlagEE = (mode & ENABLE_EXTENDED_FLAGS) != 0; |
| | const bool newFlagMI = (mode & ENABLE_MOUSE_INPUT) != 0; |
| | const bool newFlagQE = (mode & ENABLE_QUICK_EDIT_MODE) != 0; |
| | const bool newFlagEI = (mode & 0x200) != 0; |
| | if (forceTrace || |
| | newFlagEE != m_enableExtendedEnabled || |
| | newFlagMI != m_mouseInputEnabled || |
| | newFlagQE != m_quickEditEnabled || |
| | newFlagEI != m_escapeInputEnabled) { |
| | trace("CONIN modes: Extended=%s, MouseInput=%s QuickEdit=%s EscapeInput=%s", |
| | newFlagEE ? "on" : "off", |
| | newFlagMI ? "on" : "off", |
| | newFlagQE ? "on" : "off", |
| | newFlagEI ? "on" : "off"); |
| | } |
| | m_enableExtendedEnabled = newFlagEE; |
| | m_mouseInputEnabled = newFlagMI; |
| | m_quickEditEnabled = newFlagQE; |
| | m_escapeInputEnabled = newFlagEI; |
| | } |
| |
|
| | bool ConsoleInput::shouldActivateTerminalMouse() |
| | { |
| | |
| | if (m_mouseMode == WINPTY_MOUSE_MODE_AUTO) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | return m_mouseInputEnabled && !m_quickEditEnabled && |
| | m_enableExtendedEnabled; |
| | } else if (m_mouseMode == WINPTY_MOUSE_MODE_FORCE) { |
| | return true; |
| | } else { |
| | return false; |
| | } |
| | } |
| |
|
| | void ConsoleInput::doWrite(bool isEof) |
| | { |
| | const char *data = m_byteQueue.c_str(); |
| | std::vector<INPUT_RECORD> records; |
| | size_t idx = 0; |
| | while (idx < m_byteQueue.size()) { |
| | int charSize = scanInput(records, &data[idx], m_byteQueue.size() - idx, isEof); |
| | if (charSize == -1) |
| | break; |
| | idx += charSize; |
| | } |
| | m_byteQueue.erase(0, idx); |
| | flushInputRecords(records); |
| | } |
| |
|
| | void ConsoleInput::flushInputRecords(std::vector<INPUT_RECORD> &records) |
| | { |
| | if (records.size() == 0) { |
| | return; |
| | } |
| | DWORD actual = 0; |
| | if (!WriteConsoleInputW(m_conin, records.data(), records.size(), &actual)) { |
| | trace("WriteConsoleInputW failed"); |
| | } |
| | records.clear(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | static void sendKeyMessage(HWND hwnd, bool isKeyDown, uint16_t virtualKey) |
| | { |
| | uint32_t scanCode = MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC); |
| | if (scanCode > 255) { |
| | scanCode = 0; |
| | } |
| | SendMessage(hwnd, isKeyDown ? WM_KEYDOWN : WM_KEYUP, virtualKey, |
| | (scanCode << 16) | 1u | (isKeyDown ? 0u : 0xc0000000u)); |
| | } |
| |
|
| | int ConsoleInput::scanInput(std::vector<INPUT_RECORD> &records, |
| | const char *input, |
| | int inputSize, |
| | bool isEof) |
| | { |
| | ASSERT(inputSize >= 1); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | 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') { |
| | |
| | int dsrLen = matchDsr(input, inputSize); |
| | if (dsrLen > 0) { |
| | trace("Received a DSR reply"); |
| | m_dsrSent = false; |
| | return dsrLen; |
| | } else if (!isEof && dsrLen == -1) { |
| | |
| | trace("Incomplete DSR match"); |
| | return -1; |
| | } |
| |
|
| | int mouseLen = scanMouseInput(records, input, inputSize); |
| | if (mouseLen > 0 || (!isEof && mouseLen == -1)) { |
| | return mouseLen; |
| | } |
| | } |
| |
|
| | |
| | InputMap::Key match; |
| | bool incomplete; |
| | int matchLen = m_inputMap.lookupKey(input, inputSize, match, incomplete); |
| | if (!isEof && incomplete) { |
| | |
| | |
| | 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; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if (input[0] == '\x1B' && inputSize >= 2 && input[1] != '\x1B') { |
| | const int len = utf8CharLength(input[1]); |
| | if (len > 0) { |
| | if (1 + len > inputSize) { |
| | |
| | trace("Incomplete UTF-8 character in Alt-<Char>"); |
| | return -1; |
| | } |
| | appendUtf8Char(records, &input[1], len, true); |
| | return 1 + len; |
| | } |
| | } |
| |
|
| | |
| | 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) { |
| | |
| | trace("Incomplete UTF-8 character"); |
| | return -1; |
| | } |
| | appendUtf8Char(records, &input[0], len, false); |
| | return len; |
| | } |
| |
|
| | int ConsoleInput::scanMouseInput(std::vector<INPUT_RECORD> &records, |
| | const char *input, |
| | int inputSize) |
| | { |
| | MouseRecord record; |
| | const int len = matchMouseRecord(input, inputSize, record); |
| | if (len <= 0) { |
| | return len; |
| | } |
| |
|
| | if (isTracingEnabled()) { |
| | static bool debugInput = hasDebugFlag("input"); |
| | if (debugInput) { |
| | trace("mouse input: %s", record.toString().c_str()); |
| | } |
| | } |
| |
|
| | const int button = record.flags & 0x03; |
| | INPUT_RECORD newRecord = {0}; |
| | newRecord.EventType = MOUSE_EVENT; |
| | MOUSE_EVENT_RECORD &mer = newRecord.Event.MouseEvent; |
| |
|
| | mer.dwMousePosition.X = |
| | m_mouseWindowRect.Left + |
| | std::max(0, std::min<int>(record.coord.X, |
| | m_mouseWindowRect.width() - 1)); |
| |
|
| | mer.dwMousePosition.Y = |
| | m_mouseWindowRect.Top + |
| | std::max(0, std::min<int>(record.coord.Y, |
| | m_mouseWindowRect.height() - 1)); |
| |
|
| | |
| | if (record.flags & 0x04) { mer.dwControlKeyState |= SHIFT_PRESSED; } |
| | if (record.flags & 0x08) { mer.dwControlKeyState |= LEFT_ALT_PRESSED; } |
| | if (record.flags & 0x10) { mer.dwControlKeyState |= LEFT_CTRL_PRESSED; } |
| |
|
| | if (record.flags & 0x40) { |
| | |
| | mer.dwEventFlags |= MOUSE_WHEELED; |
| | if (button == 0) { |
| | |
| | mer.dwButtonState |= 0x00780000; |
| | } else if (button == 1) { |
| | |
| | mer.dwButtonState |= 0xff880000; |
| | } else { |
| | |
| | return len; |
| | } |
| | } else { |
| | |
| | if (record.flags & 0x20) { mer.dwEventFlags |= MOUSE_MOVED; } |
| | if (button == 3) { |
| | m_mouseButtonState = 0; |
| | |
| | m_doubleClick.released = true; |
| | } else { |
| | const DWORD relevantFlag = |
| | (button == 0) ? FROM_LEFT_1ST_BUTTON_PRESSED : |
| | (button == 1) ? FROM_LEFT_2ND_BUTTON_PRESSED : |
| | (button == 2) ? RIGHTMOST_BUTTON_PRESSED : |
| | 0; |
| | ASSERT(relevantFlag != 0); |
| | if (record.release) { |
| | m_mouseButtonState &= ~relevantFlag; |
| | if (relevantFlag == m_doubleClick.button) { |
| | |
| | m_doubleClick.released = true; |
| | } else { |
| | |
| | m_doubleClick = DoubleClickDetection(); |
| | } |
| | } else if ((m_mouseButtonState & relevantFlag) == 0) { |
| | |
| | m_mouseButtonState |= relevantFlag; |
| | |
| | |
| | |
| | |
| | if (m_doubleClick.button == relevantFlag && |
| | m_doubleClick.pos == record.coord && |
| | (GetTickCount() - m_doubleClick.tick < |
| | GetDoubleClickTime())) { |
| | |
| | mer.dwEventFlags |= DOUBLE_CLICK; |
| | m_doubleClick = DoubleClickDetection(); |
| | } else { |
| | |
| | m_doubleClick.button = relevantFlag; |
| | m_doubleClick.pos = record.coord; |
| | m_doubleClick.tick = GetTickCount(); |
| | } |
| | } |
| | } |
| | } |
| |
|
| | mer.dwButtonState |= m_mouseButtonState; |
| |
|
| | if (m_mouseInputEnabled && !m_quickEditEnabled) { |
| | if (isTracingEnabled()) { |
| | static bool debugInput = hasDebugFlag("input"); |
| | if (debugInput) { |
| | trace("mouse event: %s", mouseEventToString(mer).c_str()); |
| | } |
| | } |
| |
|
| | records.push_back(newRecord); |
| | } |
| |
|
| | return len; |
| | } |
| |
|
| | void ConsoleInput::appendUtf8Char(std::vector<INPUT_RECORD> &records, |
| | const char *charBuffer, |
| | const int charLen, |
| | const bool terminalAltEscape) |
| | { |
| | const uint32_t codePoint = decodeUtf8(charBuffer); |
| | if (codePoint == static_cast<uint32_t>(-1)) { |
| | static bool debugInput = isTracingEnabled() && hasDebugFlag("input"); |
| | if (debugInput) { |
| | StringBuilder error(64); |
| | error << "Discarding invalid UTF-8 sequence:"; |
| | for (int i = 0; i < charLen; ++i) { |
| | error << ' '; |
| | error << hexOfInt<true, uint8_t>(charBuffer[i]); |
| | } |
| | trace("%s", error.c_str()); |
| | } |
| | return; |
| | } |
| |
|
| | const short charScan = codePoint > 0xFFFF ? -1 : VkKeyScan(codePoint); |
| | uint16_t virtualKey = 0; |
| | uint16_t winKeyState = 0; |
| | uint32_t winCodePointDn = codePoint; |
| | uint32_t winCodePointUp = codePoint; |
| | uint16_t vtKeyState = 0; |
| |
|
| | if (charScan != -1) { |
| | virtualKey = charScan & 0xFF; |
| | if (charScan & 0x100) { |
| | winKeyState |= SHIFT_PRESSED; |
| | } |
| | if (charScan & 0x200) { |
| | winKeyState |= LEFT_CTRL_PRESSED; |
| | } |
| | if (charScan & 0x400) { |
| | winKeyState |= RIGHT_ALT_PRESSED; |
| | } |
| | if (terminalAltEscape && (winKeyState & LEFT_CTRL_PRESSED)) { |
| | |
| | |
| | |
| | |
| | |
| | winCodePointDn = 0; |
| | winCodePointUp = 0; |
| | } |
| | } |
| | if (terminalAltEscape) { |
| | winCodePointUp = 0; |
| | winKeyState |= LEFT_ALT_PRESSED; |
| | vtKeyState |= LEFT_ALT_PRESSED; |
| | } |
| |
|
| | appendKeyPress(records, virtualKey, |
| | winCodePointDn, winCodePointUp, winKeyState, |
| | codePoint, vtKeyState); |
| | } |
| |
|
| | void ConsoleInput::appendKeyPress(std::vector<INPUT_RECORD> &records, |
| | const uint16_t virtualKey, |
| | const uint32_t winCodePointDn, |
| | const uint32_t winCodePointUp, |
| | const uint16_t winKeyState, |
| | const uint32_t vtCodePoint, |
| | const uint16_t vtKeyState) |
| | { |
| | const bool ctrl = (winKeyState & LEFT_CTRL_PRESSED) != 0; |
| | const bool leftAlt = (winKeyState & LEFT_ALT_PRESSED) != 0; |
| | const bool rightAlt = (winKeyState & RIGHT_ALT_PRESSED) != 0; |
| | const bool shift = (winKeyState & SHIFT_PRESSED) != 0; |
| | const bool enhanced = (winKeyState & ENHANCED_KEY) != 0; |
| | bool hasDebugInput = false; |
| |
|
| | if (isTracingEnabled()) { |
| | static bool debugInput = hasDebugFlag("input"); |
| | if (debugInput) { |
| | hasDebugInput = true; |
| | InputMap::Key key = { virtualKey, winCodePointDn, winKeyState }; |
| | trace("keypress: %s", key.toString().c_str()); |
| | } |
| | } |
| |
|
| | if (m_escapeInputEnabled && |
| | (virtualKey == VK_UP || |
| | virtualKey == VK_DOWN || |
| | virtualKey == VK_LEFT || |
| | virtualKey == VK_RIGHT || |
| | virtualKey == VK_HOME || |
| | virtualKey == VK_END) && |
| | !ctrl && !leftAlt && !rightAlt && !shift) { |
| | flushInputRecords(records); |
| | if (hasDebugInput) { |
| | trace("sending keypress to console HWND"); |
| | } |
| | sendKeyMessage(m_console.hwnd(), true, virtualKey); |
| | sendKeyMessage(m_console.hwnd(), false, virtualKey); |
| | return; |
| | } |
| |
|
| | uint16_t stepKeyState = 0; |
| | if (ctrl) { |
| | stepKeyState |= LEFT_CTRL_PRESSED; |
| | appendInputRecord(records, TRUE, VK_CONTROL, 0, stepKeyState); |
| | } |
| | if (leftAlt) { |
| | stepKeyState |= LEFT_ALT_PRESSED; |
| | appendInputRecord(records, TRUE, VK_MENU, 0, stepKeyState); |
| | } |
| | if (rightAlt) { |
| | stepKeyState |= RIGHT_ALT_PRESSED; |
| | appendInputRecord(records, TRUE, VK_MENU, 0, stepKeyState | ENHANCED_KEY); |
| | } |
| | if (shift) { |
| | stepKeyState |= SHIFT_PRESSED; |
| | appendInputRecord(records, TRUE, VK_SHIFT, 0, stepKeyState); |
| | } |
| | if (enhanced) { |
| | stepKeyState |= ENHANCED_KEY; |
| | } |
| | if (m_escapeInputEnabled) { |
| | reencodeEscapedKeyPress(records, virtualKey, vtCodePoint, vtKeyState); |
| | } else { |
| | appendCPInputRecords(records, TRUE, virtualKey, winCodePointDn, stepKeyState); |
| | } |
| | appendCPInputRecords(records, FALSE, virtualKey, winCodePointUp, stepKeyState); |
| | if (enhanced) { |
| | stepKeyState &= ~ENHANCED_KEY; |
| | } |
| | if (shift) { |
| | stepKeyState &= ~SHIFT_PRESSED; |
| | appendInputRecord(records, FALSE, VK_SHIFT, 0, stepKeyState); |
| | } |
| | if (rightAlt) { |
| | stepKeyState &= ~RIGHT_ALT_PRESSED; |
| | appendInputRecord(records, FALSE, VK_MENU, 0, stepKeyState | ENHANCED_KEY); |
| | } |
| | if (leftAlt) { |
| | stepKeyState &= ~LEFT_ALT_PRESSED; |
| | appendInputRecord(records, FALSE, VK_MENU, 0, stepKeyState); |
| | } |
| | if (ctrl) { |
| | stepKeyState &= ~LEFT_CTRL_PRESSED; |
| | appendInputRecord(records, FALSE, VK_CONTROL, 0, stepKeyState); |
| | } |
| | } |
| |
|
| | void ConsoleInput::appendCPInputRecords(std::vector<INPUT_RECORD> &records, |
| | BOOL keyDown, |
| | uint16_t virtualKey, |
| | uint32_t codePoint, |
| | uint16_t keyState) |
| | { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | wchar_t ws[2]; |
| | const int wslen = encodeUtf16(ws, codePoint); |
| |
|
| | if (wslen == 1) { |
| | appendInputRecord(records, keyDown, virtualKey, ws[0], keyState); |
| | } else if (wslen == 2) { |
| | appendInputRecord(records, keyDown, virtualKey, ws[0], keyState); |
| | appendInputRecord(records, keyDown, virtualKey, ws[1], keyState); |
| | } else { |
| | |
| | |
| | trace("INTERNAL ERROR: appendInputRecordCP: invalid codePoint: " |
| | "U+%04X", codePoint); |
| | } |
| | } |
| |
|
| | void ConsoleInput::appendInputRecord(std::vector<INPUT_RECORD> &records, |
| | BOOL keyDown, |
| | uint16_t virtualKey, |
| | wchar_t utf16Char, |
| | uint16_t keyState) |
| | { |
| | INPUT_RECORD ir = {}; |
| | ir.EventType = KEY_EVENT; |
| | ir.Event.KeyEvent.bKeyDown = keyDown; |
| | ir.Event.KeyEvent.wRepeatCount = 1; |
| | ir.Event.KeyEvent.wVirtualKeyCode = virtualKey; |
| | ir.Event.KeyEvent.wVirtualScanCode = |
| | MapVirtualKey(virtualKey, MAPVK_VK_TO_VSC); |
| | ir.Event.KeyEvent.uChar.UnicodeChar = utf16Char; |
| | ir.Event.KeyEvent.dwControlKeyState = keyState; |
| | records.push_back(ir); |
| | } |
| |
|
| | DWORD ConsoleInput::inputConsoleMode() |
| | { |
| | DWORD mode = 0; |
| | if (!GetConsoleMode(m_conin, &mode)) { |
| | trace("GetConsoleMode failed"); |
| | return 0; |
| | } |
| | return mode; |
| | } |
| |
|