summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/video/windows/SDL_windowsmouse.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/video/windows/SDL_windowsmouse.c')
-rw-r--r--contrib/SDL-3.2.8/src/video/windows/SDL_windowsmouse.c745
1 files changed, 745 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/video/windows/SDL_windowsmouse.c b/contrib/SDL-3.2.8/src/video/windows/SDL_windowsmouse.c
new file mode 100644
index 0000000..3d6bcc4
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/windows/SDL_windowsmouse.c
@@ -0,0 +1,745 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
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) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
24
25#include "SDL_windowsvideo.h"
26#include "SDL_windowsevents.h"
27#include "SDL_windowsrawinput.h"
28
29#include "../SDL_video_c.h"
30#include "../../events/SDL_mouse_c.h"
31#include "../../joystick/usb_ids.h"
32#include "../../core/windows/SDL_windows.h" // for checking windows version
33
34
35typedef struct CachedCursor
36{
37 float scale;
38 HCURSOR cursor;
39 struct CachedCursor *next;
40} CachedCursor;
41
42struct SDL_CursorData
43{
44 SDL_Surface *surface;
45 int hot_x;
46 int hot_y;
47 CachedCursor *cache;
48 HCURSOR cursor;
49};
50
51typedef struct
52{
53 Uint64 xs[5];
54 Uint64 ys[5];
55 Sint64 residual[2];
56 Uint32 dpiscale;
57 Uint32 dpidenom;
58 int last_node;
59 bool enhanced;
60 bool dpiaware;
61} WIN_MouseData;
62
63DWORD SDL_last_warp_time = 0;
64HCURSOR SDL_cursor = NULL;
65static SDL_Cursor *SDL_blank_cursor = NULL;
66static WIN_MouseData WIN_system_scale_data;
67
68static SDL_Cursor *WIN_CreateCursorAndData(HCURSOR hcursor)
69{
70 if (!hcursor) {
71 return NULL;
72 }
73
74 SDL_Cursor *cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor));
75 if (!cursor) {
76 return NULL;
77 }
78
79 SDL_CursorData *data = (SDL_CursorData *)SDL_calloc(1, sizeof(*data));
80 if (!data) {
81 SDL_free(cursor);
82 return NULL;
83 }
84
85 data->cursor = hcursor;
86 cursor->internal = data;
87 return cursor;
88}
89
90
91static bool IsMonochromeSurface(SDL_Surface *surface)
92{
93 int x, y;
94 Uint8 r, g, b, a;
95
96 SDL_assert(surface->format == SDL_PIXELFORMAT_ARGB8888);
97
98 for (y = 0; y < surface->h; y++) {
99 for (x = 0; x < surface->w; x++) {
100 SDL_ReadSurfacePixel(surface, x, y, &r, &g, &b, &a);
101
102 // Black or white pixel.
103 if (!((r == 0x00 && g == 0x00 && b == 0x00) || (r == 0xff && g == 0xff && b == 0xff))) {
104 return false;
105 }
106
107 // Transparent or opaque pixel.
108 if (!(a == 0x00 || a == 0xff)) {
109 return false;
110 }
111 }
112 }
113
114 return true;
115}
116
117static HBITMAP CreateColorBitmap(SDL_Surface *surface)
118{
119 HBITMAP bitmap;
120 BITMAPINFO bi;
121 void *pixels;
122
123 SDL_assert(surface->format == SDL_PIXELFORMAT_ARGB8888);
124
125 SDL_zero(bi);
126 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
127 bi.bmiHeader.biWidth = surface->w;
128 bi.bmiHeader.biHeight = -surface->h; // Invert height to make the top-down DIB.
129 bi.bmiHeader.biPlanes = 1;
130 bi.bmiHeader.biBitCount = 32;
131 bi.bmiHeader.biCompression = BI_RGB;
132
133 bitmap = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &pixels, NULL, 0);
134 if (!bitmap || !pixels) {
135 WIN_SetError("CreateDIBSection()");
136 if (bitmap) {
137 DeleteObject(bitmap);
138 }
139 return NULL;
140 }
141
142 SDL_memcpy(pixels, surface->pixels, surface->pitch * surface->h);
143
144 return bitmap;
145}
146
147/* Generate bitmap with a mask and optional monochrome image data.
148 *
149 * For info on the expected mask format see:
150 * https://devblogs.microsoft.com/oldnewthing/20101018-00/?p=12513
151 */
152static HBITMAP CreateMaskBitmap(SDL_Surface *surface, bool is_monochrome)
153{
154 HBITMAP bitmap;
155 bool isstack;
156 void *pixels;
157 int x, y;
158 Uint8 r, g, b, a;
159 Uint8 *dst;
160 const int pitch = ((surface->w + 15) & ~15) / 8;
161 const int size = pitch * surface->h;
162 static const unsigned char masks[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 };
163
164 SDL_assert(surface->format == SDL_PIXELFORMAT_ARGB8888);
165
166 pixels = SDL_small_alloc(Uint8, size * (is_monochrome ? 2 : 1), &isstack);
167 if (!pixels) {
168 SDL_OutOfMemory();
169 return NULL;
170 }
171
172 dst = (Uint8 *)pixels;
173
174 // Make the mask completely transparent.
175 SDL_memset(dst, 0xff, size);
176 if (is_monochrome) {
177 SDL_memset(dst + size, 0x00, size);
178 }
179
180 for (y = 0; y < surface->h; y++, dst += pitch) {
181 for (x = 0; x < surface->w; x++) {
182 SDL_ReadSurfacePixel(surface, x, y, &r, &g, &b, &a);
183
184 if (a != 0) {
185 // Reset bit of an opaque pixel.
186 dst[x >> 3] &= ~masks[x & 7];
187 }
188
189 if (is_monochrome && !(r == 0x00 && g == 0x00 && b == 0x00)) {
190 // Set bit of white or inverted pixel.
191 dst[size + (x >> 3)] |= masks[x & 7];
192 }
193 }
194 }
195
196 bitmap = CreateBitmap(surface->w, surface->h * (is_monochrome ? 2 : 1), 1, 1, pixels);
197 SDL_small_free(pixels, isstack);
198 if (!bitmap) {
199 WIN_SetError("CreateBitmap()");
200 return NULL;
201 }
202
203 return bitmap;
204}
205
206static HCURSOR WIN_CreateHCursor(SDL_Surface *surface, int hot_x, int hot_y)
207{
208 HCURSOR hcursor;
209 ICONINFO ii;
210 bool is_monochrome = IsMonochromeSurface(surface);
211
212 SDL_zero(ii);
213 ii.fIcon = FALSE;
214 ii.xHotspot = (DWORD)hot_x;
215 ii.yHotspot = (DWORD)hot_y;
216 ii.hbmMask = CreateMaskBitmap(surface, is_monochrome);
217 ii.hbmColor = is_monochrome ? NULL : CreateColorBitmap(surface);
218
219 if (!ii.hbmMask || (!is_monochrome && !ii.hbmColor)) {
220 SDL_SetError("Couldn't create cursor bitmaps");
221 if (ii.hbmMask) {
222 DeleteObject(ii.hbmMask);
223 }
224 if (ii.hbmColor) {
225 DeleteObject(ii.hbmColor);
226 }
227 return NULL;
228 }
229
230 hcursor = CreateIconIndirect(&ii);
231 if (!hcursor) {
232 WIN_SetError("CreateIconIndirect()");
233 DeleteObject(ii.hbmMask);
234 if (ii.hbmColor) {
235 DeleteObject(ii.hbmColor);
236 }
237 return NULL;
238 }
239
240 DeleteObject(ii.hbmMask);
241 if (ii.hbmColor) {
242 DeleteObject(ii.hbmColor);
243 }
244
245 return hcursor;
246}
247
248static SDL_Cursor *WIN_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
249{
250 if (!SDL_SurfaceHasAlternateImages(surface)) {
251 HCURSOR hcursor = WIN_CreateHCursor(surface, hot_x, hot_y);
252 if (!hcursor) {
253 return NULL;
254 }
255 return WIN_CreateCursorAndData(hcursor);
256 }
257
258 // Dynamically generate cursors at the appropriate DPI
259 SDL_Cursor *cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor));
260 if (cursor) {
261 SDL_CursorData *data = (SDL_CursorData *)SDL_calloc(1, sizeof(*data));
262 if (!data) {
263 SDL_free(cursor);
264 return NULL;
265 }
266 data->hot_x = hot_x;
267 data->hot_y = hot_y;
268 data->surface = surface;
269 ++surface->refcount;
270 cursor->internal = data;
271 }
272 return cursor;
273}
274
275static SDL_Cursor *WIN_CreateBlankCursor(void)
276{
277 SDL_Cursor *cursor = NULL;
278 SDL_Surface *surface = SDL_CreateSurface(32, 32, SDL_PIXELFORMAT_ARGB8888);
279 if (surface) {
280 cursor = WIN_CreateCursor(surface, 0, 0);
281 SDL_DestroySurface(surface);
282 }
283 return cursor;
284}
285
286static SDL_Cursor *WIN_CreateSystemCursor(SDL_SystemCursor id)
287{
288 LPCTSTR name;
289
290 switch (id) {
291 default:
292 SDL_assert(!"Unknown system cursor ID");
293 return NULL;
294 case SDL_SYSTEM_CURSOR_DEFAULT:
295 name = IDC_ARROW;
296 break;
297 case SDL_SYSTEM_CURSOR_TEXT:
298 name = IDC_IBEAM;
299 break;
300 case SDL_SYSTEM_CURSOR_WAIT:
301 name = IDC_WAIT;
302 break;
303 case SDL_SYSTEM_CURSOR_CROSSHAIR:
304 name = IDC_CROSS;
305 break;
306 case SDL_SYSTEM_CURSOR_PROGRESS:
307 name = IDC_APPSTARTING;
308 break;
309 case SDL_SYSTEM_CURSOR_NWSE_RESIZE:
310 name = IDC_SIZENWSE;
311 break;
312 case SDL_SYSTEM_CURSOR_NESW_RESIZE:
313 name = IDC_SIZENESW;
314 break;
315 case SDL_SYSTEM_CURSOR_EW_RESIZE:
316 name = IDC_SIZEWE;
317 break;
318 case SDL_SYSTEM_CURSOR_NS_RESIZE:
319 name = IDC_SIZENS;
320 break;
321 case SDL_SYSTEM_CURSOR_MOVE:
322 name = IDC_SIZEALL;
323 break;
324 case SDL_SYSTEM_CURSOR_NOT_ALLOWED:
325 name = IDC_NO;
326 break;
327 case SDL_SYSTEM_CURSOR_POINTER:
328 name = IDC_HAND;
329 break;
330 case SDL_SYSTEM_CURSOR_NW_RESIZE:
331 name = IDC_SIZENWSE;
332 break;
333 case SDL_SYSTEM_CURSOR_N_RESIZE:
334 name = IDC_SIZENS;
335 break;
336 case SDL_SYSTEM_CURSOR_NE_RESIZE:
337 name = IDC_SIZENESW;
338 break;
339 case SDL_SYSTEM_CURSOR_E_RESIZE:
340 name = IDC_SIZEWE;
341 break;
342 case SDL_SYSTEM_CURSOR_SE_RESIZE:
343 name = IDC_SIZENWSE;
344 break;
345 case SDL_SYSTEM_CURSOR_S_RESIZE:
346 name = IDC_SIZENS;
347 break;
348 case SDL_SYSTEM_CURSOR_SW_RESIZE:
349 name = IDC_SIZENESW;
350 break;
351 case SDL_SYSTEM_CURSOR_W_RESIZE:
352 name = IDC_SIZEWE;
353 break;
354 }
355 return WIN_CreateCursorAndData(LoadCursor(NULL, name));
356}
357
358static SDL_Cursor *WIN_CreateDefaultCursor(void)
359{
360 SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
361 return WIN_CreateSystemCursor(id);
362}
363
364static void WIN_FreeCursor(SDL_Cursor *cursor)
365{
366 SDL_CursorData *data = cursor->internal;
367
368 if (data->surface) {
369 SDL_DestroySurface(data->surface);
370 }
371 while (data->cache) {
372 CachedCursor *entry = data->cache;
373 data->cache = entry->next;
374 if (entry->cursor) {
375 DestroyCursor(entry->cursor);
376 }
377 SDL_free(entry);
378 }
379 if (data->cursor) {
380 DestroyCursor(data->cursor);
381 }
382 SDL_free(data);
383 SDL_free(cursor);
384}
385
386static HCURSOR GetCachedCursor(SDL_Cursor *cursor)
387{
388 SDL_CursorData *data = cursor->internal;
389
390 SDL_Window *focus = SDL_GetMouseFocus();
391 if (!focus) {
392 return NULL;
393 }
394
395 float scale = SDL_GetDisplayContentScale(SDL_GetDisplayForWindow(focus));
396 for (CachedCursor *entry = data->cache; entry; entry = entry->next) {
397 if (scale == entry->scale) {
398 return entry->cursor;
399 }
400 }
401
402 // Need to create a cursor for this content scale
403 SDL_Surface *surface = NULL;
404 HCURSOR hcursor = NULL;
405 CachedCursor *entry = NULL;
406
407 surface = SDL_GetSurfaceImage(data->surface, scale);
408 if (!surface) {
409 goto error;
410 }
411
412 int hot_x = (int)SDL_round(data->hot_x * scale);
413 int hot_y = (int)SDL_round(data->hot_y * scale);
414 hcursor = WIN_CreateHCursor(surface, hot_x, hot_y);
415 if (!hcursor) {
416 goto error;
417 }
418
419 entry = (CachedCursor *)SDL_malloc(sizeof(*entry));
420 if (!entry) {
421 goto error;
422 }
423 entry->cursor = hcursor;
424 entry->scale = scale;
425 entry->next = data->cache;
426 data->cache = entry;
427
428 SDL_DestroySurface(surface);
429
430 return hcursor;
431
432error:
433 if (surface) {
434 SDL_DestroySurface(surface);
435 }
436 if (hcursor) {
437 DestroyCursor(hcursor);
438 }
439 SDL_free(entry);
440 return NULL;
441}
442
443static bool WIN_ShowCursor(SDL_Cursor *cursor)
444{
445 if (!cursor) {
446 cursor = SDL_blank_cursor;
447 }
448 if (cursor) {
449 if (cursor->internal->surface) {
450 SDL_cursor = GetCachedCursor(cursor);
451 } else {
452 SDL_cursor = cursor->internal->cursor;
453 }
454 } else {
455 SDL_cursor = NULL;
456 }
457 if (SDL_GetMouseFocus() != NULL) {
458 SetCursor(SDL_cursor);
459 }
460 return true;
461}
462
463void WIN_SetCursorPos(int x, int y)
464{
465 // We need to jitter the value because otherwise Windows will occasionally inexplicably ignore the SetCursorPos() or SendInput()
466 SetCursorPos(x, y);
467 SetCursorPos(x + 1, y);
468 SetCursorPos(x, y);
469
470 // Flush any mouse motion prior to or associated with this warp
471#ifdef _MSC_VER // We explicitly want to use GetTickCount(), not GetTickCount64()
472#pragma warning(push)
473#pragma warning(disable : 28159)
474#endif
475 SDL_last_warp_time = GetTickCount();
476 if (!SDL_last_warp_time) {
477 SDL_last_warp_time = 1;
478 }
479#ifdef _MSC_VER
480#pragma warning(pop)
481#endif
482}
483
484static bool WIN_WarpMouse(SDL_Window *window, float x, float y)
485{
486 SDL_WindowData *data = window->internal;
487 HWND hwnd = data->hwnd;
488 POINT pt;
489
490 // Don't warp the mouse while we're doing a modal interaction
491 if (data->in_title_click || data->focus_click_pending) {
492 return true;
493 }
494
495 pt.x = (int)SDL_roundf(x);
496 pt.y = (int)SDL_roundf(y);
497 ClientToScreen(hwnd, &pt);
498 WIN_SetCursorPos(pt.x, pt.y);
499
500 // Send the exact mouse motion associated with this warp
501 SDL_SendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, x, y);
502 return true;
503}
504
505static bool WIN_WarpMouseGlobal(float x, float y)
506{
507 POINT pt;
508
509 pt.x = (int)SDL_roundf(x);
510 pt.y = (int)SDL_roundf(y);
511 SetCursorPos(pt.x, pt.y);
512 return true;
513}
514
515static bool WIN_SetRelativeMouseMode(bool enabled)
516{
517 return WIN_SetRawMouseEnabled(SDL_GetVideoDevice(), enabled);
518}
519
520static bool WIN_CaptureMouse(SDL_Window *window)
521{
522 if (window) {
523 SDL_WindowData *data = window->internal;
524 SetCapture(data->hwnd);
525 } else {
526 SDL_Window *focus_window = SDL_GetMouseFocus();
527
528 if (focus_window) {
529 SDL_WindowData *data = focus_window->internal;
530 if (!data->mouse_tracked) {
531 SDL_SetMouseFocus(NULL);
532 }
533 }
534 ReleaseCapture();
535 }
536
537 return true;
538}
539
540static SDL_MouseButtonFlags WIN_GetGlobalMouseState(float *x, float *y)
541{
542 SDL_MouseButtonFlags result = 0;
543 POINT pt = { 0, 0 };
544 bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
545
546 GetCursorPos(&pt);
547 *x = (float)pt.x;
548 *y = (float)pt.y;
549
550 result |= GetAsyncKeyState(!swapButtons ? VK_LBUTTON : VK_RBUTTON) & 0x8000 ? SDL_BUTTON_LMASK : 0;
551 result |= GetAsyncKeyState(!swapButtons ? VK_RBUTTON : VK_LBUTTON) & 0x8000 ? SDL_BUTTON_RMASK : 0;
552 result |= GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_BUTTON_MMASK : 0;
553 result |= GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_BUTTON_X1MASK : 0;
554 result |= GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_BUTTON_X2MASK : 0;
555
556 return result;
557}
558
559static void WIN_ApplySystemScale(void *internal, Uint64 timestamp, SDL_Window *window, SDL_MouseID mouseID, float *x, float *y)
560{
561 if (!internal) {
562 return;
563 }
564 WIN_MouseData *data = (WIN_MouseData *)internal;
565
566 SDL_VideoDisplay *display = window ? SDL_GetVideoDisplayForWindow(window) : SDL_GetVideoDisplay(SDL_GetPrimaryDisplay());
567
568 Sint64 ix = (Sint64)*x * 65536;
569 Sint64 iy = (Sint64)*y * 65536;
570 Uint32 dpi = display ? (Uint32)(display->content_scale * USER_DEFAULT_SCREEN_DPI) : USER_DEFAULT_SCREEN_DPI;
571
572 if (!data->enhanced) { // early return if flat scale
573 dpi = data->dpiscale * (data->dpiaware ? dpi : USER_DEFAULT_SCREEN_DPI);
574 ix *= dpi;
575 iy *= dpi;
576 ix /= USER_DEFAULT_SCREEN_DPI;
577 iy /= USER_DEFAULT_SCREEN_DPI;
578 ix /= 32;
579 iy /= 32;
580 // data->residual[0] += ix;
581 // data->residual[1] += iy;
582 // ix = 65536 * (data->residual[0] / 65536);
583 // iy = 65536 * (data->residual[1] / 65536);
584 // data->residual[0] -= ix;
585 // data->residual[1] -= iy;
586 *x = (float)ix / 65536.0f;
587 *y = (float)iy / 65536.0f;
588 return;
589 }
590
591 Uint64 *xs = data->xs;
592 Uint64 *ys = data->ys;
593 Uint64 absx = SDL_abs(ix);
594 Uint64 absy = SDL_abs(iy);
595 Uint64 speed = SDL_min(absx, absy) + (SDL_max(absx, absy) << 1); // super cursed approximation used by Windows
596 if (speed == 0) {
597 return;
598 }
599
600 int i, j, k;
601 for (i = 1; i < 5; i++) {
602 j = i;
603 if (speed < xs[j]) {
604 break;
605 }
606 }
607 i -= 1;
608 j -= 1;
609 k = data->last_node;
610 data->last_node = j;
611
612 Uint32 denom = data->dpidenom;
613 Sint64 scale = 0;
614 Sint64 xdiff = xs[j+1] - xs[j];
615 Sint64 ydiff = ys[j+1] - ys[j];
616 if (xdiff != 0) {
617 Sint64 slope = ydiff / xdiff;
618 Sint64 inter = slope * xs[i] - ys[i];
619 scale += slope - inter / speed;
620 }
621
622 if (j > k) {
623 denom <<= 1;
624 xdiff = xs[k+1] - xs[k];
625 ydiff = ys[k+1] - ys[k];
626 if (xdiff != 0) {
627 Sint64 slope = ydiff / xdiff;
628 Sint64 inter = slope * xs[k] - ys[k];
629 scale += slope - inter / speed;
630 }
631 }
632
633 scale *= dpi;
634 ix *= scale;
635 iy *= scale;
636 ix /= denom;
637 iy /= denom;
638 // data->residual[0] += ix;
639 // data->residual[1] += iy;
640 // ix = 65536 * (data->residual[0] / 65536);
641 // iy = 65536 * (data->residual[1] / 65536);
642 // data->residual[0] -= ix;
643 // data->residual[1] -= iy;
644 *x = (float)ix / 65536.0f;
645 *y = (float)iy / 65536.0f;
646}
647
648void WIN_InitMouse(SDL_VideoDevice *_this)
649{
650 SDL_Mouse *mouse = SDL_GetMouse();
651
652 mouse->CreateCursor = WIN_CreateCursor;
653 mouse->CreateSystemCursor = WIN_CreateSystemCursor;
654 mouse->ShowCursor = WIN_ShowCursor;
655 mouse->FreeCursor = WIN_FreeCursor;
656 mouse->WarpMouse = WIN_WarpMouse;
657 mouse->WarpMouseGlobal = WIN_WarpMouseGlobal;
658 mouse->SetRelativeMouseMode = WIN_SetRelativeMouseMode;
659 mouse->CaptureMouse = WIN_CaptureMouse;
660 mouse->GetGlobalMouseState = WIN_GetGlobalMouseState;
661 mouse->ApplySystemScale = WIN_ApplySystemScale;
662 mouse->system_scale_data = &WIN_system_scale_data;
663
664 SDL_SetDefaultCursor(WIN_CreateDefaultCursor());
665
666 SDL_blank_cursor = WIN_CreateBlankCursor();
667
668 WIN_UpdateMouseSystemScale();
669}
670
671void WIN_QuitMouse(SDL_VideoDevice *_this)
672{
673 if (SDL_blank_cursor) {
674 WIN_FreeCursor(SDL_blank_cursor);
675 SDL_blank_cursor = NULL;
676 }
677}
678
679static void ReadMouseCurve(int v, Uint64 xs[5], Uint64 ys[5])
680{
681 bool win8 = WIN_IsWindows8OrGreater();
682 DWORD xbuff[10] = {
683 0x00000000, 0,
684 0x00006e15, 0,
685 0x00014000, 0,
686 0x0003dc29, 0,
687 0x00280000, 0
688 };
689 DWORD ybuff[10] = {
690 0x00000000, 0,
691 win8 ? 0x000111fd : 0x00015eb8, 0,
692 win8 ? 0x00042400 : 0x00054ccd, 0,
693 win8 ? 0x0012fc00 : 0x00184ccd, 0,
694 win8 ? 0x01bbc000 : 0x02380000, 0
695 };
696 DWORD xsize = sizeof(xbuff);
697 DWORD ysize = sizeof(ybuff);
698 HKEY open_handle;
699 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Control Panel\\Mouse", 0, KEY_READ, &open_handle) == ERROR_SUCCESS) {
700 RegQueryValueExW(open_handle, L"SmoothMouseXCurve", NULL, NULL, (BYTE*)xbuff, &xsize);
701 RegQueryValueExW(open_handle, L"SmoothMouseYCurve", NULL, NULL, (BYTE*)ybuff, &ysize);
702 RegCloseKey(open_handle);
703 }
704 xs[0] = 0; // first node must always be origin
705 ys[0] = 0; // first node must always be origin
706 int i;
707 for (i = 1; i < 5; i++) {
708 xs[i] = (7 * (Uint64)xbuff[i*2]);
709 ys[i] = (v * (Uint64)ybuff[i*2]) << 17;
710 }
711}
712
713void WIN_UpdateMouseSystemScale(void)
714{
715 SDL_Mouse *mouse = SDL_GetMouse();
716
717 if (mouse->ApplySystemScale == WIN_ApplySystemScale) {
718 mouse->system_scale_data = &WIN_system_scale_data;
719 }
720
721 // always reinitialize to valid defaults, whether fetch was successful or not.
722 WIN_MouseData *data = &WIN_system_scale_data;
723 data->residual[0] = 0;
724 data->residual[1] = 0;
725 data->dpiscale = 32;
726 data->dpidenom = (10 * (WIN_IsWindows8OrGreater() ? 120 : 150)) << 16;
727 data->dpiaware = WIN_IsPerMonitorV2DPIAware(SDL_GetVideoDevice());
728 data->enhanced = false;
729
730 int v = 10;
731 if (SystemParametersInfo(SPI_GETMOUSESPEED, 0, &v, 0)) {
732 v = SDL_max(1, SDL_min(v, 20));
733 data->dpiscale = SDL_max(SDL_max(v, (v - 2) * 4), (v - 6) * 8);
734 }
735
736 int params[3];
737 if (SystemParametersInfo(SPI_GETMOUSE, 0, &params, 0)) {
738 data->enhanced = params[2] ? true : false;
739 if (params[2]) {
740 ReadMouseCurve(v, data->xs, data->ys);
741 }
742 }
743}
744
745#endif // SDL_VIDEO_DRIVER_WINDOWS