Browse Source

windows: enable raw keyboard input when raw mouse input is enabled

Sam Lantinga 1 year ago
parent
commit
012fc1e32b

+ 41 - 13
src/video/windows/SDL_windowsevents.c

@@ -512,9 +512,13 @@ WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
     }
     }
 
 
     if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
     if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
-        SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, scanCode);
+        if (data->raw_input_enable_count == 0) {
+            SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, scanCode);
+        }
     } else {
     } else {
-        SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_RELEASED, scanCode);
+        if (data->raw_input_enable_count == 0) {
+            SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, SDL_RELEASED, scanCode);
+        }
 
 
         /* If the key was down prior to our hook being installed, allow the
         /* 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
            key up message to pass normally the first time. This ensures other
@@ -532,8 +536,14 @@ WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
 
 
 static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_WindowData *data, HANDLE hDevice, RAWMOUSE *rawmouse)
 static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_WindowData *data, HANDLE hDevice, RAWMOUSE *rawmouse)
 {
 {
+    SDL_Mouse *mouse = SDL_GetMouse();
     SDL_MouseID mouseID;
     SDL_MouseID mouseID;
 
 
+    /* We only use raw mouse input in relative mode */
+    if (!mouse->relative_mode || mouse->relative_mode_warp) {
+        return;
+    }
+
     if (GetMouseMessageSource(rawmouse->ulExtraInformation) == SDL_MOUSE_EVENT_SOURCE_TOUCH) {
     if (GetMouseMessageSource(rawmouse->ulExtraInformation) == SDL_MOUSE_EVENT_SOURCE_TOUCH) {
         return;
         return;
     }
     }
@@ -619,17 +629,34 @@ static void WIN_HandleRawMouseInput(Uint64 timestamp, SDL_WindowData *data, HAND
     WIN_CheckRawMouseButtons(timestamp, hDevice, rawmouse->usButtonFlags, data, mouseID);
     WIN_CheckRawMouseButtons(timestamp, hDevice, rawmouse->usButtonFlags, data, mouseID);
 }
 }
 
 
-void WIN_PollRawMouseInput(void)
+static void WIN_HandleRawKeyboardInput(Uint64 timestamp, SDL_WindowData *data, HANDLE hDevice, RAWKEYBOARD *rawkeyboard)
+{
+    SDL_KeyboardID keyboardID = (SDL_KeyboardID)(uintptr_t)hDevice;
+
+    Uint8 state = (rawkeyboard->Flags & RI_KEY_BREAK) ? SDL_RELEASED : SDL_PRESSED;
+    Uint16 scanCode = rawkeyboard->MakeCode;
+    if (rawkeyboard->Flags & RI_KEY_E0) {
+        scanCode |= (0xE0 << 8);
+    } else if (rawkeyboard->Flags & RI_KEY_E1) {
+        scanCode |= (0xE1 << 8);
+    }
+
+    // Pack scan code into one byte to make the index
+    Uint8 index = LOBYTE(scanCode) | (HIBYTE(scanCode) ? 0x80 : 0x00);
+    SDL_Scancode code = windows_scancode_table[index];
+
+    SDL_SendKeyboardKey(timestamp, keyboardID, state, code);
+}
+
+void WIN_PollRawInput(SDL_VideoDevice *_this)
 {
 {
-    SDL_Mouse *mouse = SDL_GetMouse();
     SDL_Window *window;
     SDL_Window *window;
     SDL_WindowData *data;
     SDL_WindowData *data;
     UINT size, count, i, total = 0;
     UINT size, count, i, total = 0;
     RAWINPUT *input;
     RAWINPUT *input;
     Uint64 now;
     Uint64 now;
 
 
-    /* We only use raw mouse input in relative mode */
-    if (!mouse->relative_mode || mouse->relative_mode_warp) {
+    if (_this->driverdata->raw_input_enable_count == 0) {
         return;
         return;
     }
     }
 
 
@@ -695,6 +722,9 @@ void WIN_PollRawMouseInput(void)
             if (input->header.dwType == RIM_TYPEMOUSE) {
             if (input->header.dwType == RIM_TYPEMOUSE) {
                 RAWMOUSE *rawmouse = (RAWMOUSE *)((BYTE *)input + data->rawinput_offset);
                 RAWMOUSE *rawmouse = (RAWMOUSE *)((BYTE *)input + data->rawinput_offset);
                 WIN_HandleRawMouseInput(timestamp, window->driverdata, input->header.hDevice, rawmouse);
                 WIN_HandleRawMouseInput(timestamp, window->driverdata, input->header.hDevice, rawmouse);
+            } else if (input->header.dwType == RIM_TYPEKEYBOARD) {
+                RAWKEYBOARD *rawkeyboard = (RAWKEYBOARD *)((BYTE *)input + data->rawinput_offset);
+                WIN_HandleRawKeyboardInput(timestamp, window->driverdata, input->header.hDevice, rawkeyboard);
             }
             }
         }
         }
     }
     }
