bool TermX::GetSubstitute(const KEY_EVENT_RECORD& k, wchar_t (&szSubst)[16]) { _ASSERTE(szSubst[0] == 0); static UINT F1Codes[24] = { 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 28, 29, 31, 32, 33, 34, 42, 43, 44, 45 }; static wchar_t F1F4Codes[] = {L'P', L'Q', L'R', L'S'}; static wchar_t ArrowCodes[] = {L'F', L'H', L'D', L'A', L'C', L'B'}; typedef DWORD XTermCtrls; const XTermCtrls xtc_Shift = 1, xtc_Alt = 2, xtc_Ctrl = 4, xtc_None = 0; struct processor { XTermCtrls Mods; void SetKey(wchar_t (&szSubst)[16], wchar_t c, wchar_t prefix=L'O') { if (!Mods) { //wcscpy_c(szSubst, L"\033O*A"); msprintf(szSubst, countof(szSubst), L"\033%c%c", prefix, c); } else { msprintf(szSubst, countof(szSubst), L"\033[1;%c%c", Mods+L'1', c); } } void SetFKey(wchar_t (&szSubst)[16], UINT fn) { if (!Mods) { msprintf(szSubst, countof(szSubst), L"\033[%u~", fn); } else { msprintf(szSubst, countof(szSubst), L"\033[%u;%c~", fn, Mods+L'1'); } } void SetTilde(wchar_t (&szSubst)[16], wchar_t c) { if (!Mods) { msprintf(szSubst, countof(szSubst), L"\033[%c~", c); } else { msprintf(szSubst, countof(szSubst), L"\033[%c;%c~", c, Mods+L'1'); } } } Processor = {xtc_None}; if (k.dwControlKeyState & (SHIFT_PRESSED)) Processor.Mods |= xtc_Shift; if (k.dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) Processor.Mods |= xtc_Alt; if (k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) Processor.Mods |= xtc_Ctrl; switch (k.wVirtualKeyCode) { case VK_END: case VK_HOME: case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN: Processor.SetKey(szSubst, ArrowCodes[(k.wVirtualKeyCode-VK_END)], AppCursorKeys ? L'O' : L'['); return true; case VK_F1: case VK_F2: case VK_F3: case VK_F4: Processor.SetKey(szSubst, F1F4Codes[(k.wVirtualKeyCode-VK_F1)]); return true; case VK_F5: case VK_F6: case VK_F7: case VK_F8: case VK_F9: case VK_F10: case VK_F11: case VK_F12: case VK_F13: case VK_F14: case VK_F15: case VK_F16: case VK_F17: case VK_F18: case VK_F19: case VK_F20: case VK_F21: case VK_F22: case VK_F23: case VK_F24: // "\033[11;*~" .. L"\033[15;*~", and so on: F1Codes[] Processor.SetFKey(szSubst, F1Codes[(k.wVirtualKeyCode-VK_F1)]); return true; case VK_INSERT: Processor.SetTilde(szSubst, L'2'); return true; case VK_PRIOR: Processor.SetTilde(szSubst, L'5'); return true; case VK_NEXT: Processor.SetTilde(szSubst, L'6'); return true; case VK_DELETE: Processor.SetTilde(szSubst, L'3'); return true; case VK_BACK: if ((Processor.Mods & xtc_Alt)) szSubst[0] = 0x1B; szSubst[(Processor.Mods == xtc_Alt) ? 1 : 0] = ((Processor.Mods & (xtc_Ctrl|xtc_Alt)) == (xtc_Ctrl|xtc_Alt)) ? 0x9F : (Processor.Mods & xtc_Ctrl) ? X_CTRL('_')/*0x1F*/ : X_CDEL/*0x7F*/; szSubst[(Processor.Mods == xtc_Alt) ? 2 : 1] = 0; return true; case VK_TAB: if (!(k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED|LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))) { wcscpy_c(szSubst, (k.dwControlKeyState & SHIFT_PRESSED) ? L"\033[Z" : L"\t"); } return true; /* NumPad with NumLock ON */ case VK_NUMPAD0: case VK_NUMPAD1: case VK_NUMPAD2: case VK_NUMPAD3: case VK_NUMPAD4: case VK_NUMPAD5: case VK_NUMPAD6: case VK_NUMPAD7: case VK_NUMPAD8: case VK_NUMPAD9: case VK_DECIMAL: // VK_OEM_PERIOD}, // Actually, this may be comma case VK_DIVIDE: case VK_MULTIPLY: case VK_SUBTRACT: case VK_ADD: if (k.uChar.UnicodeChar) { // Just a digits '0'..'9' and symbols +-/*. szSubst[0] = k.uChar.UnicodeChar; szSubst[1] = 0; } return true; } // Alt+Char if ((Processor.Mods & xtc_Alt) && k.uChar.UnicodeChar // connector/gh#4: AltGr+Char && ((k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED|LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) != (LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED)) ) { szSubst[0] = L'\033'; szSubst[1] = k.uChar.UnicodeChar; szSubst[2] = 0; return true; } // Ctrl+Char? A-->1, ..., J-->10, ... return false; }
bool TermX::GetSubstitute(const KEY_EVENT_RECORD& k, CEStr& lsSubst) { _ASSERTE(lsSubst.IsEmpty()); // Bypass AltGr+keys to console intact if ((k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED)) == (LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED)) { if (k.uChar.UnicodeChar) { wchar_t szData[3] = {k.uChar.UnicodeChar}; if (LastDeadCharVK == k.wVirtualKeyCode) szData[1] = k.uChar.UnicodeChar; lsSubst.Set(szData); LastDeadCharVK = 0; } else { LastDeadCharVK = k.wVirtualKeyCode; lsSubst.Clear(); } return true; } wchar_t szSubst[16] = L""; static UINT F1Codes[24] = { 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 28, 29, 31, 32, 33, 34, 42, 43, 44, 45 }; static wchar_t F1F4Codes[] = {L'P', L'Q', L'R', L'S'}; static wchar_t ArrowCodes[] = {L'F', L'H', L'D', L'A', L'C', L'B'}; typedef DWORD XTermCtrls; const XTermCtrls xtc_Shift = 1, xtc_Alt = 2, xtc_Ctrl = 4, xtc_None = 0; struct processor { XTermCtrls Mods; wchar_t szSubst[16]; void SetKey(CEStr& lsSubst, wchar_t c, wchar_t prefix=L'O') { if (!Mods) { //wcscpy_c(szSubst, L"\033O*A"); msprintf(szSubst, countof(szSubst), L"\033%c%c", prefix, c); } else { msprintf(szSubst, countof(szSubst), L"\033[1;%c%c", Mods+L'1', c); } lsSubst.Set(szSubst); } void SetFKey(CEStr& lsSubst, UINT fn) { if (!Mods) { msprintf(szSubst, countof(szSubst), L"\033[%u~", fn); } else { msprintf(szSubst, countof(szSubst), L"\033[%u;%c~", fn, Mods+L'1'); } lsSubst.Set(szSubst); } void SetTilde(CEStr& lsSubst, wchar_t c) { if (!Mods) { msprintf(szSubst, countof(szSubst), L"\033[%c~", c); } else { msprintf(szSubst, countof(szSubst), L"\033[%c;%c~", c, Mods+L'1'); } lsSubst.Set(szSubst); } } Processor = {xtc_None}; if (k.dwControlKeyState & (SHIFT_PRESSED)) Processor.Mods |= xtc_Shift; if (k.dwControlKeyState & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) Processor.Mods |= xtc_Alt; if (k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) Processor.Mods |= xtc_Ctrl; switch (k.wVirtualKeyCode) { case VK_END: case VK_HOME: case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN: Processor.SetKey(lsSubst, ArrowCodes[(k.wVirtualKeyCode-VK_END)], AppCursorKeys ? L'O' : L'['); return true; case VK_F1: case VK_F2: case VK_F3: case VK_F4: Processor.SetKey(lsSubst, F1F4Codes[(k.wVirtualKeyCode-VK_F1)]); return true; case VK_F5: case VK_F6: case VK_F7: case VK_F8: case VK_F9: case VK_F10: case VK_F11: case VK_F12: case VK_F13: case VK_F14: case VK_F15: case VK_F16: case VK_F17: case VK_F18: case VK_F19: case VK_F20: case VK_F21: case VK_F22: case VK_F23: case VK_F24: // "\033[11;*~" .. L"\033[15;*~", and so on: F1Codes[] Processor.SetFKey(lsSubst, F1Codes[(k.wVirtualKeyCode-VK_F1)]); return true; case VK_INSERT: Processor.SetTilde(lsSubst, L'2'); return true; case VK_PRIOR: Processor.SetTilde(lsSubst, L'5'); return true; case VK_NEXT: Processor.SetTilde(lsSubst, L'6'); return true; case VK_DELETE: Processor.SetTilde(lsSubst, L'3'); return true; case VK_BACK: if ((Processor.Mods & xtc_Alt)) szSubst[0] = 0x1B; szSubst[(Processor.Mods == xtc_Alt) ? 1 : 0] = ((Processor.Mods & (xtc_Ctrl|xtc_Alt)) == (xtc_Ctrl|xtc_Alt)) ? 0x9F : (Processor.Mods & xtc_Ctrl) ? X_CTRL('_')/*0x1F*/ : X_CDEL/*0x7F*/; szSubst[(Processor.Mods == xtc_Alt) ? 2 : 1] = 0; lsSubst.Set(szSubst); return true; case VK_TAB: if (!(k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED|LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED))) { wcscpy_c(szSubst, (k.dwControlKeyState & SHIFT_PRESSED) ? L"\033[Z" : L"\t"); } lsSubst.Set(szSubst); return true; /* NumPad with NumLock ON */ case VK_NUMPAD0: case VK_NUMPAD1: case VK_NUMPAD2: case VK_NUMPAD3: case VK_NUMPAD4: case VK_NUMPAD5: case VK_NUMPAD6: case VK_NUMPAD7: case VK_NUMPAD8: case VK_NUMPAD9: case VK_DECIMAL: // VK_OEM_PERIOD}, // Actually, this may be comma case VK_DIVIDE: case VK_MULTIPLY: case VK_SUBTRACT: case VK_ADD: if (k.uChar.UnicodeChar) { // Just a digits '0'..'9' and symbols +-/*. szSubst[0] = k.uChar.UnicodeChar; szSubst[1] = 0; } lsSubst.Set(szSubst); return true; } // Alt+Char if ((Processor.Mods & xtc_Alt) && k.uChar.UnicodeChar // connector/gh#4: AltGr+Char && (((k.dwControlKeyState & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED|LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) != (LEFT_CTRL_PRESSED|RIGHT_ALT_PRESSED)) // or just a Alt+Char || !(Processor.Mods & xtc_Ctrl)) ) { szSubst[0] = L'\033'; szSubst[1] = k.uChar.UnicodeChar; szSubst[2] = 0; lsSubst.Set(szSubst); return true; } // Ctrl+Char: A-->1, ..., J-->10, ... if (Processor.Mods & (xtc_Alt | xtc_Ctrl)) { wchar_t key_char = k.uChar.UnicodeChar; if (!key_char) { switch (k.wVirtualKeyCode) { case VK_OEM_2: key_char = L'?'; break; // Ctrl+/ -> \x1F case VK_OEM_3: key_char = L'~'; break; case VK_OEM_4: key_char = L'['; break; case VK_OEM_5: key_char = L'\\'; break; case VK_OEM_6: key_char = L']'; break; case VK_OEM_COMMA: key_char = L','; break; case VK_OEM_PERIOD: key_char = L'.'; break; case VK_OEM_MINUS: key_char = L'-'; break; case VK_OEM_PLUS: key_char = L'='; break; default: if (k.wVirtualKeyCode >= L'0' && k.wVirtualKeyCode <= L'9') key_char = k.wVirtualKeyCode; else if (k.wVirtualKeyCode >= L'A' && k.wVirtualKeyCode <= L'Z') key_char = k.wVirtualKeyCode; } } if (key_char) { szSubst[0] = szSubst[1] = szSubst[2] = szSubst[3] = 0; if ((Processor.Mods == xtc_Ctrl) && (key_char == L'2' || key_char == L' ')) { // Must send '\x00' but it's not a valid ASCIIZ string, have to be processed in connector return false; } else if (key_char >= L'A' && key_char <= L'Z') { if (Processor.Mods == xtc_Ctrl) { // In vt220: If XOFF support is enabled, then CTRL-S is a "hold screen" local function and CTRL-Q is an "unhold screen" local function. szSubst[0] = (wchar_t)(1 + (key_char - L'A')); } else if ((Processor.Mods == (xtc_Ctrl|xtc_Alt)) || (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift))) { szSubst[0] = 0x1B; szSubst[1] = (wchar_t)(1 + (key_char - L'A')); } // doesn't work, "showkey -a" receives "<x1B><xC3><x82><x01>" //else if (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift)) //{ // szSubst[0] = 0x1B; szSubst[1] = 0xC2; // szSubst[2] = (wchar_t)(1 + (key_char - L'A')); //} } else if ((Processor.Mods == xtc_Ctrl) && (key_char == L'1' || key_char == L'9' || key_char == L'0')) { // Strangely Ctrl+1, Ctrl+9, Ctrl+0 generate only 1, 9 and 0. szSubst[0] = key_char; } else if ((Processor.Mods == xtc_Ctrl) && (key_char >= L'3' && key_char <= L'7')) { szSubst[0] = (wchar_t)(0x1B + (key_char - L'3')); } else switch (key_char) { case L',': szSubst[0] = 0x2C; break; // Processor.SetKey(lsSubst, L'l'); break; case L'.': szSubst[0] = 0x2E; break; // Processor.SetKey(lsSubst, L'n'); break; //case L'-': // Processor.SetKey(lsSubst, L'm'); break; //case L'0': // Processor.SetKey(lsSubst, L'p'); break; //case L'1': // Processor.SetKey(lsSubst, L'q'); break; // case L'2': // processed above //case L'3': // Processor.SetKey(lsSubst, L's'); break; //case L'4': // Processor.SetKey(lsSubst, L't'); break; //case L'5': // Processor.SetKey(lsSubst, L'u'); break; //case L'6': case L'~': szSubst[0] = 0x1E; break; //case L'7': // Processor.SetKey(lsSubst, L'w'); break; case L'8': szSubst[0] = 0x1B; if ((Processor.Mods == (xtc_Ctrl|xtc_Alt)) || (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift))) szSubst[1] = 0x7F; else szSubst[0] = 0x7F; break; //Processor.SetKey(lsSubst, L'x'); break; //case L'9': // Processor.SetKey(lsSubst, L'y'); break; //case L'=': // Processor.SetKey(lsSubst, L'X'); break; case L'[': case L'\\': case L']': { wchar_t c = (key_char == L'[') ? 0x1B : (key_char == L'\\') ? 0x1C : 0x1D; szSubst[0] = 0x1B; if (Processor.Mods == xtc_Alt) szSubst[1] = 0x40 + c; else if ((Processor.Mods == (xtc_Ctrl|xtc_Alt)) || (Processor.Mods == (xtc_Ctrl|xtc_Alt|xtc_Shift))) szSubst[1] = c; else szSubst[0] = c; break; } case L'?': if (!(Processor.Mods & xtc_Alt)) szSubst[0] = (Processor.Mods & xtc_Shift) ? 0x7F : 0x1F; else { szSubst[0] = 0x1B; szSubst[1] = (Processor.Mods & xtc_Shift) ? 0x3F : 0x2F; } break; } if (szSubst[0]) { lsSubst.Set(szSubst); return true; } } } return false; }