From 05ffe67e1a35dc1309de363322147e0fcd5b3ef3 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Sat, 20 Feb 2021 07:33:56 -0800 Subject: [PATCH] fix(windows/#3157): Dead key fix (#3166) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit __Issue:__ On Windows, pressing a dead key (like ') twice would not emit any output. Curiously, composing works correctly (' + a -> `á`), and a dead character + space worked correctly too. __Defect:__ In our keyboard-layout helper, we were calling `ToUnicodeEx`, which, confusingly, is actually side-effectful - it can change the state of the keyboard, in particular dead keys: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-tounicodeex#parameters __Fix:__ There is a new flag introduced in Win10 >1607 that causes that particular API call to not change the keyboard state. With that fix, the dead keys behave as expected. Fixes #3157 --- CHANGES_CURRENT.md | 1 + manual_test/cases.md | 18 ++++++++++++++++++ .../stubs/keyboard-layout-windows.c | 8 +++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CHANGES_CURRENT.md b/CHANGES_CURRENT.md index df15d3765d..7723712c68 100644 --- a/CHANGES_CURRENT.md +++ b/CHANGES_CURRENT.md @@ -12,6 +12,7 @@ - #3146 - Vim: Fix command-line staying open when clicking the editor or file explorer (fixes #3031) - #3161 - Configuration: Turn soft word-wrap on by default (fixes #3161) - #3162 - Windows: Support opening UNC paths (fixes #3151) +- #3166 - Windows: Fix dead key input (fixes #3157) ### Performance diff --git a/manual_test/cases.md b/manual_test/cases.md index 0b60f76170..05919cf44b 100644 --- a/manual_test/cases.md +++ b/manual_test/cases.md @@ -192,6 +192,24 @@ __Pass:__ - [ ] OSX - [ ] Linux +## 7.4 Dead Keys + +Regresion test for #3157 + +Prerequisite: +- Install ENG-INTL keyboard layout + +- Switch keyboard layout to English (International) +- Run Onivim 2 +- Enter dead key (') followed by space -> should type key +- Press dead key twice (") - platform dependent, should output one or two instances of the key +- Enter dead key (') followed by composing character (like a) - should get à + +__Pass:__ +- [ ] Win +- [ ] OSX +- [ ] Linux + # 8. Workspace ## 8.1 Open Workspace via Command Palette diff --git a/src/oni2-keyboard-layout/stubs/keyboard-layout-windows.c b/src/oni2-keyboard-layout/stubs/keyboard-layout-windows.c index a527544a5d..cde3151110 100644 --- a/src/oni2-keyboard-layout/stubs/keyboard-layout-windows.c +++ b/src/oni2-keyboard-layout/stubs/keyboard-layout-windows.c @@ -7,6 +7,9 @@ #define SPACE_SCAN_CODE 0x0039 +// Parameter to pass to ToUnicodeEx: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-tounicodeex#parameters +#define DONT_CHANGE_KEYBOARD_STATE 4 + #include #include @@ -87,7 +90,10 @@ CAMLprim value oni2_KeyboardLayoutInit() { int keyboardCharacterToUTF8(UINT keycode, UINT scancode, BYTE *keyboardState, char* dest, int destSize, HKL keyboardLayout) { wchar_t destUtf16[UTF16_BUFFER_SIZE]; - int utf16Count = ToUnicodeEx(keycode, scancode, keyboardState, destUtf16, UTF16_BUFFER_SIZE, 0, keyboardLayout); + // CAREFUL: ToUnicodeEx has the side-effect of resetting dead key state, as well as others - see: + // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-tounicodeex#remarks + // Fix #3157, for Windows 10 >1607 by passing bit 2 to `wFlags` + int utf16Count = ToUnicodeEx(keycode, scancode, keyboardState, destUtf16, UTF16_BUFFER_SIZE, DONT_CHANGE_KEYBOARD_STATE, keyboardLayout); if (utf16Count == -1) { return -1;