@@ -1024,13 +1054,11 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
 #if 0   /* We handle raw input all at once instead of using a syscall for each mouse event */
 #if 0   /* We handle raw input all at once instead of using a syscall for each mouse event */
     case WM_INPUT:
     case WM_INPUT:
     {
     {
-        SDL_Mouse *mouse = SDL_GetMouse();
         HRAWINPUT hRawInput = (HRAWINPUT)lParam;
         HRAWINPUT hRawInput = (HRAWINPUT)lParam;
         RAWINPUT inp;
         RAWINPUT inp;
         UINT size = sizeof(inp);
         UINT size = sizeof(inp);
 
 
-        /* We only use raw mouse input in relative mode */
-        if (!mouse->relative_mode || mouse->relative_mode_warp) {
+        if (data->raw_input_enable_count == 0) {
             break;
             break;
         }
         }
 
 
@@ -1040,10 +1068,10 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
         }
         }
 
 
         GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
         GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
-
-        /* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
         if (inp.header.dwType == RIM_TYPEMOUSE) {
         if (inp.header.dwType == RIM_TYPEMOUSE) {
             WIN_HandleRawMouseInput(WIN_GetEventTimestamp(), data, inp.header.hDevice, &inp.data.mouse);
             WIN_HandleRawMouseInput(WIN_GetEventTimestamp(), data, inp.header.hDevice, &inp.data.mouse);
+        } else if (inp.header.dwType == RIM_TYPEKEYBOARD) {
+            WIN_HandleRawKeyboardInput(WIN_GetEventTimestamp(), data, inp.header.hDevice, &inp.data.keyboard);
         }
         }
     } break;
     } break;
 #endif
 #endif
@@ -1107,7 +1135,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
             }
             }
         }
         }
 
 
-        if (code != SDL_SCANCODE_UNKNOWN) {
+        if (data->videodata->raw_input_enable_count == 0 && code != SDL_SCANCODE_UNKNOWN) {
             SDL_SendKeyboardKey(WIN_GetEventTimestamp(), SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, code);
             SDL_SendKeyboardKey(WIN_GetEventTimestamp(), SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, code);
         }
         }
     }
     }
@@ -1121,7 +1149,7 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
         SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
         SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
         const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
         const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
 
 
-        if (code != SDL_SCANCODE_UNKNOWN) {
+        if (data->videodata->raw_input_enable_count == 0 && code != SDL_SCANCODE_UNKNOWN) {
             if (code == SDL_SCANCODE_PRINTSCREEN &&
             if (code == SDL_SCANCODE_PRINTSCREEN &&
                 keyboardState[code] == SDL_RELEASED) {
                 keyboardState[code] == SDL_RELEASED) {
                 SDL_SendKeyboardKey(WIN_GetEventTimestamp(), SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, code);
                 SDL_SendKeyboardKey(WIN_GetEventTimestamp(), SDL_GLOBAL_KEYBOARD_ID, SDL_PRESSED, code);

+ 1 - 1
src/video/windows/SDL_windowsevents.h

@@ -30,7 +30,7 @@ extern HINSTANCE SDL_Instance;
 extern LRESULT CALLBACK WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam);
 extern LRESULT CALLBACK WIN_KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam);
 extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
 extern LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam,
                                        LPARAM lParam);
                                        LPARAM lParam);
-extern void WIN_PollRawMouseInput(void);
+extern void WIN_PollRawInput(SDL_VideoDevice *_this);
 extern void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, SDL_bool initial_check);
 extern void WIN_CheckKeyboardAndMouseHotplug(SDL_VideoDevice *_this, SDL_bool initial_check);
 extern void WIN_PumpEvents(SDL_VideoDevice *_this);
 extern void WIN_PumpEvents(SDL_VideoDevice *_this);
 extern void WIN_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window);
 extern void WIN_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window);

+ 52 - 44
src/video/windows/SDL_windowsmouse.c

@@ -33,24 +33,24 @@ DWORD SDL_last_warp_time = 0;
 HCURSOR SDL_cursor = NULL;
 HCURSOR SDL_cursor = NULL;
 static SDL_Cursor *SDL_blank_cursor = NULL;
 static SDL_Cursor *SDL_blank_cursor = NULL;
 
 
-static int rawInputEnableCount = 0;
-
 typedef struct
 typedef struct
 {
 {
     HANDLE ready_event;
     HANDLE ready_event;
     HANDLE done_event;
     HANDLE done_event;
     HANDLE thread;
     HANDLE thread;
-} RawMouseThreadData;
+} RawInputThreadData;
 
 
-static RawMouseThreadData thread_data = {
+static RawInputThreadData thread_data = {
     INVALID_HANDLE_VALUE,
     INVALID_HANDLE_VALUE,
     INVALID_HANDLE_VALUE,
     INVALID_HANDLE_VALUE,
     INVALID_HANDLE_VALUE
     INVALID_HANDLE_VALUE
 };
 };
 
 
-static DWORD WINAPI WIN_RawMouseThread(LPVOID param)
+static DWORD WINAPI WIN_RawInputThread(LPVOID param)
 {
 {
-    RAWINPUTDEVICE rawMouse;
+    SDL_VideoDevice *_this = SDL_GetVideoDevice();
+    RawInputThreadData *data = (RawInputThreadData *)param;
+    RAWINPUTDEVICE devices[2];
     HWND window;
     HWND window;
 
 
     window = CreateWindowEx(0, TEXT("Message"), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
     window = CreateWindowEx(0, TEXT("Message"), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
@@ -58,76 +58,83 @@ static DWORD WINAPI WIN_RawMouseThread(LPVOID param)
         return 0;
         return 0;
     }
     }
 
 
-    rawMouse.usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
-    rawMouse.usUsage = USB_USAGE_GENERIC_MOUSE;
-    rawMouse.dwFlags = 0;
-    rawMouse.hwndTarget = window;
+    devices[0].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
+    devices[0].usUsage = USB_USAGE_GENERIC_MOUSE;
+    devices[0].dwFlags = 0;
+    devices[0].hwndTarget = window;
+
+    devices[1].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
+    devices[1].usUsage = USB_USAGE_GENERIC_KEYBOARD;
+    devices[1].dwFlags = 0;
+    devices[1].hwndTarget = window;
 
 
-    if (!RegisterRawInputDevices(&rawMouse, 1, sizeof(rawMouse))) {
+    if (!RegisterRawInputDevices(devices, SDL_arraysize(devices), sizeof(devices[0]))) {
         DestroyWindow(window);
         DestroyWindow(window);
         return 0;
         return 0;
     }
     }
 
 
-    /* Make sure we get mouse events as soon as possible */
+    /* Make sure we get events as soon as possible */
     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
 
 
     /* Tell the parent we're ready to go! */
     /* Tell the parent we're ready to go! */
