| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include "DefaultInputMap.h" |
| |
|
| | #include <windows.h> |
| | #include <string.h> |
| |
|
| | #include <algorithm> |
| |
|
| | #include "../shared/StringBuilder.h" |
| | #include "../shared/WinptyAssert.h" |
| | #include "InputMap.h" |
| |
|
| | #define ESC "\x1B" |
| | #define DIM(x) (sizeof(x) / sizeof((x)[0])) |
| |
|
| | namespace { |
| |
|
| | struct EscapeEncoding { |
| | bool alt_prefix_allowed; |
| | char prefix; |
| | char id; |
| | int modifiers; |
| | InputMap::Key key; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const int kBare = 0x01; |
| | const int kSemiMod = 0x02; |
| | const int kBareMod = 0x04; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | const int kSuffixCtrl = 0x08; |
| | const int kSuffixShift = 0x10; |
| | const int kSuffixBoth = kSuffixCtrl | kSuffixShift; |
| |
|
| | static const EscapeEncoding escapeLetterEncodings[] = { |
| | |
| | |
| | { true, '[', 'A', kBare | kBareMod | kSemiMod, { VK_UP, '\0', 0 } }, |
| | { true, '[', 'B', kBare | kBareMod | kSemiMod, { VK_DOWN, '\0', 0 } }, |
| | { true, '[', 'C', kBare | kBareMod | kSemiMod, { VK_RIGHT, '\0', 0 } }, |
| | { true, '[', 'D', kBare | kBareMod | kSemiMod, { VK_LEFT, '\0', 0 } }, |
| |
|
| | |
| | |
| | |
| | { true, 'O', 'A', kBare, { VK_UP, '\0', 0 } }, |
| | { true, 'O', 'B', kBare, { VK_DOWN, '\0', 0 } }, |
| | { true, 'O', 'C', kBare, { VK_RIGHT, '\0', 0 } }, |
| | { true, 'O', 'D', kBare, { VK_LEFT, '\0', 0 } }, |
| |
|
| | |
| | |
| | { true, '[', 'a', kBare, { VK_UP, '\0', SHIFT_PRESSED } }, |
| | { true, '[', 'b', kBare, { VK_DOWN, '\0', SHIFT_PRESSED } }, |
| | { true, '[', 'c', kBare, { VK_RIGHT, '\0', SHIFT_PRESSED } }, |
| | { true, '[', 'd', kBare, { VK_LEFT, '\0', SHIFT_PRESSED } }, |
| | { true, 'O', 'a', kBare, { VK_UP, '\0', LEFT_CTRL_PRESSED } }, |
| | { true, 'O', 'b', kBare, { VK_DOWN, '\0', LEFT_CTRL_PRESSED } }, |
| | { true, 'O', 'c', kBare, { VK_RIGHT, '\0', LEFT_CTRL_PRESSED } }, |
| | { true, 'O', 'd', kBare, { VK_LEFT, '\0', LEFT_CTRL_PRESSED } }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | { true, '[', 'E', kBare | kSemiMod, { VK_CLEAR, '\0', 0 } }, |
| | { true, '[', 'G', kBare | kSemiMod, { VK_CLEAR, '\0', 0 } }, |
| | { true, 'O', 'G', kBare, { VK_CLEAR, '\0', 0 } }, |
| |
|
| | |
| | |
| | |
| | { true, '[', 'H', kBare | kBareMod | kSemiMod, { VK_HOME, '\0', 0 } }, |
| | { true, '[', 'F', kBare | kBareMod | kSemiMod, { VK_END, '\0', 0 } }, |
| | { true, 'O', 'H', kBare, { VK_HOME, '\0', 0 } }, |
| | { true, 'O', 'F', kBare, { VK_END, '\0', 0 } }, |
| |
|
| | |
| | { true, '[', 'P', kSemiMod, { VK_F1, '\0', 0 } }, |
| | { true, '[', 'Q', kSemiMod, { VK_F2, '\0', 0 } }, |
| | { true, '[', 'R', kSemiMod, { VK_F3, '\0', 0 } }, |
| | { true, '[', 'S', kSemiMod, { VK_F4, '\0', 0 } }, |
| |
|
| | |
| | |
| | |
| | { false, 'O', 'P', kBare | kBareMod | kSemiMod, { VK_F1, '\0', 0 } }, |
| | { false, 'O', 'Q', kBare | kBareMod | kSemiMod, { VK_F2, '\0', 0 } }, |
| | { false, 'O', 'R', kBare | kBareMod | kSemiMod, { VK_F3, '\0', 0 } }, |
| | { false, 'O', 'S', kBare | kBareMod | kSemiMod, { VK_F4, '\0', 0 } }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | { true, 'O', 'M', kBare | kBareMod, { VK_RETURN, '\r', 0 } }, |
| | { true, 'O', 'j', kBare | kBareMod, { VK_MULTIPLY, '*', 0 } }, |
| | { true, 'O', 'k', kBare | kBareMod, { VK_ADD, '+', 0 } }, |
| | { true, 'O', 'm', kBare | kBareMod, { VK_SUBTRACT, '-', 0 } }, |
| | { true, 'O', 'n', kBare | kBareMod, { VK_DELETE, '\0', 0 } }, |
| | { true, 'O', 'o', kBare | kBareMod, { VK_DIVIDE, '/', 0 } }, |
| | { true, 'O', 'p', kBare | kBareMod, { VK_INSERT, '\0', 0 } }, |
| | { true, 'O', 'q', kBare | kBareMod, { VK_END, '\0', 0 } }, |
| | { true, 'O', 'r', kBare | kBareMod, { VK_DOWN, '\0', 0 } }, |
| | { true, 'O', 's', kBare | kBareMod, { VK_NEXT, '\0', 0 } }, |
| | { true, 'O', 't', kBare | kBareMod, { VK_LEFT, '\0', 0 } }, |
| | { true, 'O', 'u', kBare | kBareMod, { VK_CLEAR, '\0', 0 } }, |
| | { true, 'O', 'v', kBare | kBareMod, { VK_RIGHT, '\0', 0 } }, |
| | { true, 'O', 'w', kBare | kBareMod, { VK_HOME, '\0', 0 } }, |
| | { true, 'O', 'x', kBare | kBareMod, { VK_UP, '\0', 0 } }, |
| | { true, 'O', 'y', kBare | kBareMod, { VK_PRIOR, '\0', 0 } }, |
| |
|
| | { true, '[', 'M', kBare | kSemiMod, { VK_RETURN, '\r', 0 } }, |
| | { true, '[', 'j', kBare | kSemiMod, { VK_MULTIPLY, '*', 0 } }, |
| | { true, '[', 'k', kBare | kSemiMod, { VK_ADD, '+', 0 } }, |
| | { true, '[', 'm', kBare | kSemiMod, { VK_SUBTRACT, '-', 0 } }, |
| | { true, '[', 'n', kBare | kSemiMod, { VK_DELETE, '\0', 0 } }, |
| | { true, '[', 'o', kBare | kSemiMod, { VK_DIVIDE, '/', 0 } }, |
| | { true, '[', 'p', kBare | kSemiMod, { VK_INSERT, '\0', 0 } }, |
| | { true, '[', 'q', kBare | kSemiMod, { VK_END, '\0', 0 } }, |
| | { true, '[', 'r', kBare | kSemiMod, { VK_DOWN, '\0', 0 } }, |
| | { true, '[', 's', kBare | kSemiMod, { VK_NEXT, '\0', 0 } }, |
| | { true, '[', 't', kBare | kSemiMod, { VK_LEFT, '\0', 0 } }, |
| | { true, '[', 'u', kBare | kSemiMod, { VK_CLEAR, '\0', 0 } }, |
| | { true, '[', 'v', kBare | kSemiMod, { VK_RIGHT, '\0', 0 } }, |
| | { true, '[', 'w', kBare | kSemiMod, { VK_HOME, '\0', 0 } }, |
| | { true, '[', 'x', kBare | kSemiMod, { VK_UP, '\0', 0 } }, |
| | { true, '[', 'y', kBare | kSemiMod, { VK_PRIOR, '\0', 0 } }, |
| |
|
| | { false, '[', 'Z', kBare, { VK_TAB, '\t', SHIFT_PRESSED } }, |
| | }; |
| |
|
| | static const EscapeEncoding escapeNumericEncodings[] = { |
| | { true, '[', 1, kBare | kSemiMod | kSuffixBoth, { VK_HOME, '\0', 0 } }, |
| | { true, '[', 2, kBare | kSemiMod | kSuffixBoth, { VK_INSERT, '\0', 0 } }, |
| | { true, '[', 3, kBare | kSemiMod | kSuffixBoth, { VK_DELETE, '\0', 0 } }, |
| | { true, '[', 4, kBare | kSemiMod | kSuffixBoth, { VK_END, '\0', 0 } }, |
| | { true, '[', 5, kBare | kSemiMod | kSuffixBoth, { VK_PRIOR, '\0', 0 } }, |
| | { true, '[', 6, kBare | kSemiMod | kSuffixBoth, { VK_NEXT, '\0', 0 } }, |
| | { true, '[', 7, kBare | kSemiMod | kSuffixBoth, { VK_HOME, '\0', 0 } }, |
| | { true, '[', 8, kBare | kSemiMod | kSuffixBoth, { VK_END, '\0', 0 } }, |
| | { true, '[', 11, kBare | kSemiMod | kSuffixBoth, { VK_F1, '\0', 0 } }, |
| | { true, '[', 12, kBare | kSemiMod | kSuffixBoth, { VK_F2, '\0', 0 } }, |
| | { true, '[', 13, kBare | kSemiMod | kSuffixBoth, { VK_F3, '\0', 0 } }, |
| | { true, '[', 14, kBare | kSemiMod | kSuffixBoth, { VK_F4, '\0', 0 } }, |
| | { true, '[', 15, kBare | kSemiMod | kSuffixBoth, { VK_F5, '\0', 0 } }, |
| | { true, '[', 17, kBare | kSemiMod | kSuffixBoth, { VK_F6, '\0', 0 } }, |
| | { true, '[', 18, kBare | kSemiMod | kSuffixBoth, { VK_F7, '\0', 0 } }, |
| | { true, '[', 19, kBare | kSemiMod | kSuffixBoth, { VK_F8, '\0', 0 } }, |
| | { true, '[', 20, kBare | kSemiMod | kSuffixBoth, { VK_F9, '\0', 0 } }, |
| | { true, '[', 21, kBare | kSemiMod | kSuffixBoth, { VK_F10, '\0', 0 } }, |
| | { true, '[', 23, kBare | kSemiMod | kSuffixBoth, { VK_F11, '\0', 0 } }, |
| | { true, '[', 24, kBare | kSemiMod | kSuffixBoth, { VK_F12, '\0', 0 } }, |
| | { true, '[', 25, kBare | kSemiMod | kSuffixBoth, { VK_F3, '\0', SHIFT_PRESSED } }, |
| | { true, '[', 26, kBare | kSemiMod | kSuffixBoth, { VK_F4, '\0', SHIFT_PRESSED } }, |
| | { true, '[', 28, kBare | kSemiMod | kSuffixBoth, { VK_F5, '\0', SHIFT_PRESSED } }, |
| | { true, '[', 29, kBare | kSemiMod | kSuffixBoth, { VK_F6, '\0', SHIFT_PRESSED } }, |
| | { true, '[', 31, kBare | kSemiMod | kSuffixBoth, { VK_F7, '\0', SHIFT_PRESSED } }, |
| | { true, '[', 32, kBare | kSemiMod | kSuffixBoth, { VK_F8, '\0', SHIFT_PRESSED } }, |
| | { true, '[', 33, kBare | kSemiMod | kSuffixBoth, { VK_F9, '\0', SHIFT_PRESSED } }, |
| | { true, '[', 34, kBare | kSemiMod | kSuffixBoth, { VK_F10, '\0', SHIFT_PRESSED } }, |
| | }; |
| |
|
| | const int kCsiShiftModifier = 1; |
| | const int kCsiAltModifier = 2; |
| | const int kCsiCtrlModifier = 4; |
| |
|
| | static inline bool useEnhancedForVirtualKey(uint16_t vk) { |
| | switch (vk) { |
| | case VK_UP: |
| | case VK_DOWN: |
| | case VK_LEFT: |
| | case VK_RIGHT: |
| | case VK_INSERT: |
| | case VK_DELETE: |
| | case VK_HOME: |
| | case VK_END: |
| | case VK_PRIOR: |
| | case VK_NEXT: |
| | return true; |
| | default: |
| | return false; |
| | } |
| | } |
| |
|
| | static void addSimpleEntries(InputMap &inputMap) { |
| | struct SimpleEncoding { |
| | const char *encoding; |
| | InputMap::Key key; |
| | }; |
| |
|
| | static const SimpleEncoding simpleEncodings[] = { |
| | |
| |
|
| | { "\x7F", { VK_BACK, '\x08', 0, } }, |
| | { ESC "\x7F", { VK_BACK, '\x08', LEFT_ALT_PRESSED, } }, |
| | { "\x03", { 'C', '\x03', LEFT_CTRL_PRESSED, } }, |
| |
|
| | |
| | { ESC "[[A", { VK_F1, '\0', 0 } }, |
| | { ESC "[[B", { VK_F2, '\0', 0 } }, |
| | { ESC "[[C", { VK_F3, '\0', 0 } }, |
| | { ESC "[[D", { VK_F4, '\0', 0 } }, |
| | { ESC "[[E", { VK_F5, '\0', 0 } }, |
| |
|
| | { ESC ESC "[[A", { VK_F1, '\0', LEFT_ALT_PRESSED } }, |
| | { ESC ESC "[[B", { VK_F2, '\0', LEFT_ALT_PRESSED } }, |
| | { ESC ESC "[[C", { VK_F3, '\0', LEFT_ALT_PRESSED } }, |
| | { ESC ESC "[[D", { VK_F4, '\0', LEFT_ALT_PRESSED } }, |
| | { ESC ESC "[[E", { VK_F5, '\0', LEFT_ALT_PRESSED } }, |
| | }; |
| |
|
| | for (size_t i = 0; i < DIM(simpleEncodings); ++i) { |
| | auto k = simpleEncodings[i].key; |
| | if (useEnhancedForVirtualKey(k.virtualKey)) { |
| | k.keyState |= ENHANCED_KEY; |
| | } |
| | inputMap.set(simpleEncodings[i].encoding, |
| | strlen(simpleEncodings[i].encoding), |
| | k); |
| | } |
| | } |
| |
|
| | struct ExpandContext { |
| | InputMap &inputMap; |
| | const EscapeEncoding &e; |
| | char *buffer; |
| | char *bufferEnd; |
| | }; |
| |
|
| | static inline void setEncoding(const ExpandContext &ctx, char *end, |
| | uint16_t extraKeyState) { |
| | InputMap::Key k = ctx.e.key; |
| | k.keyState |= extraKeyState; |
| | if (k.keyState & LEFT_CTRL_PRESSED) { |
| | switch (k.virtualKey) { |
| | case VK_ADD: |
| | case VK_DIVIDE: |
| | case VK_MULTIPLY: |
| | case VK_SUBTRACT: |
| | k.unicodeChar = '\0'; |
| | break; |
| | case VK_RETURN: |
| | k.unicodeChar = '\n'; |
| | break; |
| | } |
| | } |
| | if (useEnhancedForVirtualKey(k.virtualKey)) { |
| | k.keyState |= ENHANCED_KEY; |
| | } |
| | ctx.inputMap.set(ctx.buffer, end - ctx.buffer, k); |
| | } |
| |
|
| | static inline uint16_t keyStateForMod(int mod) { |
| | int ret = 0; |
| | if ((mod - 1) & kCsiShiftModifier) ret |= SHIFT_PRESSED; |
| | if ((mod - 1) & kCsiAltModifier) ret |= LEFT_ALT_PRESSED; |
| | if ((mod - 1) & kCsiCtrlModifier) ret |= LEFT_CTRL_PRESSED; |
| | return ret; |
| | } |
| |
|
| | static void expandNumericEncodingSuffix(const ExpandContext &ctx, char *p, |
| | uint16_t extraKeyState) { |
| | ASSERT(p <= ctx.bufferEnd - 1); |
| | { |
| | char *q = p; |
| | *q++ = '~'; |
| | setEncoding(ctx, q, extraKeyState); |
| | } |
| | if (ctx.e.modifiers & kSuffixShift) { |
| | char *q = p; |
| | *q++ = '$'; |
| | setEncoding(ctx, q, extraKeyState | SHIFT_PRESSED); |
| | } |
| | if (ctx.e.modifiers & kSuffixCtrl) { |
| | char *q = p; |
| | *q++ = '^'; |
| | setEncoding(ctx, q, extraKeyState | LEFT_CTRL_PRESSED); |
| | } |
| | if (ctx.e.modifiers & (kSuffixCtrl | kSuffixShift)) { |
| | char *q = p; |
| | *q++ = '@'; |
| | setEncoding(ctx, q, extraKeyState | SHIFT_PRESSED | LEFT_CTRL_PRESSED); |
| | } |
| | } |
| |
|
| | template <bool is_numeric> |
| | static inline void expandEncodingAfterAltPrefix( |
| | const ExpandContext &ctx, char *p, uint16_t extraKeyState) { |
| | auto appendId = [&](char *&ptr) { |
| | const auto idstr = decOfInt(ctx.e.id); |
| | ASSERT(ptr <= ctx.bufferEnd - idstr.size()); |
| | std::copy(idstr.data(), idstr.data() + idstr.size(), ptr); |
| | ptr += idstr.size(); |
| | }; |
| | ASSERT(p <= ctx.bufferEnd - 2); |
| | *p++ = '\x1b'; |
| | *p++ = ctx.e.prefix; |
| | if (ctx.e.modifiers & kBare) { |
| | char *q = p; |
| | if (is_numeric) { |
| | appendId(q); |
| | expandNumericEncodingSuffix(ctx, q, extraKeyState); |
| | } else { |
| | ASSERT(q <= ctx.bufferEnd - 1); |
| | *q++ = ctx.e.id; |
| | setEncoding(ctx, q, extraKeyState); |
| | } |
| | } |
| | if (ctx.e.modifiers & kBareMod) { |
| | ASSERT(!is_numeric && "kBareMod is invalid with numeric sequences"); |
| | for (int mod = 2; mod <= 8; ++mod) { |
| | char *q = p; |
| | ASSERT(q <= ctx.bufferEnd - 2); |
| | *q++ = '0' + mod; |
| | *q++ = ctx.e.id; |
| | setEncoding(ctx, q, extraKeyState | keyStateForMod(mod)); |
| | } |
| | } |
| | if (ctx.e.modifiers & kSemiMod) { |
| | for (int mod = 2; mod <= 8; ++mod) { |
| | char *q = p; |
| | if (is_numeric) { |
| | appendId(q); |
| | ASSERT(q <= ctx.bufferEnd - 2); |
| | *q++ = ';'; |
| | *q++ = '0' + mod; |
| | expandNumericEncodingSuffix( |
| | ctx, q, extraKeyState | keyStateForMod(mod)); |
| | } else { |
| | ASSERT(q <= ctx.bufferEnd - 4); |
| | *q++ = '1'; |
| | *q++ = ';'; |
| | *q++ = '0' + mod; |
| | *q++ = ctx.e.id; |
| | setEncoding(ctx, q, extraKeyState | keyStateForMod(mod)); |
| | } |
| | } |
| | } |
| | } |
| |
|
| | template <bool is_numeric> |
| | static inline void expandEncoding(const ExpandContext &ctx) { |
| | if (ctx.e.alt_prefix_allowed) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | char *p = ctx.buffer; |
| | ASSERT(p <= ctx.bufferEnd - 1); |
| | *p++ = '\x1b'; |
| | expandEncodingAfterAltPrefix<is_numeric>(ctx, p, LEFT_ALT_PRESSED); |
| | } |
| | expandEncodingAfterAltPrefix<is_numeric>(ctx, ctx.buffer, 0); |
| | } |
| |
|
| | template <bool is_numeric, size_t N> |
| | static void addEscapes(InputMap &inputMap, const EscapeEncoding (&encodings)[N]) { |
| | char buffer[32]; |
| | for (size_t i = 0; i < DIM(encodings); ++i) { |
| | ExpandContext ctx = { |
| | inputMap, encodings[i], |
| | buffer, buffer + sizeof(buffer) |
| | }; |
| | expandEncoding<is_numeric>(ctx); |
| | } |
| | } |
| |
|
| | } |
| |
|
| | void addDefaultEntriesToInputMap(InputMap &inputMap) { |
| | addEscapes<false>(inputMap, escapeLetterEncodings); |
| | addEscapes<true>(inputMap, escapeNumericEncodings); |
| | addSimpleEntries(inputMap); |
| | } |
| |
|