summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCameron Gutman <aicommander@gmail.com>2021-01-28 20:02:01 -0600
committerCameron Gutman <aicommander@gmail.com>2021-01-28 20:02:01 -0600
commit56b74131c1d67128a0d066aa5b30e9df4022764e (patch)
treed9a2a55e73d62e2a78b188d1d8fda8ac6779add1
parente40435273d3ade7d8b2ed6daea5a11261d00718d (diff)
downloadsdl-56b74131c1d67128a0d066aa5b30e9df4022764e.tar.gz
Properly handle keys already down when the hook is installed
For keys that are already down when we install the keyboard hook, we need to allow the WM_KEYUP/WM_SYSKEYUP message to be processed normally. This ensures that other applications see the key up, which prevents the key from being stuck down from the perspective of other apps when our grab is released.
-rw-r--r--src/video/windows/SDL_windowsevents.c11
-rw-r--r--src/video/windows/SDL_windowsvideo.h2
-rw-r--r--src/video/windows/SDL_windowswindow.c5
3 files changed, 18 insertions, 0 deletions
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 87878dd73..4f914aae6 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -432,6 +432,7 @@ LRESULT CALLBACK
WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT* hookData = (KBDLLHOOKSTRUCT*)lParam;
+ SDL_VideoData* data = SDL_GetVideoDevice()->driverdata;
SDL_Scancode scanCode;
if (nCode < 0 || nCode != HC_ACTION) {
@@ -474,6 +475,16 @@ WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
SDL_SendKeyboardKey(SDL_PRESSED, scanCode);
} else {
SDL_SendKeyboardKey(SDL_RELEASED, scanCode);
+
+ /* If the key was down prior to our hook being installed, allow the
+ key up message to pass normally the first time. This ensures other
+ windows have a consistent view of the key state, and avoids keys
+ being stuck down in those windows if they are down when the grab
+ happens and raised while grabbed. */
+ if (hookData->vkCode <= 0xFF && data->pre_hook_key_state[hookData->vkCode]) {
+ data->pre_hook_key_state[hookData->vkCode] = 0;
+ return CallNextHookEx(NULL, nCode, wParam, lParam);
+ }
}
return 1;
diff --git a/src/video/windows/SDL_windowsvideo.h b/src/video/windows/SDL_windowsvideo.h
index cca98c1ea..86fbf3798 100644
--- a/src/video/windows/SDL_windowsvideo.h
+++ b/src/video/windows/SDL_windowsvideo.h
@@ -186,6 +186,8 @@ typedef struct SDL_VideoData
DWORD ime_convmodesinkcookie;
TSFSink *ime_uielemsink;
TSFSink *ime_ippasink;
+
+ BYTE pre_hook_key_state[256];
} SDL_VideoData;
extern SDL_bool g_WindowsEnableMessageLoop;
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index 6eb26ebc7..95ceaf993 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -759,6 +759,11 @@ static void WIN_GrabKeyboard(SDL_Window *window)
return;
}
+ /* Capture a snapshot of the current keyboard state before the hook */
+ if (!GetKeyboardState(data->videodata->pre_hook_key_state)) {
+ return;
+ }
+
/* To grab the keyboard, we have to install a low-level keyboard hook to
intercept keys that would normally be captured by the OS. Intercepting
all key events on the system is rather invasive, but it's what Microsoft