-    SetEvent(thread_data.ready_event);
+    SetEvent(data->ready_event);
 
 
     for ( ; ; ) {
     for ( ; ; ) {
-        if (MsgWaitForMultipleObjects(1, &thread_data.done_event, 0, INFINITE, QS_RAWINPUT) != WAIT_OBJECT_0 + 1) {
+        if (MsgWaitForMultipleObjects(1, &data->done_event, 0, INFINITE, QS_RAWINPUT) != WAIT_OBJECT_0 + 1) {
             break;
             break;
         }
         }
 
 
         /* Clear the queue status so MsgWaitForMultipleObjects() will wait again */
         /* Clear the queue status so MsgWaitForMultipleObjects() will wait again */
         (void)GetQueueStatus(QS_RAWINPUT);
         (void)GetQueueStatus(QS_RAWINPUT);
 
 
-        WIN_PollRawMouseInput();
+        WIN_PollRawInput(_this);
     }
     }
 
 
-    rawMouse.dwFlags |= RIDEV_REMOVE;
-    RegisterRawInputDevices(&rawMouse, 1, sizeof(rawMouse));
+    devices[0].dwFlags |= RIDEV_REMOVE;
+    devices[1].dwFlags |= RIDEV_REMOVE;
+    RegisterRawInputDevices(devices, SDL_arraysize(devices), sizeof(devices[0]));
 
 
     DestroyWindow(window);
     DestroyWindow(window);
 
 
     return 0;
     return 0;
 }
 }
 
 
-static void CleanupRawMouseThreadData(void)
+static void CleanupRawInputThreadData(RawInputThreadData *data)
 {
 {
-    if (thread_data.thread != INVALID_HANDLE_VALUE) {
-        SetEvent(thread_data.done_event);
-        WaitForSingleObject(thread_data.thread, 500);
-        CloseHandle(thread_data.thread);
-        thread_data.thread = INVALID_HANDLE_VALUE;
+    if (data->thread != INVALID_HANDLE_VALUE) {
+        SetEvent(data->done_event);
+        WaitForSingleObject(data->thread, 500);
+        CloseHandle(data->thread);
+        data->thread = INVALID_HANDLE_VALUE;
     }
     }
 
 
-    if (thread_data.ready_event != INVALID_HANDLE_VALUE) {
-        CloseHandle(thread_data.ready_event);
-        thread_data.ready_event = INVALID_HANDLE_VALUE;
+    if (data->ready_event != INVALID_HANDLE_VALUE) {
+        CloseHandle(data->ready_event);
+        data->ready_event = INVALID_HANDLE_VALUE;
     }
     }
 
 
-    if (thread_data.done_event != INVALID_HANDLE_VALUE) {
-        CloseHandle(thread_data.done_event);
-        thread_data.done_event = INVALID_HANDLE_VALUE;
+    if (data->done_event != INVALID_HANDLE_VALUE) {
+        CloseHandle(data->done_event);
+        data->done_event = INVALID_HANDLE_VALUE;
     }
     }
 }
 }
 
 
