瀏覽代碼

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.
Cameron Gutman 5 年之前
父節點
當前提交
a78bce9e38
共有 3 個文件被更改,包括 18 次插入0 次删除
  1. 11 0
      src/video/windows/SDL_windowsevents.c
  2. 2 0
      src/video/windows/SDL_windowsvideo.h
  3. 5 0
      src/video/windows/SDL_windowswindow.c

+ 11 - 0
src/video/windows/SDL_windowsevents.c

@@ -432,6 +432,7 @@ LRESULT CALLBACK
 WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
 WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
 {
 {
     KBDLLHOOKSTRUCT* hookData = (KBDLLHOOKSTRUCT*)lParam;
     KBDLLHOOKSTRUCT* hookData = (KBDLLHOOKSTRUCT*)lParam;
+    SDL_VideoData* data = SDL_GetVideoDevice()->driverdata;
     SDL_Scancode scanCode;
     SDL_Scancode scanCode;
 
 
     if (nCode < 0 || nCode != HC_ACTION) {
     if (nCode < 0 || nCode != HC_ACTION) {
@@ -474,6 +475,16 @@ WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
         SDL_SendKeyboardKey(SDL_PRESSED, scanCode);
         SDL_SendKeyboardKey(SDL_PRESSED, scanCode);
     } else {
     } else {
         SDL_SendKeyboardKey(SDL_RELEASED, scanCode);
         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;
     return 1;

+ 2 - 0
src/video/windows/SDL_windowsvideo.h

@@ -186,6 +186,8 @@ typedef struct SDL_VideoData
     DWORD ime_convmodesinkcookie;
     DWORD ime_convmodesinkcookie;
     TSFSink *ime_uielemsink;
     TSFSink *ime_uielemsink;
     TSFSink *ime_ippasink;
     TSFSink *ime_ippasink;
+
+    BYTE pre_hook_key_state[256];
 } SDL_VideoData;
 } SDL_VideoData;
 
 
 extern SDL_bool g_WindowsEnableMessageLoop;
 extern SDL_bool g_WindowsEnableMessageLoop;

+ 5 - 0
src/video/windows/SDL_windowswindow.c

@@ -759,6 +759,11 @@ static void WIN_GrabKeyboard(SDL_Window *window)
         return;
         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
     /* 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
        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
        all key events on the system is rather invasive, but it's what Microsoft