mirror of
https://github.com/microsoft/terminal.git
synced 2026-05-18 01:00:00 +00:00
wip
This commit is contained in:
208
reference.cpp
208
reference.cpp
@@ -1,208 +0,0 @@
|
||||
|
||||
void TerminalInput::_initKeyboardMap() noexcept
|
||||
try
|
||||
{
|
||||
auto defineKeyWithUnusedModifiers = [this](const int keyCode, const std::wstring& sequence) {
|
||||
for (auto m = 0; m < 8; m++)
|
||||
_keyMap[VTModifier(m) + keyCode] = sequence;
|
||||
};
|
||||
auto defineKeyWithAltModifier = [this](const int keyCode, const std::wstring& sequence) {
|
||||
_keyMap[keyCode] = sequence;
|
||||
_keyMap[Alt + keyCode] = L"\x1B" + sequence;
|
||||
};
|
||||
auto defineKeypadKey = [this](const int keyCode, const wchar_t* prefix, const wchar_t finalChar) {
|
||||
_keyMap[keyCode] = fmt::format(FMT_COMPILE(L"{}{}"), prefix, finalChar);
|
||||
for (auto m = 1; m < 8; m++)
|
||||
_keyMap[VTModifier(m) + keyCode] = fmt::format(FMT_COMPILE(L"{}1;{}{}"), _csi, m + 1, finalChar);
|
||||
};
|
||||
auto defineEditingKey = [this](const int keyCode, const int parm) {
|
||||
_keyMap[keyCode] = fmt::format(FMT_COMPILE(L"{}{}~"), _csi, parm);
|
||||
for (auto m = 1; m < 8; m++)
|
||||
_keyMap[VTModifier(m) + keyCode] = fmt::format(FMT_COMPILE(L"{}{};{}~"), _csi, parm, m + 1);
|
||||
};
|
||||
auto defineNumericKey = [this](const int keyCode, const wchar_t finalChar) {
|
||||
_keyMap[keyCode] = fmt::format(FMT_COMPILE(L"{}{}"), _ss3, finalChar);
|
||||
for (auto m = 1; m < 8; m++)
|
||||
_keyMap[VTModifier(m) + keyCode] = fmt::format(FMT_COMPILE(L"{}{}{}"), _ss3, m + 1, finalChar);
|
||||
};
|
||||
|
||||
_keyMap.clear();
|
||||
|
||||
// The CSI and SS3 introducers are C1 control codes, which can either be
|
||||
// sent as a single codepoint, or as a two character escape sequence.
|
||||
if (_inputMode.test(Mode::SendC1))
|
||||
{
|
||||
_csi = L"\x9B";
|
||||
_ss3 = L"\x8F";
|
||||
}
|
||||
else
|
||||
{
|
||||
_csi = L"\x1B[";
|
||||
_ss3 = L"\x1BO";
|
||||
}
|
||||
|
||||
// PAUSE doesn't have a VT mapping, but traditionally we've mapped it to ^Z,
|
||||
// regardless of modifiers.
|
||||
defineKeyWithUnusedModifiers(VK_PAUSE, L"\x1A"s);
|
||||
|
||||
// BACKSPACE maps to either DEL or BS, depending on the Backarrow Key mode.
|
||||
// The Ctrl modifier inverts the active mode, swapping BS and DEL (this is
|
||||
// not standard, but a modern terminal convention). The Alt modifier adds
|
||||
// an ESC prefix (also not standard).
|
||||
const auto backSequence = _inputMode.test(Mode::BackarrowKey) ? L"\b"s : L"\x7F"s;
|
||||
const auto ctrlBackSequence = _inputMode.test(Mode::BackarrowKey) ? L"\x7F"s : L"\b"s;
|
||||
defineKeyWithAltModifier(VK_BACK, backSequence);
|
||||
defineKeyWithAltModifier(Ctrl + VK_BACK, ctrlBackSequence);
|
||||
defineKeyWithAltModifier(Shift + VK_BACK, backSequence);
|
||||
defineKeyWithAltModifier(Ctrl + Shift + VK_BACK, ctrlBackSequence);
|
||||
|
||||
// TAB maps to HT, and Shift+TAB to CBT. The Ctrl modifier has no effect.
|
||||
// The Alt modifier adds an ESC prefix, although in practice all the Alt
|
||||
// mappings are likely to be system hotkeys.
|
||||
const auto shiftTabSequence = fmt::format(FMT_COMPILE(L"{}Z"), _csi);
|
||||
defineKeyWithAltModifier(VK_TAB, L"\t"s);
|
||||
defineKeyWithAltModifier(Ctrl + VK_TAB, L"\t"s);
|
||||
defineKeyWithAltModifier(Shift + VK_TAB, shiftTabSequence);
|
||||
defineKeyWithAltModifier(Ctrl + Shift + VK_TAB, shiftTabSequence);
|
||||
|
||||
// RETURN maps to either CR or CR LF, depending on the Line Feed mode. With
|
||||
// a Ctrl modifier it maps to LF, because that's the expected behavior for
|
||||
// most PC keyboard layouts. The Alt modifier adds an ESC prefix.
|
||||
const auto returnSequence = _inputMode.test(Mode::LineFeed) ? L"\r\n"s : L"\r"s;
|
||||
defineKeyWithAltModifier(VK_RETURN, returnSequence);
|
||||
defineKeyWithAltModifier(Shift + VK_RETURN, returnSequence);
|
||||
defineKeyWithAltModifier(Ctrl + VK_RETURN, L"\n"s);
|
||||
defineKeyWithAltModifier(Ctrl + Shift + VK_RETURN, L"\n"s);
|
||||
|
||||
// The keypad RETURN key works the same way, except when Keypad mode is
|
||||
// enabled, but that's handled below with the other keypad keys.
|
||||
defineKeyWithAltModifier(Enhanced + VK_RETURN, returnSequence);
|
||||
defineKeyWithAltModifier(Shift + Enhanced + VK_RETURN, returnSequence);
|
||||
defineKeyWithAltModifier(Ctrl + Enhanced + VK_RETURN, L"\n"s);
|
||||
defineKeyWithAltModifier(Ctrl + Shift + Enhanced + VK_RETURN, L"\n"s);
|
||||
|
||||
if (_inputMode.test(Mode::Ansi))
|
||||
{
|
||||
// F1 to F4 map to the VT keypad function keys, which are SS3 sequences.
|
||||
// When combined with a modifier, we use CSI sequences with the modifier
|
||||
// embedded as a parameter (not standard - a modern terminal extension).
|
||||
defineKeypadKey(VK_F1, _ss3, L'P');
|
||||
defineKeypadKey(VK_F2, _ss3, L'Q');
|
||||
defineKeypadKey(VK_F3, _ss3, L'R');
|
||||
defineKeypadKey(VK_F4, _ss3, L'S');
|
||||
|
||||
// F5 through F20 map to the top row VT function keys. They use standard
|
||||
// DECFNK sequences with the modifier embedded as a parameter. The first
|
||||
// five function keys on a VT terminal are typically local functions, so
|
||||
// there's not much need to support mappings for them.
|
||||
for (auto vk = VK_F5; vk <= VK_F20; vk++)
|
||||
{
|
||||
static constexpr std::array<uint8_t, 16> parameters = { 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 28, 29, 31, 32, 33, 34 };
|
||||
const auto parm = parameters.at(static_cast<size_t>(vk) - VK_F5);
|
||||
defineEditingKey(vk, parm);
|
||||
}
|
||||
|
||||
// Cursor keys follow a similar pattern to the VT keypad function keys,
|
||||
// although they only use an SS3 prefix when the Cursor Key mode is set.
|
||||
// When combined with a modifier, they'll use CSI sequences with the
|
||||
// modifier embedded as a parameter (again not standard).
|
||||
const auto ckIntroducer = _inputMode.test(Mode::CursorKey) ? _ss3 : _csi;
|
||||
defineKeypadKey(VK_UP, ckIntroducer, L'A');
|
||||
defineKeypadKey(VK_DOWN, ckIntroducer, L'B');
|
||||
defineKeypadKey(VK_RIGHT, ckIntroducer, L'C');
|
||||
defineKeypadKey(VK_LEFT, ckIntroducer, L'D');
|
||||
defineKeypadKey(VK_CLEAR, ckIntroducer, L'E');
|
||||
defineKeypadKey(VK_HOME, ckIntroducer, L'H');
|
||||
defineKeypadKey(VK_END, ckIntroducer, L'F');
|
||||
|
||||
// Editing keys follow the same pattern as the top row VT function
|
||||
// keys, using standard DECFNK sequences with the modifier embedded.
|
||||
defineEditingKey(VK_INSERT, 2);
|
||||
defineEditingKey(VK_DELETE, 3);
|
||||
defineEditingKey(VK_PRIOR, 5);
|
||||
defineEditingKey(VK_NEXT, 6);
|
||||
|
||||
// Keypad keys depend on the Keypad mode. When reset, they transmit
|
||||
// the ASCII character assigned by the keyboard layout, but when set
|
||||
// they transmit SS3 escape sequences. When used with a modifier, the
|
||||
// modifier is embedded as a parameter value (not standard).
|
||||
if (Feature_KeypadModeEnabled::IsEnabled() && _inputMode.test(Mode::Keypad))
|
||||
{
|
||||
defineNumericKey(VK_MULTIPLY, L'j');
|
||||
defineNumericKey(VK_ADD, L'k');
|
||||
defineNumericKey(VK_SEPARATOR, L'l');
|
||||
defineNumericKey(VK_SUBTRACT, L'm');
|
||||
defineNumericKey(VK_DECIMAL, L'n');
|
||||
defineNumericKey(VK_DIVIDE, L'o');
|
||||
|
||||
defineNumericKey(VK_NUMPAD0, L'p');
|
||||
defineNumericKey(VK_NUMPAD1, L'q');
|
||||
defineNumericKey(VK_NUMPAD2, L'r');
|
||||
defineNumericKey(VK_NUMPAD3, L's');
|
||||
defineNumericKey(VK_NUMPAD4, L't');
|
||||
defineNumericKey(VK_NUMPAD5, L'u');
|
||||
defineNumericKey(VK_NUMPAD6, L'v');
|
||||
defineNumericKey(VK_NUMPAD7, L'w');
|
||||
defineNumericKey(VK_NUMPAD8, L'x');
|
||||
defineNumericKey(VK_NUMPAD9, L'y');
|
||||
|
||||
defineNumericKey(Enhanced + VK_RETURN, L'M');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// In VT52 mode, the sequences tend to use the same final character as
|
||||
// their ANSI counterparts, but with a simple ESC prefix. The modifier
|
||||
// keys have no effect.
|
||||
|
||||
// VT52 only support PF1 through PF4 function keys.
|
||||
defineKeyWithUnusedModifiers(VK_F1, L"\033P"s);
|
||||
defineKeyWithUnusedModifiers(VK_F2, L"\033Q"s);
|
||||
defineKeyWithUnusedModifiers(VK_F3, L"\033R"s);
|
||||
defineKeyWithUnusedModifiers(VK_F4, L"\033S"s);
|
||||
|
||||
// But terminals with application functions keys would
|
||||
// map some of them as controls keys in VT52 mode.
|
||||
defineKeyWithUnusedModifiers(VK_F11, L"\033"s);
|
||||
defineKeyWithUnusedModifiers(VK_F12, L"\b"s);
|
||||
defineKeyWithUnusedModifiers(VK_F13, L"\n"s);
|
||||
|
||||
// Cursor keys use the same finals as the ANSI sequences.
|
||||
defineKeyWithUnusedModifiers(VK_UP, L"\033A"s);
|
||||
defineKeyWithUnusedModifiers(VK_DOWN, L"\033B"s);
|
||||
defineKeyWithUnusedModifiers(VK_RIGHT, L"\033C"s);
|
||||
defineKeyWithUnusedModifiers(VK_LEFT, L"\033D"s);
|
||||
defineKeyWithUnusedModifiers(VK_CLEAR, L"\033E"s);
|
||||
defineKeyWithUnusedModifiers(VK_HOME, L"\033H"s);
|
||||
defineKeyWithUnusedModifiers(VK_END, L"\033F"s);
|
||||
|
||||
// Keypad keys also depend on Keypad mode, the same as ANSI mappings,
|
||||
// but the sequences use an ESC ? prefix instead of SS3.
|
||||
if (Feature_KeypadModeEnabled::IsEnabled() && _inputMode.test(Mode::Keypad))
|
||||
{
|
||||
defineKeyWithUnusedModifiers(VK_MULTIPLY, L"\033?j"s);
|
||||
defineKeyWithUnusedModifiers(VK_ADD, L"\033?k"s);
|
||||
defineKeyWithUnusedModifiers(VK_SEPARATOR, L"\033?l"s);
|
||||
defineKeyWithUnusedModifiers(VK_SUBTRACT, L"\033?m"s);
|
||||
defineKeyWithUnusedModifiers(VK_DECIMAL, L"\033?n"s);
|
||||
defineKeyWithUnusedModifiers(VK_DIVIDE, L"\033?o"s);
|
||||
|
||||
defineKeyWithUnusedModifiers(VK_NUMPAD0, L"\033?p"s);
|
||||
defineKeyWithUnusedModifiers(VK_NUMPAD1, L"\033?q"s);
|
||||
defineKeyWithUnusedModifiers(VK_NUMPAD2, L"\033?r"s);
|
||||
defineKeyWithUnusedModifiers(VK_NUMPAD3, L"\033?s"s);
|
||||
defineKeyWithUnusedModifiers(VK_NUMPAD4, L"\033?t"s);
|
||||
defineKeyWithUnusedModifiers(VK_NUMPAD5, L"\033?u"s);
|
||||
defineKeyWithUnusedModifiers(VK_NUMPAD6, L"\033?v"s);
|
||||
defineKeyWithUnusedModifiers(VK_NUMPAD7, L"\033?w"s);
|
||||
defineKeyWithUnusedModifiers(VK_NUMPAD8, L"\033?x"s);
|
||||
defineKeyWithUnusedModifiers(VK_NUMPAD9, L"\033?y"s);
|
||||
|
||||
defineKeyWithUnusedModifiers(Enhanced + VK_RETURN, L"\033?M"s);
|
||||
}
|
||||
}
|
||||
|
||||
_focusInSequence = _csi + L"I"s;
|
||||
_focusOutSequence = _csi + L"O"s;
|
||||
}
|
||||
CATCH_LOG()
|
||||
@@ -117,6 +117,14 @@ using namespace Microsoft::Console::Interactivity;
|
||||
CATCH_RETURN();
|
||||
}
|
||||
|
||||
// TODO: Avoid translating win32im sequences to Kitty Keyboard Protocol temporarily.
|
||||
// This is because as of this writing, our implementation is brand new, and Windows Terminal
|
||||
// needs a toggle to disable it. That only works if ConPTY then doesn't do it anyway.
|
||||
if (const auto inputBuffer = ServiceLocator::LocateGlobals().getConsoleInformation().pInputBuffer)
|
||||
{
|
||||
inputBuffer->GetTerminalInput().ForceDisableKittyKeyboardProtocol(true);
|
||||
}
|
||||
|
||||
// The only way we're initialized is if the args said we're in conpty mode.
|
||||
// If the args say so, then at least one of in, out, or signal was specified
|
||||
_state = State::Initialized;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -98,15 +98,18 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
|
||||
struct KeyEncodingInfo
|
||||
{
|
||||
// If not zero, this value represents the first field in the Kitty
|
||||
// Keyboard Protocol (KKP) CSI u sequence. If the KKP is requested,
|
||||
// this field will be preferred over the following fields.
|
||||
int32_t kittyKeyCode = 0;
|
||||
explicit KeyEncodingInfo()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
// A non-zero csiFinal value indicates that this key
|
||||
// should be encoded as `CSI $csiParam1 ; $csiFinal`.
|
||||
wchar_t csiFinal = 0;
|
||||
int32_t csiParam1 = 0;
|
||||
// The longest sequence we currently have is Kitty's with 6 parameters:
|
||||
// CSI unicode-key-code:alternate-key-code-shift:alternate-key-code-base ; modifiers:event-type ; text-as-codepoint u
|
||||
// That's 6 parameters, but we can greatly simplify our logic if we just make it 3x3.
|
||||
uint32_t csiParam[3][3] = {};
|
||||
|
||||
// A non-zero ss3Final value indicates that this key
|
||||
// should be encoded as `ESC O $ss3Final`.
|
||||
@@ -115,10 +118,9 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
// Any other encoding ends up as a non-zero plain value.
|
||||
// For instance, the Tab key gets translated to a plain "\t".
|
||||
std::wstring_view plain;
|
||||
|
||||
// If true, and Alt is pressed, an ESC prefix should be added to
|
||||
// the final sequence. This only applies to non-KKP encodings.
|
||||
bool altPrefix = false;
|
||||
bool plainAltPrefix = false;
|
||||
};
|
||||
|
||||
// storage location for the leading surrogate of a utf-16 surrogate pair
|
||||
@@ -149,14 +151,17 @@ namespace Microsoft::Console::VirtualTerminal
|
||||
void _initKeyboardMap() noexcept;
|
||||
DWORD _trackControlKeyState(const KEY_EVENT_RECORD& key) noexcept;
|
||||
static std::array<byte, 256> _getKeyboardState(WORD virtualKeyCode, DWORD controlKeyState);
|
||||
[[nodiscard]] static wchar_t _makeCtrlChar(wchar_t ch);
|
||||
[[nodiscard]] static uint32_t _makeCtrlChar(uint32_t ch) noexcept;
|
||||
[[nodiscard]] static StringType _makeCharOutput(uint32_t ch);
|
||||
[[nodiscard]] static StringType _makeNoOutput() noexcept;
|
||||
void _escapeOutput(StringType& charSequence, bool altIsPressed) const;
|
||||
[[nodiscard]] OutputType _makeWin32Output(const KEY_EVENT_RECORD& key) const;
|
||||
[[nodiscard]] KeyEncodingInfo _getKeyEncodingInfo(const KEY_EVENT_RECORD& key, DWORD simpleKeyState) const noexcept;
|
||||
void _fillRegularKeyEncodingInfo(KeyEncodingInfo& info, const KEY_EVENT_RECORD& key, DWORD simpleKeyState) const noexcept;
|
||||
static uint32_t _getKittyFunctionalKeyCode(const KEY_EVENT_RECORD& key, DWORD simpleKeyState) noexcept;
|
||||
void _getKittyInfo() noexcept;
|
||||
std::vector<uint8_t>& _getKittyStack() noexcept;
|
||||
static bool _codepointIsText(uint32_t cp) noexcept;
|
||||
static void _stringPushCodepoint(std::wstring& str, uint32_t cp);
|
||||
static CodepointBuffer _codepointToBuffer(uint32_t cp) noexcept;
|
||||
static uint32_t _bufferToCodepoint(const wchar_t* str) noexcept;
|
||||
static uint32_t _codepointToLower(uint32_t cp) noexcept;
|
||||
|
||||
Reference in New Issue
Block a user