-static int ToggleRawInput(SDL_bool enabled)
+static int ToggleRawInput(SDL_VideoDevice *_this, SDL_bool enabled)
 {
 {
+    SDL_VideoData *data = _this->driverdata;
     int result = -1;
     int result = -1;
 
 
     if (enabled) {
     if (enabled) {
-        rawInputEnableCount++;
-        if (rawInputEnableCount > 1) {
+        ++data->raw_input_enable_count;
+        if (data->raw_input_enable_count > 1) {
             return 0; /* already done. */
             return 0; /* already done. */
         }
         }
     } else {
     } else {
-        if (rawInputEnableCount == 0) {
+        if (data->raw_input_enable_count == 0) {
             return 0; /* already done. */
             return 0; /* already done. */
         }
         }
-        rawInputEnableCount--;
-        if (rawInputEnableCount > 0) {
+        --data->raw_input_enable_count;
+        if (data->raw_input_enable_count > 0) {
             return 0; /* not time to disable yet */
             return 0; /* not time to disable yet */
         }
         }
     }
     }
@@ -147,7 +154,7 @@ static int ToggleRawInput(SDL_bool enabled)
             goto done;
             goto done;
         }
         }
 
 
-        thread_data.thread = CreateThread(NULL, 0, WIN_RawMouseThread, &thread_data, 0, NULL);
+        thread_data.thread = CreateThread(NULL, 0, WIN_RawInputThread, &thread_data, 0, NULL);
         if (thread_data.thread == INVALID_HANDLE_VALUE) {
         if (thread_data.thread == INVALID_HANDLE_VALUE) {
             WIN_SetError("CreateThread");
             WIN_SetError("CreateThread");
             goto done;
             goto done;
@@ -162,16 +169,16 @@ static int ToggleRawInput(SDL_bool enabled)
         }
         }
         result = 0;
         result = 0;
     } else {
     } else {
-        CleanupRawMouseThreadData();
+        CleanupRawInputThreadData(&thread_data);
         result = 0;
         result = 0;
     }
     }
 
 
 done:
 done:
     if (enabled && result < 0) {
     if (enabled && result < 0) {
-        CleanupRawMouseThreadData();
+        CleanupRawInputThreadData(&thread_data);
 
 
-        /* Reset rawInputEnableCount so we can try again */
-        rawInputEnableCount = 0;
+        /* Reset so we can try again */
+        data->raw_input_enable_count = 0;
     }
     }
     return result;
     return result;
 }
 }
@@ -509,7 +516,7 @@ static int WIN_WarpMouseGlobal(float x, float y)
 
 
 static int WIN_SetRelativeMouseMode(SDL_bool enabled)
 static int WIN_SetRelativeMouseMode(SDL_bool enabled)
 {
 {
-    return ToggleRawInput(enabled);
+    return ToggleRawInput(SDL_GetVideoDevice(), enabled);
 }
 }
 
 
 static int WIN_CaptureMouse(SDL_Window *window)
 static int WIN_CaptureMouse(SDL_Window *window)
@@ -574,9 +581,10 @@ void WIN_InitMouse(SDL_VideoDevice *_this)
 
 
 void WIN_QuitMouse(SDL_VideoDevice *_this)
 void WIN_QuitMouse(SDL_VideoDevice *_this)
 {
 {
-    if (rawInputEnableCount) { /* force RAWINPUT off here. */
-        rawInputEnableCount = 1;
-        ToggleRawInput(SDL_FALSE);
+    SDL_VideoData *data = _this->driverdata;
+    if (data->raw_input_enable_count) { /* force RAWINPUT off here. */
+        data->raw_input_enable_count = 1;
+        ToggleRawInput(_this, SDL_FALSE);
     }
     }
 
 
     if (SDL_blank_cursor) {
     if (SDL_blank_cursor) {

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

@@ -406,6 +406,8 @@ struct SDL_VideoData
 
 
     SDL_bool cleared;
     SDL_bool cleared;
 
 
+    int raw_input_enable_count;
+
 #ifndef SDL_DISABLE_WINDOWS_IME
 #ifndef SDL_DISABLE_WINDOWS_IME
     SDL_bool ime_com_initialized;
     SDL_bool ime_com_initialized;
     struct ITfThreadMgr *ime_threadmgr;
     struct ITfThreadMgr *ime_threadmgr;