Atlas - SDL_windowsrawinput.c
Home / ext / SDL / src / video / windows Lines: 1 | Size: 9158 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#if defined(SDL_VIDEO_DRIVER_WINDOWS) 24 25#include "SDL_windowsvideo.h" 26 27#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 28 29#include "SDL_windowsevents.h" 30 31#include "../../joystick/usb_ids.h" 32#include "../../events/SDL_events_c.h" 33#include "../../thread/SDL_systhread.h" 34 35#define ENABLE_RAW_MOUSE_INPUT 0x01 36#define ENABLE_RAW_KEYBOARD_INPUT 0x02 37#define RAW_KEYBOARD_FLAG_NOHOTKEYS 0x04 38 39typedef struct 40{ 41 bool done; 42 Uint32 flags; 43 HANDLE ready_event; 44 HANDLE done_event; 45 HANDLE thread; 46} RawInputThreadData; 47 48static RawInputThreadData thread_data = { 49 false, 50 0, 51 INVALID_HANDLE_VALUE, 52 INVALID_HANDLE_VALUE, 53 INVALID_HANDLE_VALUE 54}; 55 56static DWORD WINAPI WIN_RawInputThread(LPVOID param) 57{ 58 SDL_VideoDevice *_this = SDL_GetVideoDevice(); 59 RawInputThreadData *data = (RawInputThreadData *)param; 60 RAWINPUTDEVICE devices[2]; 61 HWND window; 62 UINT count = 0; 63 64 SDL_SYS_SetupThread("SDLRawInput"); 65 66 window = CreateWindowEx(0, TEXT("Message"), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); 67 if (!window) { 68 return 0; 69 } 70 71 SDL_zeroa(devices); 72 73 if (data->flags & ENABLE_RAW_MOUSE_INPUT) { 74 devices[count].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP; 75 devices[count].usUsage = USB_USAGE_GENERIC_MOUSE; 76 devices[count].dwFlags = 0; 77 devices[count].hwndTarget = window; 78 ++count; 79 } 80 81 if (data->flags & ENABLE_RAW_KEYBOARD_INPUT) { 82 devices[count].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP; 83 devices[count].usUsage = USB_USAGE_GENERIC_KEYBOARD; 84 devices[count].dwFlags = 0; 85 if (data->flags & RAW_KEYBOARD_FLAG_NOHOTKEYS) { 86 devices[count].dwFlags |= RIDEV_NOHOTKEYS; 87 } 88 devices[count].hwndTarget = window; 89 ++count; 90 } 91 92 if (!RegisterRawInputDevices(devices, count, sizeof(devices[0]))) { 93 DestroyWindow(window); 94 return 0; 95 } 96 97 // Make sure we get events as soon as possible 98 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); 99 100 // Tell the parent we're ready to go! 101 SetEvent(data->ready_event); 102 103 Uint64 idle_begin = SDL_GetTicksNS(); 104 while (!data->done && 105 // The high-order word of GetQueueStatus() will let us know if there's currently raw input to be processed. 106 // If there isn't, then we'll wait for new data to arrive with MsgWaitForMultipleObjects(). 107 ((HIWORD(GetQueueStatus(QS_RAWINPUT)) & QS_RAWINPUT) || 108 (MsgWaitForMultipleObjects(1, &data->done_event, FALSE, INFINITE, QS_RAWINPUT) == WAIT_OBJECT_0 + 1))) { 109 110 Uint64 idle_end = SDL_GetTicksNS(); 111 Uint64 idle_time = idle_end - idle_begin; 112 Uint64 usb_8khz_interval = SDL_US_TO_NS(125); 113 Uint64 poll_start = idle_time < usb_8khz_interval ? _this->internal->last_rawinput_poll : idle_end; 114 115 WIN_PollRawInput(_this, poll_start); 116 117 // Reset idle_begin for the next go-around 118 idle_begin = SDL_GetTicksNS(); 119 } 120 121 if (_this->internal->raw_input_fake_pen_id) { 122 SDL_RemovePenDevice(0, SDL_GetKeyboardFocus(), _this->internal->raw_input_fake_pen_id); 123 _this->internal->raw_input_fake_pen_id = 0; 124 } 125 126 devices[0].dwFlags |= RIDEV_REMOVE; 127 devices[0].hwndTarget = NULL; 128 devices[1].dwFlags |= RIDEV_REMOVE; 129 devices[1].hwndTarget = NULL; 130 RegisterRawInputDevices(devices, count, sizeof(devices[0])); 131 132 DestroyWindow(window); 133 134 return 0; 135} 136 137static void CleanupRawInputThreadData(RawInputThreadData *data) 138{ 139 if (data->thread != INVALID_HANDLE_VALUE) { 140 data->done = true; 141 SetEvent(data->done_event); 142 WaitForSingleObject(data->thread, 3000); 143 CloseHandle(data->thread); 144 data->thread = INVALID_HANDLE_VALUE; 145 } 146 147 if (data->ready_event != INVALID_HANDLE_VALUE) { 148 CloseHandle(data->ready_event); 149 data->ready_event = INVALID_HANDLE_VALUE; 150 } 151 152 if (data->done_event != INVALID_HANDLE_VALUE) { 153 CloseHandle(data->done_event); 154 data->done_event = INVALID_HANDLE_VALUE; 155 } 156} 157 158static bool WIN_SetRawInputEnabled(SDL_VideoDevice *_this, Uint32 flags) 159{ 160 bool result = false; 161 162 CleanupRawInputThreadData(&thread_data); 163 164 if (flags) { 165 HANDLE handles[2]; 166 167 thread_data.flags = flags; 168 thread_data.ready_event = CreateEvent(NULL, FALSE, FALSE, NULL); 169 if (thread_data.ready_event == INVALID_HANDLE_VALUE) { 170 WIN_SetError("CreateEvent"); 171 goto done; 172 } 173 174 thread_data.done = false; 175 thread_data.done_event = CreateEvent(NULL, FALSE, FALSE, NULL); 176 if (thread_data.done_event == INVALID_HANDLE_VALUE) { 177 WIN_SetError("CreateEvent"); 178 goto done; 179 } 180 181 thread_data.thread = CreateThread(NULL, 0, WIN_RawInputThread, &thread_data, 0, NULL); 182 if (thread_data.thread == INVALID_HANDLE_VALUE) { 183 WIN_SetError("CreateThread"); 184 goto done; 185 } 186 187 // Wait for the thread to signal ready or exit 188 handles[0] = thread_data.ready_event; 189 handles[1] = thread_data.thread; 190 if (WaitForMultipleObjects(2, handles, FALSE, INFINITE) != WAIT_OBJECT_0) { 191 SDL_SetError("Couldn't set up raw input handling"); 192 goto done; 193 } 194 result = true; 195 } else { 196 result = true; 197 } 198 199done: 200 if (!result) { 201 CleanupRawInputThreadData(&thread_data); 202 } 203 return result; 204} 205 206static bool WIN_UpdateRawInputEnabled(SDL_VideoDevice *_this) 207{ 208 SDL_VideoData *data = _this->internal; 209 Uint32 flags = 0; 210 if (data->raw_mouse_enabled) { 211 flags |= ENABLE_RAW_MOUSE_INPUT; 212 } 213 if (data->raw_keyboard_enabled) { 214 flags |= ENABLE_RAW_KEYBOARD_INPUT; 215 if (data->raw_keyboard_flag_nohotkeys) { 216 flags |= RAW_KEYBOARD_FLAG_NOHOTKEYS; 217 } 218 } 219 if (flags != data->raw_input_enabled) { 220 if (WIN_SetRawInputEnabled(_this, flags)) { 221 data->raw_input_enabled = flags; 222 } else { 223 return false; 224 } 225 } 226 return true; 227} 228 229bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled) 230{ 231 SDL_VideoData *data = _this->internal; 232 data->raw_mouse_enabled = enabled; 233 if (data->gameinput_context) { 234 if (!WIN_UpdateGameInputEnabled(_this)) { 235 data->raw_mouse_enabled = !enabled; 236 return false; 237 } 238 } else { 239 if (!WIN_UpdateRawInputEnabled(_this)) { 240 data->raw_mouse_enabled = !enabled; 241 return false; 242 } 243 } 244 return true; 245} 246 247bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled) 248{ 249 SDL_VideoData *data = _this->internal; 250 data->raw_keyboard_enabled = enabled; 251 if (data->gameinput_context) { 252 if (!WIN_UpdateGameInputEnabled(_this)) { 253 data->raw_keyboard_enabled = !enabled; 254 return false; 255 } 256 } else { 257 if (!WIN_UpdateRawInputEnabled(_this)) { 258 data->raw_keyboard_enabled = !enabled; 259 return false; 260 } 261 } 262 return true; 263} 264 265typedef enum WIN_RawKeyboardFlag { 266 NOHOTKEYS 267} WIN_RawKeyboardFlag; 268 269static bool WIN_SetRawKeyboardFlag(SDL_VideoDevice *_this, WIN_RawKeyboardFlag flag, bool enabled) 270{ 271 SDL_VideoData *data = _this->internal; 272 273 switch(flag) { 274 case NOHOTKEYS: 275 data->raw_keyboard_flag_nohotkeys = enabled; 276 break; 277 default: 278 return false; 279 } 280 281 if (data->gameinput_context) { 282 return true; 283 } 284 285 return WIN_UpdateRawInputEnabled(_this); 286} 287 288bool WIN_SetRawKeyboardFlag_NoHotkeys(SDL_VideoDevice *_this, bool enabled) 289{ 290 return WIN_SetRawKeyboardFlag(_this, NOHOTKEYS, enabled); 291} 292 293#else 294 295bool WIN_SetRawMouseEnabled(SDL_VideoDevice *_this, bool enabled) 296{ 297 return SDL_Unsupported(); 298} 299 300bool WIN_SetRawKeyboardEnabled(SDL_VideoDevice *_this, bool enabled) 301{ 302 return SDL_Unsupported(); 303} 304 305bool WIN_SetRawKeyboardFlag_NoHotkeys(SDL_VideoDevice *_this, bool enabled) 306{ 307 return SDL_Unsupported(); 308} 309 310#endif // !SDL_PLATFORM_XBOXONE && !SDL_PLATFORM_XBOXSERIES 311 312#endif // SDL_VIDEO_DRIVER_WINDOWS 313[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.