|
@@ -23,9 +23,11 @@
|
|
|
#if defined(SDL_VIDEO_DRIVER_WINDOWS) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
|
|
|
|
|
|
#include "SDL_windowsvideo.h"
|
|
|
+#include "SDL_windowsevents.h"
|
|
|
|
|
|
-#include "../../events/SDL_mouse_c.h"
|
|
|
#include "../SDL_video_c.h"
|
|
|
+#include "../../events/SDL_mouse_c.h"
|
|
|
+#include "../../joystick/usb_ids.h"
|
|
|
|
|
|
DWORD SDL_last_warp_time = 0;
|
|
|
HCURSOR SDL_cursor = NULL;
|
|
@@ -33,9 +35,84 @@ static SDL_Cursor *SDL_blank_cursor = NULL;
|
|
|
|
|
|
static int rawInputEnableCount = 0;
|
|
|
|
|
|
+typedef struct
|
|
|
+{
|
|
|
+ HANDLE ready_event;
|
|
|
+ HANDLE done_event;
|
|
|
+ HANDLE thread;
|
|
|
+} RawMouseThreadData;
|
|
|
+
|
|
|
+static RawMouseThreadData thread_data = {
|
|
|
+ INVALID_HANDLE_VALUE,
|
|
|
+ INVALID_HANDLE_VALUE,
|
|
|
+ INVALID_HANDLE_VALUE
|
|
|
+};
|
|
|
+
|
|
|
+static DWORD WINAPI WIN_RawMouseThread(LPVOID param)
|
|
|
+{
|
|
|
+ RAWINPUTDEVICE rawMouse;
|
|
|
+ HWND window;
|
|
|
+
|
|
|
+ window = CreateWindowEx(0, TEXT("Message"), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
|
|
|
+ if (!window) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ rawMouse.usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
|
|
|
+ rawMouse.usUsage = USB_USAGE_GENERIC_MOUSE;
|
|
|
+ rawMouse.dwFlags = 0;
|
|
|
+ rawMouse.hwndTarget = window;
|
|
|
+
|
|
|
+ if (!RegisterRawInputDevices(&rawMouse, 1, sizeof(rawMouse))) {
|
|
|
+ DestroyWindow(window);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Tell the parent we're ready to go! */
|
|
|
+ SetEvent(thread_data.ready_event);
|
|
|
+
|
|
|
+ for ( ; ; ) {
|
|
|
+ if (MsgWaitForMultipleObjects(1, &thread_data.done_event, 0, INFINITE, QS_RAWINPUT) != WAIT_OBJECT_0 + 1) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Clear the queue status so MsgWaitForMultipleObjects() will wait again */
|
|
|
+ (void)GetQueueStatus(QS_RAWINPUT);
|
|
|
+
|
|
|
+ WIN_PollRawMouseInput();
|
|
|
+ }
|
|
|
+
|
|
|
+ rawMouse.dwFlags |= RIDEV_REMOVE;
|
|
|
+ RegisterRawInputDevices(&rawMouse, 1, sizeof(rawMouse));
|
|
|
+
|
|
|
+ DestroyWindow(window);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void CleanupRawMouseThreadData(void)
|
|
|
+{
|
|
|
+ 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 (thread_data.ready_event != INVALID_HANDLE_VALUE) {
|
|
|
+ CloseHandle(thread_data.ready_event);
|
|
|
+ thread_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;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int ToggleRawInput(SDL_bool enabled)
|
|
|
{
|
|
|
- RAWINPUTDEVICE rawMouse = { 0x01, 0x02, 0, NULL }; /* Mouse: UsagePage = 1, Usage = 2 */
|
|
|
+ int result = -1;
|
|
|
|
|
|
if (enabled) {
|
|
|
rawInputEnableCount++;
|
|
@@ -52,23 +129,48 @@ static int ToggleRawInput(SDL_bool enabled)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (!enabled) {
|
|
|
- rawMouse.dwFlags |= RIDEV_REMOVE;
|
|
|
- }
|
|
|
+ if (enabled) {
|
|
|
+ HANDLE handles[2];
|
|
|
|
|
|
- /* (Un)register raw input for mice */
|
|
|
- if (RegisterRawInputDevices(&rawMouse, 1, sizeof(RAWINPUTDEVICE)) == FALSE) {
|
|
|
- /* Reset the enable count, otherwise subsequent enable calls will
|
|
|
- believe raw input is enabled */
|
|
|
- rawInputEnableCount = 0;
|
|
|
+ thread_data.ready_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
+ if (thread_data.ready_event == INVALID_HANDLE_VALUE) {
|
|
|
+ WIN_SetError("CreateEvent");
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ thread_data.done_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
+ if (thread_data.done_event == INVALID_HANDLE_VALUE) {
|
|
|
+ WIN_SetError("CreateEvent");
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
|
|
|
- /* Only return an error when registering. If we unregister and fail,
|
|
|
- then it's probably that we unregistered twice. That's OK. */
|
|
|
- if (enabled) {
|
|
|
- return SDL_Unsupported();
|
|
|
+ thread_data.thread = CreateThread(NULL, 0, WIN_RawMouseThread, &thread_data, 0, NULL);
|
|
|
+ if (thread_data.thread == INVALID_HANDLE_VALUE) {
|
|
|
+ WIN_SetError("CreateThread");
|
|
|
+ goto done;
|
|
|
}
|
|
|
+
|
|
|
+ /* Wait for the thread to signal ready or exit */
|
|
|
+ handles[0] = thread_data.ready_event;
|
|
|
+ handles[1] = thread_data.thread;
|
|
|
+ if (WaitForMultipleObjects(2, handles, FALSE, INFINITE) != WAIT_OBJECT_0) {
|
|
|
+ SDL_SetError("Couldn't set up raw input handling");
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ result = 0;
|
|
|
+ } else {
|
|
|
+ CleanupRawMouseThreadData();
|
|
|
+ result = 0;
|
|
|
}
|
|
|
- return 0;
|
|
|
+
|
|
|
+done:
|
|
|
+ if (enabled && result < 0) {
|
|
|
+ CleanupRawMouseThreadData();
|
|
|
+
|
|
|
+ /* Reset rawInputEnableCount so we can try again */
|
|
|
+ rawInputEnableCount = 0;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
static SDL_Cursor *WIN_CreateDefaultCursor()
|