From b009d06bc3db91a34fcc6b6cb2bb1dc196ce3f8c Mon Sep 17 00:00:00 2001 From: Leonard Hecker Date: Mon, 8 Feb 2021 16:33:38 +0100 Subject: [PATCH] Fixed #5205: Ctrl+Alt+2 doesn't send ^[^@ (#5272) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary of the Pull Request Fixes #5205, by replacing another use of `MapVirtualKeyW` with `ToUnicodeEx`. The latter just seems to be much more consistent at translating key combinations in general. In this particular case though it fixes the issue, because there's no differentiation in `MapVirtualKeyW` for whether it failed to return a character (`'\0'`) or succeeded in turning `^@` into `'\0'`. `ToUnicodeEx` on the other hand returns the success state separately from the translated character. ## PR Checklist * [x] Closes #5205 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [x] Tests added/passed * [ ] Requires documentation to be updated * [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #5205 ## Detailed Description of the Pull Request / Additional comments This PR changes the behavior of the `Ctrl+Alt+Key` handling slightly: ⚠️ `ToUnicodeEx` returns unshifted characters. ⚠️ For instance `Ctrl+Alt+a` is now turned into `^[^a`. Due to how ASCII works this is essentially the same though because `'A' & 0b11111` and `'a' & 0b11111` are the same. ## Validation Steps Performed * Run `showkey -a` * Ensured `Ctrl+Alt+Space` as well as `Ctrl+Alt+Shift+2` are turned into `^[^@` * Ensured other, random `Ctrl+Alt+Key` combination behave identical to the current master --- .../actions/spelling/dictionary/microsoft.txt | 2 ++ src/terminal/input/terminalInput.cpp | 32 ++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.github/actions/spelling/dictionary/microsoft.txt b/.github/actions/spelling/dictionary/microsoft.txt index 83440accbfa..d6743107907 100644 --- a/.github/actions/spelling/dictionary/microsoft.txt +++ b/.github/actions/spelling/dictionary/microsoft.txt @@ -39,6 +39,7 @@ systemroot taskkill tasklist tdbuildteamid +VCRT vcruntime visualstudio VSTHRD @@ -47,3 +48,4 @@ wslpath wtl wtt wttlog +Xamarin diff --git a/src/terminal/input/terminalInput.cpp b/src/terminal/input/terminalInput.cpp index 73be6356acc..f3b1864ab38 100644 --- a/src/terminal/input/terminalInput.cpp +++ b/src/terminal/input/terminalInput.cpp @@ -565,25 +565,33 @@ bool TerminalInput::HandleKey(const IInputEvent* const pInEvent) // for the 5 least significant ones to be zeroed out. if (keyEvent.IsAltPressed() && keyEvent.IsCtrlPressed()) { - auto ch = keyEvent.GetCharData(); - if (ch == UNICODE_NULL) - { - // For Alt+Ctrl+Key messages GetCharData() returns 0. - // The values of the ASCII characters and virtual key codes - // of , A-Z (as used below) are numerically identical. - // -> Get the char from the virtual key. - ch = keyEvent.GetVirtualKeyCode(); - } + const auto ch = keyEvent.GetCharData(); + const auto vkey = keyEvent.GetVirtualKeyCode(); + + // For Alt+Ctrl+Key messages GetCharData() usually returns 0. + // Luckily the numerical values of the ASCII characters and virtual key codes + // of and A-Z, as used below, are numerically identical. + // -> Get the char from the virtual key if it's 0. + const auto ctrlAltChar = keyEvent.GetCharData() != 0 ? keyEvent.GetCharData() : keyEvent.GetVirtualKeyCode(); + // Alt+Ctrl acts as a substitute for AltGr on Windows. // For instance using a German keyboard both AltGr+< and Alt+Ctrl+< produce a | (pipe) character. // The below condition primitively ensures that we allow all common Alt+Ctrl combinations // while preserving most of the functionality of Alt+Ctrl as a substitute for AltGr. - if (ch == UNICODE_SPACE || (ch > 0x40 && ch <= 0x5A)) + if (ctrlAltChar == UNICODE_SPACE || (ctrlAltChar > 0x40 && ctrlAltChar <= 0x5A)) { // Pressing the control key causes all bits but the 5 least // significant ones to be zeroed out (when using ASCII). - ch &= 0b11111; - _SendEscapedInputSequence(ch); + _SendEscapedInputSequence(ctrlAltChar & 0b11111); + return true; + } + + // Currently, when we're called with Alt+Ctrl+@, ch will be 0, since Ctrl+@ equals a null byte. + // VkKeyScanW(0) in turn returns the vkey for the null character (ASCII @). + // -> Use the vkey to determine if Ctrl+@ is being pressed and produce ^[^@. + if (ch == UNICODE_NULL && vkey == LOBYTE(VkKeyScanW(0))) + { + _SendEscapedInputSequence(L'\0'); return true; } }