SDL_windowsmouse.c 20 KB

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