When pressing Alt-Tab for example, the application receives the KeyPress event for Alt key before losing focus, but when focusing it back it never receives the corresponding KeyRelease event and this can lead to incorrect key state for applications listening on WM_SYSKEYUP/DOWN messages, or for applications that use dinput keyboard device which is implemented with the corresponding low-level keyboard hooks messages.
When focus is gained back the application receives a KeymapNotify to indicate the full keyboard state, and this can be used to make up for the missing KeyRelease events.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winex11.drv/keyboard.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 131c5f5442f..166b5446aab 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1209,14 +1209,20 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) int i, j; BYTE keystate[256]; WORD vkey; + WORD scan; + DWORD flags; BOOL changed = FALSE; struct { WORD vkey; + WORD scan; WORD pressed; } keys[256];
if (!get_async_key_state( keystate )) return FALSE;
+ /* from KeymapNotify documentation this should always be true */ + if (!hwnd) hwnd = GetForegroundWindow(); + memset(keys, 0, sizeof(keys));
EnterCriticalSection( &kbd_section ); @@ -1229,11 +1235,13 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) for (j = 0; j < 8; j++) { vkey = keyc2vkey[(i * 8) + j]; + scan = keyc2scan[(i * 8) + j] & 0xff;
/* If multiple keys map to the same vkey, we want to report it as * pressed iff any of them are pressed. */ if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey; if (event->xkeymap.key_vector[i] & (1<<j)) keys[vkey & 0xff].pressed = TRUE; + keys[vkey & 0xff].scan = scan; } }
@@ -1244,6 +1252,14 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) TRACE( "Adjusting state for vkey %#.2x. State before %#.2x\n", keys[vkey].vkey, keystate[vkey]);
+ flags = 0; + if (!keys[vkey].pressed) + flags |= KEYEVENTF_KEYUP; + if (keys[vkey].vkey & 0x100) + flags |= KEYEVENTF_EXTENDEDKEY; + + X11DRV_send_keyboard_input( hwnd, vkey, keys[vkey].scan, flags, GetTickCount() ); + update_key_state( keystate, vkey, keys[vkey].pressed ); changed = TRUE; }
On 8/7/19 8:44 AM, Rémi Bernon wrote:
When pressing Alt-Tab for example, the application receives the KeyPress event for Alt key before losing focus, but when focusing it back it never receives the corresponding KeyRelease event and this can lead to incorrect key state for applications listening on WM_SYSKEYUP/DOWN messages, or for applications that use dinput keyboard device which is implemented with the corresponding low-level keyboard hooks messages.
When focus is gained back the application receives a KeymapNotify to indicate the full keyboard state, and this can be used to make up for the missing KeyRelease events.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
When writing tests for 1bc9c4fdb I came to the conclusion that Windows doesn't send window messages in this case. Low-level hooks may be a different matter. I guess this change is not likely to break anything per se, but it's not strictly correct either.
On 8/7/19 5:19 PM, Zebediah Figura wrote:
On 8/7/19 8:44 AM, Rémi Bernon wrote:
When pressing Alt-Tab for example, the application receives the KeyPress event for Alt key before losing focus, but when focusing it back it never receives the corresponding KeyRelease event and this can lead to incorrect key state for applications listening on WM_SYSKEYUP/DOWN messages, or for applications that use dinput keyboard device which is implemented with the corresponding low-level keyboard hooks messages.
When focus is gained back the application receives a KeymapNotify to indicate the full keyboard state, and this can be used to make up for the missing KeyRelease events.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
When writing tests for 1bc9c4fdb I came to the conclusion that Windows doesn't send window messages in this case. Low-level hooks may be a different matter. I guess this change is not likely to break anything per se, but it's not strictly correct either.
Indeed, but it's not specific to this change. When comparing with Windows I could see that keyboard messages and low level hooks behave a little differently on Wine:
Pressing Alt alone: * On Windows, it triggers repeated low-level WM_SYSKEYDOWN and WM_SYSKEYDOWN messages. * On Wine, it triggers only once a low-level WM_SYSKEYDOWN and a WM_SYSKEYDOWN message.
Releasing Alt alone: * On Windows, it triggers a low-level WM_KEYUP and a WM_SYSKEYUP message. * On Wine, it triggers a WM_SYSKEYUP low-level and message, and a WM_KEYUP low-level and message.
Also, low-level hooks are called on Windows even if the application is in background, they aren't on Wine. This means that when focus is restored from Alt-Tab, there's a WM_KEYUP low-level hook call on Windows that is missing on Wine.
This could be another way to fix the issue here, as the low-level hook call would make dinput update it state correctly. Listening to background keyboard X11 events however would require to subscribe to xinput2 events, which is currently considered optional and only activated when cursor clipping is active (so only on foreground windows). The raw input patch series could help by making xinput2 active all the time, but it would still be optional.
On 8/7/19 5:19 PM, Zebediah Figura wrote:
On 8/7/19 8:44 AM, Rémi Bernon wrote:
When pressing Alt-Tab for example, the application receives the KeyPress event for Alt key before losing focus, but when focusing it back it never receives the corresponding KeyRelease event and this can lead to incorrect key state for applications listening on WM_SYSKEYUP/DOWN messages, or for applications that use dinput keyboard device which is implemented with the corresponding low-level keyboard hooks messages.
When focus is gained back the application receives a KeymapNotify to indicate the full keyboard state, and this can be used to make up for the missing KeyRelease events.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
When writing tests for 1bc9c4fdb I came to the conclusion that Windows doesn't send window messages in this case. Low-level hooks may be a different matter. I guess this change is not likely to break anything per se, but it's not strictly correct either.
Actually it does break some games. I'm trying to find way to make it right.