[KMS/DRM] Fix for bug #5468: corruption on dynamic cursor changing caused by wrong buffer size.
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../../SDL_internal.h"
23 #if SDL_VIDEO_DRIVER_WINDOWS
25 #include "SDL_windowsvideo.h"
26 #include "SDL_windowsshape.h"
27 #include "SDL_system.h"
28 #include "SDL_syswm.h"
29 #include "SDL_timer.h"
30 #include "SDL_vkeys.h"
31 #include "SDL_hints.h"
32 #include "../../events/SDL_events_c.h"
33 #include "../../events/SDL_touch_c.h"
34 #include "../../events/scancodes_windows.h"
35 #include "SDL_hints.h"
37 /* Dropfile support */
40 /* For GET_X_LPARAM, GET_Y_LPARAM. */
43 /* #define WMMSG_DEBUG */
49 /* Masks for processing the windows KEYDOWN and KEYUP messages */
50 #define REPEATED_KEYMASK (1<<30)
51 #define EXTENDED_KEYMASK (1<<24)
53 #define VK_ENTER 10 /* Keypad Enter ... no VKEY defined? */
54 #ifndef VK_OEM_NEC_EQUAL
55 #define VK_OEM_NEC_EQUAL 0x92
58 /* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */
59 #ifndef WM_XBUTTONDOWN
60 #define WM_XBUTTONDOWN 0x020B
63 #define WM_XBUTTONUP 0x020C
65 #ifndef GET_XBUTTON_WPARAM
66 #define GET_XBUTTON_WPARAM(w) (HIWORD(w))
69 #define WM_INPUT 0x00ff
72 #define WM_TOUCH 0x0240
74 #ifndef WM_MOUSEHWHEEL
75 #define WM_MOUSEHWHEEL 0x020E
77 #ifndef WM_POINTERUPDATE
78 #define WM_POINTERUPDATE 0x0245
81 #define WM_UNICHAR 0x0109
85 VKeytoScancodeFallback(WPARAM vkey)
88 case VK_LEFT: return SDL_SCANCODE_LEFT;
89 case VK_UP: return SDL_SCANCODE_UP;
90 case VK_RIGHT: return SDL_SCANCODE_RIGHT;
91 case VK_DOWN: return SDL_SCANCODE_DOWN;
93 default: return SDL_SCANCODE_UNKNOWN;
98 VKeytoScancode(WPARAM vkey)
101 case VK_MODECHANGE: return SDL_SCANCODE_MODE;
102 case VK_SELECT: return SDL_SCANCODE_SELECT;
103 case VK_EXECUTE: return SDL_SCANCODE_EXECUTE;
104 case VK_HELP: return SDL_SCANCODE_HELP;
105 case VK_PAUSE: return SDL_SCANCODE_PAUSE;
106 case VK_NUMLOCK: return SDL_SCANCODE_NUMLOCKCLEAR;
108 case VK_F13: return SDL_SCANCODE_F13;
109 case VK_F14: return SDL_SCANCODE_F14;
110 case VK_F15: return SDL_SCANCODE_F15;
111 case VK_F16: return SDL_SCANCODE_F16;
112 case VK_F17: return SDL_SCANCODE_F17;
113 case VK_F18: return SDL_SCANCODE_F18;
114 case VK_F19: return SDL_SCANCODE_F19;
115 case VK_F20: return SDL_SCANCODE_F20;
116 case VK_F21: return SDL_SCANCODE_F21;
117 case VK_F22: return SDL_SCANCODE_F22;
118 case VK_F23: return SDL_SCANCODE_F23;
119 case VK_F24: return SDL_SCANCODE_F24;
121 case VK_OEM_NEC_EQUAL: return SDL_SCANCODE_KP_EQUALS;
122 case VK_BROWSER_BACK: return SDL_SCANCODE_AC_BACK;
123 case VK_BROWSER_FORWARD: return SDL_SCANCODE_AC_FORWARD;
124 case VK_BROWSER_REFRESH: return SDL_SCANCODE_AC_REFRESH;
125 case VK_BROWSER_STOP: return SDL_SCANCODE_AC_STOP;
126 case VK_BROWSER_SEARCH: return SDL_SCANCODE_AC_SEARCH;
127 case VK_BROWSER_FAVORITES: return SDL_SCANCODE_AC_BOOKMARKS;
128 case VK_BROWSER_HOME: return SDL_SCANCODE_AC_HOME;
129 case VK_VOLUME_MUTE: return SDL_SCANCODE_AUDIOMUTE;
130 case VK_VOLUME_DOWN: return SDL_SCANCODE_VOLUMEDOWN;
131 case VK_VOLUME_UP: return SDL_SCANCODE_VOLUMEUP;
133 case VK_MEDIA_NEXT_TRACK: return SDL_SCANCODE_AUDIONEXT;
134 case VK_MEDIA_PREV_TRACK: return SDL_SCANCODE_AUDIOPREV;
135 case VK_MEDIA_STOP: return SDL_SCANCODE_AUDIOSTOP;
136 case VK_MEDIA_PLAY_PAUSE: return SDL_SCANCODE_AUDIOPLAY;
137 case VK_LAUNCH_MAIL: return SDL_SCANCODE_MAIL;
138 case VK_LAUNCH_MEDIA_SELECT: return SDL_SCANCODE_MEDIASELECT;
140 case VK_OEM_102: return SDL_SCANCODE_NONUSBACKSLASH;
142 case VK_ATTN: return SDL_SCANCODE_SYSREQ;
143 case VK_CRSEL: return SDL_SCANCODE_CRSEL;
144 case VK_EXSEL: return SDL_SCANCODE_EXSEL;
145 case VK_OEM_CLEAR: return SDL_SCANCODE_CLEAR;
147 case VK_LAUNCH_APP1: return SDL_SCANCODE_APP1;
148 case VK_LAUNCH_APP2: return SDL_SCANCODE_APP2;
150 default: return SDL_SCANCODE_UNKNOWN;
155 WindowsScanCodeToSDLScanCode(LPARAM lParam, WPARAM wParam)
158 int nScanCode = (lParam >> 16) & 0xFF;
159 SDL_bool bIsExtended = (lParam & (1 << 24)) != 0;
161 code = VKeytoScancode(wParam);
163 if (code == SDL_SCANCODE_UNKNOWN && nScanCode <= 127) {
164 code = windows_scancode_table[nScanCode];
168 case SDL_SCANCODE_RETURN:
169 code = SDL_SCANCODE_KP_ENTER;
171 case SDL_SCANCODE_LALT:
172 code = SDL_SCANCODE_RALT;
174 case SDL_SCANCODE_LCTRL:
175 code = SDL_SCANCODE_RCTRL;
177 case SDL_SCANCODE_SLASH:
178 code = SDL_SCANCODE_KP_DIVIDE;
180 case SDL_SCANCODE_CAPSLOCK:
181 code = SDL_SCANCODE_KP_PLUS;
188 case SDL_SCANCODE_HOME:
189 code = SDL_SCANCODE_KP_7;
191 case SDL_SCANCODE_UP:
192 code = SDL_SCANCODE_KP_8;
194 case SDL_SCANCODE_PAGEUP:
195 code = SDL_SCANCODE_KP_9;
197 case SDL_SCANCODE_LEFT:
198 code = SDL_SCANCODE_KP_4;
200 case SDL_SCANCODE_RIGHT:
201 code = SDL_SCANCODE_KP_6;
203 case SDL_SCANCODE_END:
204 code = SDL_SCANCODE_KP_1;
206 case SDL_SCANCODE_DOWN:
207 code = SDL_SCANCODE_KP_2;
209 case SDL_SCANCODE_PAGEDOWN:
210 code = SDL_SCANCODE_KP_3;
212 case SDL_SCANCODE_INSERT:
213 code = SDL_SCANCODE_KP_0;
215 case SDL_SCANCODE_DELETE:
216 code = SDL_SCANCODE_KP_PERIOD;
218 case SDL_SCANCODE_PRINTSCREEN:
219 code = SDL_SCANCODE_KP_MULTIPLY;
227 /* The on-screen keyboard can generate VK_LEFT and VK_RIGHT events without a scancode
228 * value set, however we cannot simply map these in VKeytoScancode() or we will be
229 * incorrectly handling the arrow keys on the number pad when NumLock is disabled
230 * (which also generate VK_LEFT, VK_RIGHT, etc in that scenario). Instead, we'll only
231 * map them if none of the above special number pad mappings applied. */
232 if (code == SDL_SCANCODE_UNKNOWN) {
233 code = VKeytoScancodeFallback(wParam);
240 WIN_ShouldIgnoreFocusClick()
242 return !SDL_GetHintBoolean(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, SDL_FALSE);
246 WIN_CheckWParamMouseButton(SDL_bool bwParamMousePressed, Uint32 mouseFlags, SDL_bool bSwapButtons, SDL_WindowData *data, Uint8 button, SDL_MouseID mouseID)
249 if (button == SDL_BUTTON_LEFT) {
250 button = SDL_BUTTON_RIGHT;
252 else if (button == SDL_BUTTON_RIGHT) {
253 button = SDL_BUTTON_LEFT;
257 if (data->focus_click_pending & SDL_BUTTON(button)) {
258 /* Ignore the button click for activation */
259 if (!bwParamMousePressed) {
260 data->focus_click_pending &= ~SDL_BUTTON(button);
261 WIN_UpdateClipCursor(data->window);
263 if (WIN_ShouldIgnoreFocusClick()) {
268 if (bwParamMousePressed && !(mouseFlags & SDL_BUTTON(button))) {
269 SDL_SendMouseButton(data->window, mouseID, SDL_PRESSED, button);
270 } else if (!bwParamMousePressed && (mouseFlags & SDL_BUTTON(button))) {
271 SDL_SendMouseButton(data->window, mouseID, SDL_RELEASED, button);
276 * Some windows systems fail to send a WM_LBUTTONDOWN sometimes, but each mouse move contains the current button state also
277 * so this function reconciles our view of the world with the current buttons reported by windows
280 WIN_CheckWParamMouseButtons(WPARAM wParam, SDL_WindowData *data, SDL_MouseID mouseID)
282 if (wParam != data->mouse_button_flags) {
283 Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL);
285 /* WM_LBUTTONDOWN and friends handle button swapping for us. No need to check SM_SWAPBUTTON here. */
286 WIN_CheckWParamMouseButton((wParam & MK_LBUTTON), mouseFlags, SDL_FALSE, data, SDL_BUTTON_LEFT, mouseID);
287 WIN_CheckWParamMouseButton((wParam & MK_MBUTTON), mouseFlags, SDL_FALSE, data, SDL_BUTTON_MIDDLE, mouseID);
288 WIN_CheckWParamMouseButton((wParam & MK_RBUTTON), mouseFlags, SDL_FALSE, data, SDL_BUTTON_RIGHT, mouseID);
289 WIN_CheckWParamMouseButton((wParam & MK_XBUTTON1), mouseFlags, SDL_FALSE, data, SDL_BUTTON_X1, mouseID);
290 WIN_CheckWParamMouseButton((wParam & MK_XBUTTON2), mouseFlags, SDL_FALSE, data, SDL_BUTTON_X2, mouseID);
292 data->mouse_button_flags = wParam;
297 WIN_CheckRawMouseButtons(ULONG rawButtons, SDL_WindowData *data)
299 if (rawButtons != data->mouse_button_flags) {
300 Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL);
301 SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
302 if ((rawButtons & RI_MOUSE_BUTTON_1_DOWN))
303 WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_1_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_LEFT, 0);
304 if ((rawButtons & RI_MOUSE_BUTTON_1_UP))
305 WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_1_UP), mouseFlags, swapButtons, data, SDL_BUTTON_LEFT, 0);
306 if ((rawButtons & RI_MOUSE_BUTTON_2_DOWN))
307 WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_2_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_RIGHT, 0);
308 if ((rawButtons & RI_MOUSE_BUTTON_2_UP))
309 WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_2_UP), mouseFlags, swapButtons, data, SDL_BUTTON_RIGHT, 0);
310 if ((rawButtons & RI_MOUSE_BUTTON_3_DOWN))
311 WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_3_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_MIDDLE, 0);
312 if ((rawButtons & RI_MOUSE_BUTTON_3_UP))
313 WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_3_UP), mouseFlags, swapButtons, data, SDL_BUTTON_MIDDLE, 0);
314 if ((rawButtons & RI_MOUSE_BUTTON_4_DOWN))
315 WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_4_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_X1, 0);
316 if ((rawButtons & RI_MOUSE_BUTTON_4_UP))
317 WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_4_UP), mouseFlags, swapButtons, data, SDL_BUTTON_X1, 0);
318 if ((rawButtons & RI_MOUSE_BUTTON_5_DOWN))
319 WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_5_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_X2, 0);
320 if ((rawButtons & RI_MOUSE_BUTTON_5_UP))
321 WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_5_UP), mouseFlags, swapButtons, data, SDL_BUTTON_X2, 0);
322 data->mouse_button_flags = rawButtons;
327 WIN_CheckAsyncMouseRelease(SDL_WindowData *data)
331 SDL_bool swapButtons;
333 /* mouse buttons may have changed state here, we need to resync them,
334 but we will get a WM_MOUSEMOVE right away which will fix things up if in non raw mode also
336 mouseFlags = SDL_GetMouseState(NULL, NULL);
337 swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
339 keyState = GetAsyncKeyState(VK_LBUTTON);
340 if (!(keyState & 0x8000)) {
341 WIN_CheckWParamMouseButton(SDL_FALSE, mouseFlags, swapButtons, data, SDL_BUTTON_LEFT, 0);
343 keyState = GetAsyncKeyState(VK_RBUTTON);
344 if (!(keyState & 0x8000)) {
345 WIN_CheckWParamMouseButton(SDL_FALSE, mouseFlags, swapButtons, data, SDL_BUTTON_RIGHT, 0);
347 keyState = GetAsyncKeyState(VK_MBUTTON);
348 if (!(keyState & 0x8000)) {
349 WIN_CheckWParamMouseButton(SDL_FALSE, mouseFlags, swapButtons, data, SDL_BUTTON_MIDDLE, 0);
351 keyState = GetAsyncKeyState(VK_XBUTTON1);
352 if (!(keyState & 0x8000)) {
353 WIN_CheckWParamMouseButton(SDL_FALSE, mouseFlags, swapButtons, data, SDL_BUTTON_X1, 0);
355 keyState = GetAsyncKeyState(VK_XBUTTON2);
356 if (!(keyState & 0x8000)) {
357 WIN_CheckWParamMouseButton(SDL_FALSE, mouseFlags, swapButtons, data, SDL_BUTTON_X2, 0);
359 data->mouse_button_flags = 0;
363 WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text)
365 if (codepoint <= 0x7F) {
366 text[0] = (char) codepoint;
368 } else if (codepoint <= 0x7FF) {
369 text[0] = 0xC0 | (char) ((codepoint >> 6) & 0x1F);
370 text[1] = 0x80 | (char) (codepoint & 0x3F);
372 } else if (codepoint <= 0xFFFF) {
373 text[0] = 0xE0 | (char) ((codepoint >> 12) & 0x0F);
374 text[1] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
375 text[2] = 0x80 | (char) (codepoint & 0x3F);
377 } else if (codepoint <= 0x10FFFF) {
378 text[0] = 0xF0 | (char) ((codepoint >> 18) & 0x0F);
379 text[1] = 0x80 | (char) ((codepoint >> 12) & 0x3F);
380 text[2] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
381 text[3] = 0x80 | (char) (codepoint & 0x3F);
390 ShouldGenerateWindowCloseOnAltF4(void)
392 return !SDL_GetHintBoolean(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, SDL_FALSE);
395 /* Win10 "Fall Creators Update" introduced the bug that SetCursorPos() (as used by SDL_WarpMouseInWindow())
396 doesn't reliably generate WM_MOUSEMOVE events anymore (see #3931) which breaks relative mouse mode via warping.
397 This is used to implement a workaround.. */
398 static SDL_bool isWin10FCUorNewer = SDL_FALSE;
400 /* We want to generate mouse events from mouse and pen, and touch events from touchscreens */
401 #define MI_WP_SIGNATURE 0xFF515700
402 #define MI_WP_SIGNATURE_MASK 0xFFFFFF00
403 #define IsTouchEvent(dw) ((dw) & MI_WP_SIGNATURE_MASK) == MI_WP_SIGNATURE
407 SDL_MOUSE_EVENT_SOURCE_UNKNOWN,
408 SDL_MOUSE_EVENT_SOURCE_MOUSE,
409 SDL_MOUSE_EVENT_SOURCE_TOUCH,
410 SDL_MOUSE_EVENT_SOURCE_PEN,
411 } SDL_MOUSE_EVENT_SOURCE;
413 static SDL_MOUSE_EVENT_SOURCE GetMouseMessageSource()
415 LPARAM extrainfo = GetMessageExtraInfo();
416 /* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
417 /* Versions below Vista will set the low 7 bits to the Mouse ID and don't use bit 7:
418 Check bits 8-32 for the signature (which will indicate a Tablet PC Pen or Touch Device).
419 Only check bit 7 when Vista and up(Cleared=Pen, Set=Touch(which we need to filter out)),
420 when the signature is set. The Mouse ID will be zero for an actual mouse. */
421 if (IsTouchEvent(extrainfo)) {
422 if (extrainfo & 0x80) {
423 return SDL_MOUSE_EVENT_SOURCE_TOUCH;
425 return SDL_MOUSE_EVENT_SOURCE_PEN;
428 return SDL_MOUSE_EVENT_SOURCE_MOUSE;
432 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
434 SDL_WindowData *data;
435 LRESULT returnCode = -1;
437 /* Send a SDL_SYSWMEVENT if the application wants them */
438 if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
441 SDL_VERSION(&wmmsg.version);
442 wmmsg.subsystem = SDL_SYSWM_WINDOWS;
443 wmmsg.msg.win.hwnd = hwnd;
444 wmmsg.msg.win.msg = msg;
445 wmmsg.msg.win.wParam = wParam;
446 wmmsg.msg.win.lParam = lParam;
447 SDL_SendSysWMEvent(&wmmsg);
450 /* Get the window data for the window */
451 data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
453 return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
459 if (msg > MAX_WMMSG) {
460 SDL_snprintf(message, sizeof(message), "Received windows message: %p UNKNOWN (%d) -- 0x%X, 0x%X\n", hwnd, msg, wParam, lParam);
462 SDL_snprintf(message, sizeof(message), "Received windows message: %p %s -- 0x%X, 0x%X\n", hwnd, wmtab[msg], wParam, lParam);
464 OutputDebugStringA(message);
466 #endif /* WMMSG_DEBUG */
468 if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
476 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
478 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
485 /* Don't immediately clip the cursor in case we're clicking minimize/maximize buttons */
486 data->skip_update_clipcursor = SDL_TRUE;
495 minimized = HIWORD(wParam);
496 if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
497 /* Don't mark the window as shown if it's activated before being shown */
498 if (!IsWindowVisible(hwnd)) {
501 if (LOWORD(wParam) == WA_CLICKACTIVE) {
502 SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
503 if (GetAsyncKeyState(VK_LBUTTON)) {
504 data->focus_click_pending |= !swapButtons ? SDL_BUTTON_LMASK : SDL_BUTTON_RMASK;
506 if (GetAsyncKeyState(VK_RBUTTON)) {
507 data->focus_click_pending |= !swapButtons ? SDL_BUTTON_RMASK : SDL_BUTTON_LMASK;
509 if (GetAsyncKeyState(VK_MBUTTON)) {
510 data->focus_click_pending |= SDL_BUTTON_MMASK;
512 if (GetAsyncKeyState(VK_XBUTTON1)) {
513 data->focus_click_pending |= SDL_BUTTON_X1MASK;
515 if (GetAsyncKeyState(VK_XBUTTON2)) {
516 data->focus_click_pending |= SDL_BUTTON_X2MASK;
520 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
521 if (SDL_GetKeyboardFocus() != data->window) {
522 SDL_SetKeyboardFocus(data->window);
525 GetCursorPos(&cursorPos);
526 ScreenToClient(hwnd, &cursorPos);
527 SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
529 WIN_CheckAsyncMouseRelease(data);
530 WIN_UpdateClipCursor(data->window);
533 * FIXME: Update keyboard state
535 WIN_CheckClipboardUpdate(data->videodata);
537 SDL_ToggleModState(KMOD_CAPS, (GetKeyState(VK_CAPITAL) & 0x0001) != 0);
538 SDL_ToggleModState(KMOD_NUM, (GetKeyState(VK_NUMLOCK) & 0x0001) != 0);
542 data->in_window_deactivation = SDL_TRUE;
544 if (SDL_GetKeyboardFocus() == data->window) {
545 SDL_SetKeyboardFocus(NULL);
549 if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect)) == 0) {
551 SDL_zero(data->cursor_clipped_rect);
554 data->in_window_deactivation = SDL_FALSE;
560 case WM_POINTERUPDATE:
562 data->last_pointer_update = lParam;
568 SDL_Mouse *mouse = SDL_GetMouse();
569 if (!mouse->relative_mode || mouse->relative_mode_warp) {
570 /* Only generate mouse events for real mouse */
571 if (GetMouseMessageSource() != SDL_MOUSE_EVENT_SOURCE_TOUCH &&
572 lParam != data->last_pointer_update) {
573 SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
574 if (isWin10FCUorNewer && mouse->relative_mode_warp) {
575 /* To work around #3931, Win10 bug introduced in Fall Creators Update, where
576 SetCursorPos() (SDL_WarpMouseInWindow()) doesn't reliably generate mouse events anymore,
577 after each windows mouse event generate a fake event for the middle of the window
578 if relative_mode_warp is used */
579 int center_x = 0, center_y = 0;
580 SDL_GetWindowSize(data->window, ¢er_x, ¢er_y);
583 SDL_SendMouseMotion(data->window, 0, 0, center_x, center_y);
587 /* We still need to update focus */
588 SDL_SetMouseFocus(data->window);
591 /* don't break here, fall through to check the wParam like the button presses */
597 case WM_LBUTTONDBLCLK:
599 case WM_RBUTTONDBLCLK:
601 case WM_MBUTTONDBLCLK:
603 case WM_XBUTTONDBLCLK:
605 SDL_Mouse *mouse = SDL_GetMouse();
606 if (!mouse->relative_mode || mouse->relative_mode_warp) {
607 if (GetMouseMessageSource() != SDL_MOUSE_EVENT_SOURCE_TOUCH &&
608 lParam != data->last_pointer_update) {
609 WIN_CheckWParamMouseButtons(wParam, data, 0);
617 SDL_Mouse *mouse = SDL_GetMouse();
618 HRAWINPUT hRawInput = (HRAWINPUT)lParam;
620 UINT size = sizeof(inp);
621 const SDL_bool isRelative = mouse->relative_mode || mouse->relative_mode_warp;
622 const SDL_bool isCapture = ((data->window->flags & SDL_WINDOW_MOUSE_CAPTURE) != 0);
624 if (!isRelative || mouse->focus != data->window) {
630 GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
632 /* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
633 if (inp.header.dwType == RIM_TYPEMOUSE) {
634 if (GetMouseMessageSource() == SDL_MOUSE_EVENT_SOURCE_TOUCH ||
635 (GetMessageExtraInfo() & 0x82) == 0x82) {
639 RAWMOUSE* rawmouse = &inp.data.mouse;
641 if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
642 SDL_SendMouseMotion(data->window, 0, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY);
643 } else if (rawmouse->lLastX || rawmouse->lLastY) {
644 /* synthesize relative moves from the abs position */
645 static SDL_Point lastMousePoint;
646 SDL_bool virtual_desktop = (rawmouse->usFlags & MOUSE_VIRTUAL_DESKTOP) ? SDL_TRUE : SDL_FALSE;
647 int w = GetSystemMetrics(virtual_desktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN);
648 int h = GetSystemMetrics(virtual_desktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN);
649 int x = (int)(((float)rawmouse->lLastX / 65535.0f) * w);
650 int y = (int)(((float)rawmouse->lLastY / 65535.0f) * h);
652 if (lastMousePoint.x == 0 && lastMousePoint.y == 0) {
653 lastMousePoint.x = x;
654 lastMousePoint.y = y;
657 SDL_SendMouseMotion(data->window, 0, 1, (int)(x-lastMousePoint.x), (int)(y-lastMousePoint.y));
659 lastMousePoint.x = x;
660 lastMousePoint.y = y;
662 WIN_CheckRawMouseButtons(rawmouse->usButtonFlags, data);
663 } else if (isCapture) {
664 /* we check for where Windows thinks the system cursor lives in this case, so we don't really lose mouse accel, etc. */
670 currentHnd = WindowFromPoint(pt);
671 ScreenToClient(hwnd, &pt);
672 GetClientRect(hwnd, &hwndRect);
674 /* if in the window, WM_MOUSEMOVE, etc, will cover it. */
675 if(currentHnd != hwnd || pt.x < 0 || pt.y < 0 || pt.x > hwndRect.right || pt.y > hwndRect.right) {
676 SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
678 SDL_SendMouseMotion(data->window, 0, 0, (int)pt.x, (int)pt.y);
679 SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT);
680 SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT);
681 SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
682 SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
683 SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
686 SDL_assert(0 && "Shouldn't happen");
695 short amount = GET_WHEEL_DELTA_WPARAM(wParam);
696 float fAmount = (float) amount / WHEEL_DELTA;
697 if (msg == WM_MOUSEWHEEL)
698 SDL_SendMouseWheel(data->window, 0, 0.0f, fAmount, SDL_MOUSEWHEEL_NORMAL);
700 SDL_SendMouseWheel(data->window, 0, fAmount, 0.0f, SDL_MOUSEWHEEL_NORMAL);
706 if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
707 if (!IsIconic(hwnd)) {
710 GetCursorPos(&cursorPos);
711 ScreenToClient(hwnd, &cursorPos);
712 mouse = SDL_GetMouse();
713 if (!mouse->was_touch_mouse_events) { /* we're not a touch handler causing a mouse leave? */
714 SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
715 } else { /* touch handling? */
716 mouse->was_touch_mouse_events = SDL_FALSE; /* not anymore */
717 if (mouse->touch_mouse_events) { /* convert touch to mouse events */
718 SDL_SendMouseMotion(data->window, SDL_TOUCH_MOUSEID, 0, cursorPos.x, cursorPos.y);
719 } else { /* normal handling */
720 SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
724 SDL_SetMouseFocus(NULL);
728 #endif /* WM_MOUSELEAVE */
733 SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
734 const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
736 /* Detect relevant keyboard shortcuts */
737 if (keyboardState[SDL_SCANCODE_LALT] == SDL_PRESSED || keyboardState[SDL_SCANCODE_RALT] == SDL_PRESSED) {
738 /* ALT+F4: Close window */
739 if (code == SDL_SCANCODE_F4 && ShouldGenerateWindowCloseOnAltF4()) {
740 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
744 if (code != SDL_SCANCODE_UNKNOWN) {
745 SDL_SendKeyboardKey(SDL_PRESSED, code);
755 SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
756 const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
758 if (code != SDL_SCANCODE_UNKNOWN) {
759 if (code == SDL_SCANCODE_PRINTSCREEN &&
760 keyboardState[code] == SDL_RELEASED) {
761 SDL_SendKeyboardKey(SDL_PRESSED, code);
763 SDL_SendKeyboardKey(SDL_RELEASED, code);
770 if (wParam == UNICODE_NOCHAR) {
774 /* otherwise fall through to below */
778 if (WIN_ConvertUTF32toUTF8((UINT32)wParam, text)) {
779 SDL_SendKeyboardText(text);
785 #ifdef WM_INPUTLANGCHANGE
786 case WM_INPUTLANGCHANGE:
789 SDL_SendKeymapChangedEvent();
793 #endif /* WM_INPUTLANGCHANGE */
795 case WM_NCLBUTTONDOWN:
797 data->in_title_click = SDL_TRUE;
801 case WM_CAPTURECHANGED:
803 data->in_title_click = SDL_FALSE;
805 /* The mouse may have been released during a modal loop */
806 WIN_CheckAsyncMouseRelease(data);
810 #ifdef WM_GETMINMAXINFO
811 case WM_GETMINMAXINFO:
819 BOOL constrain_max_size;
821 if (SDL_IsShapedWindow(data->window)) {
822 Win32_ResizeWindowShape(data->window);
825 /* If this is an expected size change, allow it */
826 if (data->expected_resize) {
830 /* Get the current position of our window */
831 GetWindowRect(hwnd, &size);
835 /* Calculate current size of our window */
836 SDL_GetWindowSize(data->window, &w, &h);
837 SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
838 SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
840 /* Store in min_w and min_h difference between current size and minimal
841 size so we don't need to call AdjustWindowRectEx twice */
844 if (max_w && max_h) {
847 constrain_max_size = TRUE;
849 constrain_max_size = FALSE;
852 if (!(SDL_GetWindowFlags(data->window) & SDL_WINDOW_BORDERLESS)) {
853 LONG style = GetWindowLong(hwnd, GWL_STYLE);
854 /* DJM - according to the docs for GetMenu(), the
855 return value is undefined if hwnd is a child window.
856 Apparently it's too difficult for MS to check
857 inside their function, so I have to do it here.
859 BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
865 AdjustWindowRectEx(&size, style, menu, 0);
866 w = size.right - size.left;
867 h = size.bottom - size.top;
870 /* Fix our size to the current size */
871 info = (MINMAXINFO *) lParam;
872 if (SDL_GetWindowFlags(data->window) & SDL_WINDOW_RESIZABLE) {
873 info->ptMinTrackSize.x = w + min_w;
874 info->ptMinTrackSize.y = h + min_h;
875 if (constrain_max_size) {
876 info->ptMaxTrackSize.x = w + max_w;
877 info->ptMaxTrackSize.y = h + max_h;
880 info->ptMaxSize.x = w;
881 info->ptMaxSize.y = h;
882 info->ptMaxPosition.x = x;
883 info->ptMaxPosition.y = y;
884 info->ptMinTrackSize.x = w;
885 info->ptMinTrackSize.y = h;
886 info->ptMaxTrackSize.x = w;
887 info->ptMaxTrackSize.y = h;
892 #endif /* WM_GETMINMAXINFO */
894 case WM_WINDOWPOSCHANGING:
896 if (data->expected_resize) {
901 case WM_WINDOWPOSCHANGED:
907 if (data->initializing || data->in_border_change) {
911 if (!GetClientRect(hwnd, &rect) || IsRectEmpty(&rect)) {
914 ClientToScreen(hwnd, (LPPOINT) & rect);
915 ClientToScreen(hwnd, (LPPOINT) & rect + 1);
917 WIN_UpdateClipCursor(data->window);
921 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
923 w = rect.right - rect.left;
924 h = rect.bottom - rect.top;
925 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w, h);
927 /* Forces a WM_PAINT event */
928 InvalidateRect(hwnd, NULL, FALSE);
936 SDL_SendWindowEvent(data->window,
937 SDL_WINDOWEVENT_RESTORED, 0, 0);
938 SDL_SendWindowEvent(data->window,
939 SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
942 SDL_SendWindowEvent(data->window,
943 SDL_WINDOWEVENT_MINIMIZED, 0, 0);
946 SDL_SendWindowEvent(data->window,
947 SDL_WINDOWEVENT_RESTORED, 0, 0);
957 hittest = LOWORD(lParam);
958 if (hittest == HTCLIENT) {
959 SetCursor(SDL_cursor);
961 } else if (!g_WindowFrameUsableWhileCursorHidden && !SDL_cursor) {
968 /* We were occluded, refresh our display */
972 if (GetUpdateRect(hwnd, &rect, FALSE)) {
973 ValidateRect(hwnd, NULL);
974 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
980 /* We'll do our own drawing, prevent flicker */
988 if ((wParam & 0xFFF0) == SC_KEYMENU) {
992 #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
993 /* Don't start the screensaver or blank the monitor in fullscreen apps */
994 if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
995 (wParam & 0xFFF0) == SC_MONITORPOWER) {
996 if (SDL_GetVideoDevice()->suspend_screensaver) {
1000 #endif /* System has screensaver support */
1006 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
1012 if (data->videodata->GetTouchInputInfo && data->videodata->CloseTouchInputHandle) {
1013 UINT i, num_inputs = LOWORD(wParam);
1015 PTOUCHINPUT inputs = SDL_small_alloc(TOUCHINPUT, num_inputs, &isstack);
1016 if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
1020 if (!GetClientRect(hwnd, &rect) ||
1021 (rect.right == rect.left && rect.bottom == rect.top)) {
1023 SDL_small_free(inputs, isstack);
1027 ClientToScreen(hwnd, (LPPOINT) & rect);
1028 ClientToScreen(hwnd, (LPPOINT) & rect + 1);
1034 for (i = 0; i < num_inputs; ++i) {
1035 PTOUCHINPUT input = &inputs[i];
1037 const SDL_TouchID touchId = (SDL_TouchID)((size_t)input->hSource);
1039 /* TODO: Can we use GetRawInputDeviceInfo and HID info to
1040 determine if this is a direct or indirect touch device?
1042 if (SDL_AddTouch(touchId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) {
1046 /* Get the normalized coordinates for the window */
1047 x = (float)(input->x - rect.left)/(rect.right - rect.left);
1048 y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
1050 if (input->dwFlags & TOUCHEVENTF_DOWN) {
1051 SDL_SendTouch(touchId, input->dwID, data->window, SDL_TRUE, x, y, 1.0f);
1053 if (input->dwFlags & TOUCHEVENTF_MOVE) {
1054 SDL_SendTouchMotion(touchId, input->dwID, data->window, x, y, 1.0f);
1056 if (input->dwFlags & TOUCHEVENTF_UP) {
1057 SDL_SendTouch(touchId, input->dwID, data->window, SDL_FALSE, x, y, 1.0f);
1061 SDL_small_free(inputs, isstack);
1063 data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
1071 HDROP drop = (HDROP) wParam;
1072 UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
1073 for (i = 0; i < count; ++i) {
1075 UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
1076 LPTSTR buffer = SDL_small_alloc(TCHAR, size, &isstack);
1078 if (DragQueryFile(drop, i, buffer, size)) {
1079 char *file = WIN_StringToUTF8(buffer);
1080 SDL_SendDropFile(data->window, file);
1083 SDL_small_free(buffer, isstack);
1086 SDL_SendDropComplete(data->window);
1092 case WM_DISPLAYCHANGE:
1094 // Reacquire displays if any were added or removed
1095 WIN_RefreshDisplays(SDL_GetVideoDevice());
1101 Uint32 window_flags = SDL_GetWindowFlags(data->window);
1102 if (wParam == TRUE && (window_flags & SDL_WINDOW_BORDERLESS) && !(window_flags & SDL_WINDOW_FULLSCREEN)) {
1103 /* When borderless, need to tell windows that the size of the non-client area is 0 */
1104 if (!(window_flags & SDL_WINDOW_RESIZABLE)) {
1106 NCCALCSIZE_PARAMS *params = (NCCALCSIZE_PARAMS *)lParam;
1107 w = data->window->windowed.w;
1108 h = data->window->windowed.h;
1109 params->rgrc[0].right = params->rgrc[0].left + w;
1110 params->rgrc[0].bottom = params->rgrc[0].top + h;
1119 SDL_Window *window = data->window;
1120 if (window->hit_test) {
1121 POINT winpoint = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
1122 if (ScreenToClient(hwnd, &winpoint)) {
1123 const SDL_Point point = { (int) winpoint.x, (int) winpoint.y };
1124 const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
1126 #define POST_HIT_TEST(ret) { SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return ret; }
1127 case SDL_HITTEST_DRAGGABLE: POST_HIT_TEST(HTCAPTION);
1128 case SDL_HITTEST_RESIZE_TOPLEFT: POST_HIT_TEST(HTTOPLEFT);
1129 case SDL_HITTEST_RESIZE_TOP: POST_HIT_TEST(HTTOP);
1130 case SDL_HITTEST_RESIZE_TOPRIGHT: POST_HIT_TEST(HTTOPRIGHT);
1131 case SDL_HITTEST_RESIZE_RIGHT: POST_HIT_TEST(HTRIGHT);
1132 case SDL_HITTEST_RESIZE_BOTTOMRIGHT: POST_HIT_TEST(HTBOTTOMRIGHT);
1133 case SDL_HITTEST_RESIZE_BOTTOM: POST_HIT_TEST(HTBOTTOM);
1134 case SDL_HITTEST_RESIZE_BOTTOMLEFT: POST_HIT_TEST(HTBOTTOMLEFT);
1135 case SDL_HITTEST_RESIZE_LEFT: POST_HIT_TEST(HTLEFT);
1136 #undef POST_HIT_TEST
1137 case SDL_HITTEST_NORMAL: return HTCLIENT;
1140 /* If we didn't return, this will call DefWindowProc below. */
1146 /* If there's a window proc, assume it's going to handle messages */
1147 if (data->wndproc) {
1148 return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
1149 } else if (returnCode >= 0) {
1152 return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
1156 static void WIN_UpdateClipCursorForWindows()
1158 SDL_VideoDevice *_this = SDL_GetVideoDevice();
1160 Uint32 now = SDL_GetTicks();
1161 const Uint32 CLIPCURSOR_UPDATE_INTERVAL_MS = 3000;
1164 for (window = _this->windows; window; window = window->next) {
1165 SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
1167 if (data->skip_update_clipcursor) {
1168 data->skip_update_clipcursor = SDL_FALSE;
1169 WIN_UpdateClipCursor(window);
1170 } else if ((now - data->last_updated_clipcursor) >= CLIPCURSOR_UPDATE_INTERVAL_MS) {
1171 WIN_UpdateClipCursor(window);
1178 /* A message hook called before TranslateMessage() */
1179 static SDL_WindowsMessageHook g_WindowsMessageHook = NULL;
1180 static void *g_WindowsMessageHookData = NULL;
1182 void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata)
1184 g_WindowsMessageHook = callback;
1185 g_WindowsMessageHookData = userdata;
1189 WIN_PumpEvents(_THIS)
1191 const Uint8 *keystate;
1193 DWORD start_ticks = GetTickCount();
1194 int new_messages = 0;
1196 if (g_WindowsEnableMessageLoop) {
1197 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1198 if (g_WindowsMessageHook) {
1199 g_WindowsMessageHook(g_WindowsMessageHookData, msg.hwnd, msg.message, msg.wParam, msg.lParam);
1202 /* Always translate the message in case it's a non-SDL window (e.g. with Qt integration) */
1203 TranslateMessage(&msg);
1204 DispatchMessage(&msg);
1206 /* Make sure we don't busy loop here forever if there are lots of events coming in */
1207 if (SDL_TICKS_PASSED(msg.time, start_ticks)) {
1208 /* We might get a few new messages generated by the Steam overlay or other application hooks
1209 In this case those messages will be processed before any pending input, so we want to continue after those messages.
1210 (thanks to Peter Deayton for his investigation here)
1212 const int MAX_NEW_MESSAGES = 3;
1214 if (new_messages > MAX_NEW_MESSAGES) {
1221 /* Windows loses a shift KEYUP event when you have both pressed at once and let go of one.
1222 You won't get a KEYUP until both are released, and that keyup will only be for the second
1223 key you released. Take heroic measures and check the keystate as of the last handled event,
1224 and if we think a key is pressed when Windows doesn't, unstick it in SDL's state. */
1225 keystate = SDL_GetKeyboardState(NULL);
1226 if ((keystate[SDL_SCANCODE_LSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
1227 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
1229 if ((keystate[SDL_SCANCODE_RSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
1230 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RSHIFT);
1233 /* Update the clipping rect in case someone else has stolen it */
1234 WIN_UpdateClipCursorForWindows();
1237 /* to work around #3931, a bug introduced in Win10 Fall Creators Update (build nr. 16299)
1238 we need to detect the windows version. this struct and the function below does that.
1239 usually this struct and the corresponding function (RtlGetVersion) are in <Ntddk.h>
1240 but here we just load it dynamically */
1241 struct SDL_WIN_OSVERSIONINFOW {
1242 ULONG dwOSVersionInfoSize;
1243 ULONG dwMajorVersion;
1244 ULONG dwMinorVersion;
1245 ULONG dwBuildNumber;
1247 WCHAR szCSDVersion[128];
1251 IsWin10FCUorNewer(void)
1253 HMODULE handle = GetModuleHandle(TEXT("ntdll.dll"));
1255 typedef LONG(WINAPI* RtlGetVersionPtr)(struct SDL_WIN_OSVERSIONINFOW*);
1256 RtlGetVersionPtr getVersionPtr = (RtlGetVersionPtr)GetProcAddress(handle, "RtlGetVersion");
1257 if (getVersionPtr != NULL) {
1258 struct SDL_WIN_OSVERSIONINFOW info;
1260 info.dwOSVersionInfoSize = sizeof(info);
1261 if (getVersionPtr(&info) == 0) { /* STATUS_SUCCESS == 0 */
1262 if ((info.dwMajorVersion == 10 && info.dwMinorVersion == 0 && info.dwBuildNumber >= 16299) ||
1263 (info.dwMajorVersion == 10 && info.dwMinorVersion > 0) ||
1264 (info.dwMajorVersion > 10))
1274 static int app_registered = 0;
1275 LPTSTR SDL_Appname = NULL;
1276 Uint32 SDL_Appstyle = 0;
1277 HINSTANCE SDL_Instance = NULL;
1279 /* Register the class for this application */
1281 SDL_RegisterApp(char *name, Uint32 style, void *hInst)
1285 TCHAR path[MAX_PATH];
1287 /* Only do this once... */
1288 if (app_registered) {
1292 if (!name && !SDL_Appname) {
1294 #if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
1295 SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
1297 SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
1301 SDL_Appname = WIN_UTF8ToString(name);
1302 SDL_Appstyle = style;
1303 SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
1306 /* Register the application class */
1307 wcex.cbSize = sizeof(WNDCLASSEX);
1308 wcex.hCursor = NULL;
1310 wcex.hIconSm = NULL;
1311 wcex.lpszMenuName = NULL;
1312 wcex.lpszClassName = SDL_Appname;
1313 wcex.style = SDL_Appstyle;
1314 wcex.hbrBackground = NULL;
1315 wcex.lpfnWndProc = WIN_WindowProc;
1316 wcex.hInstance = SDL_Instance;
1317 wcex.cbClsExtra = 0;
1318 wcex.cbWndExtra = 0;
1320 hint = SDL_GetHint(SDL_HINT_WINDOWS_INTRESOURCE_ICON);
1321 if (hint && *hint) {
1322 wcex.hIcon = LoadIcon(SDL_Instance, MAKEINTRESOURCE(SDL_atoi(hint)));
1324 hint = SDL_GetHint(SDL_HINT_WINDOWS_INTRESOURCE_ICON_SMALL);
1325 if (hint && *hint) {
1326 wcex.hIconSm = LoadIcon(SDL_Instance, MAKEINTRESOURCE(SDL_atoi(hint)));
1329 /* Use the first icon as a default icon, like in the Explorer */
1330 GetModuleFileName(SDL_Instance, path, MAX_PATH);
1331 ExtractIconEx(path, 0, &wcex.hIcon, &wcex.hIconSm, 1);
1334 if (!RegisterClassEx(&wcex)) {
1335 return SDL_SetError("Couldn't register application class");
1338 isWin10FCUorNewer = IsWin10FCUorNewer();
1344 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
1350 /* SDL_RegisterApp might not have been called before */
1351 if (!app_registered) {
1355 if (app_registered == 0) {
1356 /* Check for any registered window classes. */
1357 if (GetClassInfoEx(SDL_Instance, SDL_Appname, &wcex)) {
1358 UnregisterClass(SDL_Appname, SDL_Instance);
1359 if (wcex.hIcon) DestroyIcon(wcex.hIcon);
1360 if (wcex.hIconSm) DestroyIcon(wcex.hIconSm);
1362 SDL_free(SDL_Appname);
1367 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
1369 /* vi: set ts=4 sw=4 expandtab: */