SDL 2.0
SDL_windowsevents.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 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 SDL_VIDEO_DRIVER_WINDOWS
24
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_assert.h"
36#include "SDL_hints.h"
37
38/* Dropfile support */
39#include <shellapi.h>
40
41/* For GET_X_LPARAM, GET_Y_LPARAM. */
42#include <windowsx.h>
43
44/* #define WMMSG_DEBUG */
45#ifdef WMMSG_DEBUG
46#include <stdio.h>
47#include "wmmsg.h"
48#endif
49
50/* For processing mouse WM_*BUTTON* and WM_MOUSEMOVE message-data from GetMessageExtraInfo() */
51#define MOUSEEVENTF_FROMTOUCH 0xFF515700
52
53/* Masks for processing the windows KEYDOWN and KEYUP messages */
54#define REPEATED_KEYMASK (1<<30)
55#define EXTENDED_KEYMASK (1<<24)
56
57#define VK_ENTER 10 /* Keypad Enter ... no VKEY defined? */
58#ifndef VK_OEM_NEC_EQUAL
59#define VK_OEM_NEC_EQUAL 0x92
60#endif
61
62/* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */
63#ifndef WM_XBUTTONDOWN
64#define WM_XBUTTONDOWN 0x020B
65#endif
66#ifndef WM_XBUTTONUP
67#define WM_XBUTTONUP 0x020C
68#endif
69#ifndef GET_XBUTTON_WPARAM
70#define GET_XBUTTON_WPARAM(w) (HIWORD(w))
71#endif
72#ifndef WM_INPUT
73#define WM_INPUT 0x00ff
74#endif
75#ifndef WM_TOUCH
76#define WM_TOUCH 0x0240
77#endif
78#ifndef WM_MOUSEHWHEEL
79#define WM_MOUSEHWHEEL 0x020E
80#endif
81#ifndef WM_UNICHAR
82#define WM_UNICHAR 0x0109
83#endif
84
85static SDL_Scancode
86VKeytoScancode(WPARAM vkey)
87{
88 switch (vkey) {
89/* Windows generates this virtual keycode for Keypad 5 when NumLock is off.
90 case VK_CLEAR: return SDL_SCANCODE_CLEAR;
91*/
92 case VK_MODECHANGE: return SDL_SCANCODE_MODE;
93 case VK_SELECT: return SDL_SCANCODE_SELECT;
94 case VK_EXECUTE: return SDL_SCANCODE_EXECUTE;
95 case VK_HELP: return SDL_SCANCODE_HELP;
96 case VK_PAUSE: return SDL_SCANCODE_PAUSE;
97 case VK_NUMLOCK: return SDL_SCANCODE_NUMLOCKCLEAR;
98
99 case VK_F13: return SDL_SCANCODE_F13;
100 case VK_F14: return SDL_SCANCODE_F14;
101 case VK_F15: return SDL_SCANCODE_F15;
102 case VK_F16: return SDL_SCANCODE_F16;
103 case VK_F17: return SDL_SCANCODE_F17;
104 case VK_F18: return SDL_SCANCODE_F18;
105 case VK_F19: return SDL_SCANCODE_F19;
106 case VK_F20: return SDL_SCANCODE_F20;
107 case VK_F21: return SDL_SCANCODE_F21;
108 case VK_F22: return SDL_SCANCODE_F22;
109 case VK_F23: return SDL_SCANCODE_F23;
110 case VK_F24: return SDL_SCANCODE_F24;
111
112 case VK_OEM_NEC_EQUAL: return SDL_SCANCODE_KP_EQUALS;
113 case VK_BROWSER_BACK: return SDL_SCANCODE_AC_BACK;
114 case VK_BROWSER_FORWARD: return SDL_SCANCODE_AC_FORWARD;
115 case VK_BROWSER_REFRESH: return SDL_SCANCODE_AC_REFRESH;
116 case VK_BROWSER_STOP: return SDL_SCANCODE_AC_STOP;
117 case VK_BROWSER_SEARCH: return SDL_SCANCODE_AC_SEARCH;
118 case VK_BROWSER_FAVORITES: return SDL_SCANCODE_AC_BOOKMARKS;
119 case VK_BROWSER_HOME: return SDL_SCANCODE_AC_HOME;
120 case VK_VOLUME_MUTE: return SDL_SCANCODE_AUDIOMUTE;
121 case VK_VOLUME_DOWN: return SDL_SCANCODE_VOLUMEDOWN;
122 case VK_VOLUME_UP: return SDL_SCANCODE_VOLUMEUP;
123
124 case VK_MEDIA_NEXT_TRACK: return SDL_SCANCODE_AUDIONEXT;
125 case VK_MEDIA_PREV_TRACK: return SDL_SCANCODE_AUDIOPREV;
126 case VK_MEDIA_STOP: return SDL_SCANCODE_AUDIOSTOP;
127 case VK_MEDIA_PLAY_PAUSE: return SDL_SCANCODE_AUDIOPLAY;
128 case VK_LAUNCH_MAIL: return SDL_SCANCODE_MAIL;
129 case VK_LAUNCH_MEDIA_SELECT: return SDL_SCANCODE_MEDIASELECT;
130
132
133 case VK_ATTN: return SDL_SCANCODE_SYSREQ;
134 case VK_CRSEL: return SDL_SCANCODE_CRSEL;
135 case VK_EXSEL: return SDL_SCANCODE_EXSEL;
136 case VK_OEM_CLEAR: return SDL_SCANCODE_CLEAR;
137
138 case VK_LAUNCH_APP1: return SDL_SCANCODE_APP1;
139 case VK_LAUNCH_APP2: return SDL_SCANCODE_APP2;
140
141 default: return SDL_SCANCODE_UNKNOWN;
142 }
143}
144
145static SDL_Scancode
146WindowsScanCodeToSDLScanCode(LPARAM lParam, WPARAM wParam)
147{
148 SDL_Scancode code;
149 int nScanCode = (lParam >> 16) & 0xFF;
150 SDL_bool bIsExtended = (lParam & (1 << 24)) != 0;
151
152 code = VKeytoScancode(wParam);
153
154 if (code == SDL_SCANCODE_UNKNOWN && nScanCode <= 127) {
155 code = windows_scancode_table[nScanCode];
156
157 if (bIsExtended) {
158 switch (code) {
161 break;
163 code = SDL_SCANCODE_RALT;
164 break;
166 code = SDL_SCANCODE_RCTRL;
167 break;
170 break;
173 break;
174 default:
175 break;
176 }
177 } else {
178 switch (code) {
180 code = SDL_SCANCODE_KP_7;
181 break;
182 case SDL_SCANCODE_UP:
183 code = SDL_SCANCODE_KP_8;
184 break;
186 code = SDL_SCANCODE_KP_9;
187 break;
189 code = SDL_SCANCODE_KP_4;
190 break;
192 code = SDL_SCANCODE_KP_6;
193 break;
194 case SDL_SCANCODE_END:
195 code = SDL_SCANCODE_KP_1;
196 break;
198 code = SDL_SCANCODE_KP_2;
199 break;
201 code = SDL_SCANCODE_KP_3;
202 break;
204 code = SDL_SCANCODE_KP_0;
205 break;
208 break;
211 break;
212 default:
213 break;
214 }
215 }
216 }
217 return code;
218}
219
220static SDL_bool
221WIN_ShouldIgnoreFocusClick()
222{
224}
225
226static void
227WIN_CheckWParamMouseButton(SDL_bool bwParamMousePressed, SDL_bool bSDLMousePressed, SDL_WindowData *data, Uint8 button, SDL_MouseID mouseID)
228{
229 if (data->focus_click_pending & SDL_BUTTON(button)) {
230 /* Ignore the button click for activation */
231 if (!bwParamMousePressed) {
232 data->focus_click_pending &= ~SDL_BUTTON(button);
233 WIN_UpdateClipCursor(data->window);
234 }
235 if (WIN_ShouldIgnoreFocusClick()) {
236 return;
237 }
238 }
239
240 if (bwParamMousePressed && !bSDLMousePressed) {
241 SDL_SendMouseButton(data->window, mouseID, SDL_PRESSED, button);
242 } else if (!bwParamMousePressed && bSDLMousePressed) {
243 SDL_SendMouseButton(data->window, mouseID, SDL_RELEASED, button);
244 }
245}
246
247/*
248* Some windows systems fail to send a WM_LBUTTONDOWN sometimes, but each mouse move contains the current button state also
249* so this funciton reconciles our view of the world with the current buttons reported by windows
250*/
251static void
252WIN_CheckWParamMouseButtons(WPARAM wParam, SDL_WindowData *data, SDL_MouseID mouseID)
253{
254 if (wParam != data->mouse_button_flags) {
255 Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL);
256 WIN_CheckWParamMouseButton((wParam & MK_LBUTTON), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, mouseID);
257 WIN_CheckWParamMouseButton((wParam & MK_MBUTTON), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, mouseID);
258 WIN_CheckWParamMouseButton((wParam & MK_RBUTTON), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, mouseID);
259 WIN_CheckWParamMouseButton((wParam & MK_XBUTTON1), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, mouseID);
260 WIN_CheckWParamMouseButton((wParam & MK_XBUTTON2), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, mouseID);
261 data->mouse_button_flags = wParam;
262 }
263}
264
265
266static void
267WIN_CheckRawMouseButtons(ULONG rawButtons, SDL_WindowData *data)
268{
269 if (rawButtons != data->mouse_button_flags) {
270 Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL);
271 if ((rawButtons & RI_MOUSE_BUTTON_1_DOWN))
272 WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_1_DOWN), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0);
273 if ((rawButtons & RI_MOUSE_BUTTON_1_UP))
274 WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_1_UP), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0);
275 if ((rawButtons & RI_MOUSE_BUTTON_2_DOWN))
276 WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_2_DOWN), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0);
277 if ((rawButtons & RI_MOUSE_BUTTON_2_UP))
278 WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_2_UP), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0);
279 if ((rawButtons & RI_MOUSE_BUTTON_3_DOWN))
280 WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_3_DOWN), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0);
281 if ((rawButtons & RI_MOUSE_BUTTON_3_UP))
282 WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_3_UP), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0);
283 if ((rawButtons & RI_MOUSE_BUTTON_4_DOWN))
284 WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_4_DOWN), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0);
285 if ((rawButtons & RI_MOUSE_BUTTON_4_UP))
286 WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_4_UP), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0);
287 if ((rawButtons & RI_MOUSE_BUTTON_5_DOWN))
288 WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_5_DOWN), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0);
289 if ((rawButtons & RI_MOUSE_BUTTON_5_UP))
290 WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_5_UP), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0);
291 data->mouse_button_flags = rawButtons;
292 }
293}
294
295static void
296WIN_CheckAsyncMouseRelease(SDL_WindowData *data)
297{
298 Uint32 mouseFlags;
299 SHORT keyState;
300
301 /* mouse buttons may have changed state here, we need to resync them,
302 but we will get a WM_MOUSEMOVE right away which will fix things up if in non raw mode also
303 */
304 mouseFlags = SDL_GetMouseState(NULL, NULL);
305
306 keyState = GetAsyncKeyState(VK_LBUTTON);
307 if (!(keyState & 0x8000)) {
308 WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0);
309 }
310 keyState = GetAsyncKeyState(VK_RBUTTON);
311 if (!(keyState & 0x8000)) {
312 WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0);
313 }
314 keyState = GetAsyncKeyState(VK_MBUTTON);
315 if (!(keyState & 0x8000)) {
316 WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0);
317 }
318 keyState = GetAsyncKeyState(VK_XBUTTON1);
319 if (!(keyState & 0x8000)) {
320 WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0);
321 }
322 keyState = GetAsyncKeyState(VK_XBUTTON2);
323 if (!(keyState & 0x8000)) {
324 WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0);
325 }
326 data->mouse_button_flags = 0;
327}
328
329static BOOL
330WIN_ConvertUTF32toUTF8(UINT32 codepoint, char * text)
331{
332 if (codepoint <= 0x7F) {
333 text[0] = (char) codepoint;
334 text[1] = '\0';
335 } else if (codepoint <= 0x7FF) {
336 text[0] = 0xC0 | (char) ((codepoint >> 6) & 0x1F);
337 text[1] = 0x80 | (char) (codepoint & 0x3F);
338 text[2] = '\0';
339 } else if (codepoint <= 0xFFFF) {
340 text[0] = 0xE0 | (char) ((codepoint >> 12) & 0x0F);
341 text[1] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
342 text[2] = 0x80 | (char) (codepoint & 0x3F);
343 text[3] = '\0';
344 } else if (codepoint <= 0x10FFFF) {
345 text[0] = 0xF0 | (char) ((codepoint >> 18) & 0x0F);
346 text[1] = 0x80 | (char) ((codepoint >> 12) & 0x3F);
347 text[2] = 0x80 | (char) ((codepoint >> 6) & 0x3F);
348 text[3] = 0x80 | (char) (codepoint & 0x3F);
349 text[4] = '\0';
350 } else {
351 return SDL_FALSE;
352 }
353 return SDL_TRUE;
354}
355
356static SDL_bool
357ShouldGenerateWindowCloseOnAltF4(void)
358{
360}
361
362static SDL_bool isVistaOrNewer = SDL_FALSE;
363/* Win10 "Fall Creators Update" introduced the bug that SetCursorPos() (as used by SDL_WarpMouseInWindow())
364 doesn't reliably generate WM_MOUSEMOVE events anymore (see #3931) which breaks relative mouse mode via warping.
365 This is used to implement a workaround.. */
366static SDL_bool isWin10FCUorNewer = SDL_FALSE;
367
368/* Checks a mouse or raw packet for touch indication.
369 returns: 0 for not touch input, 1 for touch input.
370*/
371static LPARAM
372GetMessageExtraInfoAndCheckMousePacketTouch(int *checkTouch) {
373 LPARAM extrainfo = GetMessageExtraInfo();
374 /* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
375 /* Versions below Vista will set the low 7 bits to the Mouse ID and don't use bit 7:
376 Check bits 8-32 for the signature (which will indicate a Tablet PC Pen or Touch Device).
377 Only check bit 7 when Vista and up(Cleared=Pen, Set=Touch(which we need to filter out)),
378 when the signature is set. The Mouse ID will be zero for an actual mouse. */
379 *checkTouch = (!(((extrainfo & 0x7F) && (isVistaOrNewer ? (extrainfo & 0x80) : 1)) || ((extrainfo & 0xFFFFFF00) == 0xFF515700)));
380 return extrainfo;
381}
382
383LRESULT CALLBACK
384WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
385{
386 int checkTouch = -1; /* Default to -1 for not yet loaded */
387 LPARAM extrainfo; /* The extra info when checkTouch >= 0. */
389 LRESULT returnCode = -1;
390
391 /* Send a SDL_SYSWMEVENT if the application wants them */
393 SDL_SysWMmsg wmmsg;
394
395 SDL_VERSION(&wmmsg.version);
397 wmmsg.msg.win.hwnd = hwnd;
398 wmmsg.msg.win.msg = msg;
399 wmmsg.msg.win.wParam = wParam;
400 wmmsg.msg.win.lParam = lParam;
401 SDL_SendSysWMEvent(&wmmsg);
402 }
403
404 /* Get the window data for the window */
405 data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
406 if (!data) {
407 return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
408 }
409
410#ifdef WMMSG_DEBUG
411 {
412 char message[1024];
413 if (msg > MAX_WMMSG) {
414 SDL_snprintf(message, sizeof(message), "Received windows message: %p UNKNOWN (%d) -- 0x%X, 0x%X\n", hwnd, msg, wParam, lParam);
415 } else {
416 SDL_snprintf(message, sizeof(message), "Received windows message: %p %s -- 0x%X, 0x%X\n", hwnd, wmtab[msg], wParam, lParam);
417 }
418 OutputDebugStringA(message);
419 }
420#endif /* WMMSG_DEBUG */
421
422 if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
423 return 0;
424
425 switch (msg) {
426
427 case WM_SHOWWINDOW:
428 {
429 if (wParam) {
431 } else {
433 }
434 }
435 break;
436
437 case WM_NCACTIVATE:
438 {
439 /* Don't immediately clip the cursor in case we're clicking minimize/maximize buttons */
440 data->skip_update_clipcursor = SDL_TRUE;
441 }
442 break;
443
444 case WM_ACTIVATE:
445 {
446 POINT cursorPos;
447 BOOL minimized;
448
449 minimized = HIWORD(wParam);
450 if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
451 /* Don't mark the window as shown if it's activated before being shown */
452 if (!IsWindowVisible(hwnd)) {
453 break;
454 }
455 if (LOWORD(wParam) == WA_CLICKACTIVE) {
456 if (GetAsyncKeyState(VK_LBUTTON)) {
457 data->focus_click_pending |= SDL_BUTTON_LMASK;
458 }
459 if (GetAsyncKeyState(VK_RBUTTON)) {
460 data->focus_click_pending |= SDL_BUTTON_RMASK;
461 }
462 if (GetAsyncKeyState(VK_MBUTTON)) {
463 data->focus_click_pending |= SDL_BUTTON_MMASK;
464 }
465 if (GetAsyncKeyState(VK_XBUTTON1)) {
466 data->focus_click_pending |= SDL_BUTTON_X1MASK;
467 }
468 if (GetAsyncKeyState(VK_XBUTTON2)) {
469 data->focus_click_pending |= SDL_BUTTON_X2MASK;
470 }
471 }
472
474 if (SDL_GetKeyboardFocus() != data->window) {
475 SDL_SetKeyboardFocus(data->window);
476 }
477
478 GetCursorPos(&cursorPos);
479 ScreenToClient(hwnd, &cursorPos);
480 SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
481
482 WIN_CheckAsyncMouseRelease(data);
483
484 /*
485 * FIXME: Update keyboard state
486 */
487 WIN_CheckClipboardUpdate(data->videodata);
488
489 SDL_ToggleModState(KMOD_CAPS, (GetKeyState(VK_CAPITAL) & 0x0001) != 0);
490 SDL_ToggleModState(KMOD_NUM, (GetKeyState(VK_NUMLOCK) & 0x0001) != 0);
491 } else {
492 RECT rect;
493
494 data->in_window_deactivation = SDL_TRUE;
495
496 if (SDL_GetKeyboardFocus() == data->window) {
499 }
500
501 if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect) == 0)) {
502 ClipCursor(NULL);
503 SDL_zero(data->cursor_clipped_rect);
504 }
505
506 data->in_window_deactivation = SDL_FALSE;
507 }
508 }
509 returnCode = 0;
510 break;
511
512 case WM_MOUSEMOVE:
513 {
514 SDL_Mouse *mouse = SDL_GetMouse();
515 extrainfo = GetMessageExtraInfoAndCheckMousePacketTouch(&checkTouch); /* load */
516 if (!mouse->relative_mode || mouse->relative_mode_warp) {
517 /* Only generate mouse events for real mouse */
518 if (((extrainfo & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) && checkTouch) {
519 SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
520 if (isWin10FCUorNewer && mouse->relative_mode_warp) {
521 /* To work around #3931, Win10 bug introduced in Fall Creators Update, where
522 SetCursorPos() (SDL_WarpMouseInWindow()) doesn't reliably generate mouse events anymore,
523 after each windows mouse event generate a fake event for the middle of the window
524 if relative_mode_warp is used */
525 int center_x = 0, center_y = 0;
526 SDL_GetWindowSize(data->window, &center_x, &center_y);
527 center_x /= 2;
528 center_y /= 2;
529 SDL_SendMouseMotion(data->window, 0, 0, center_x, center_y);
530 }
531 }
532 }
533 }
534 /* don't break here, fall through to check the wParam like the button presses */
535 case WM_LBUTTONUP:
536 case WM_RBUTTONUP:
537 case WM_MBUTTONUP:
538 case WM_XBUTTONUP:
539 case WM_LBUTTONDOWN:
540 case WM_LBUTTONDBLCLK:
541 case WM_RBUTTONDOWN:
542 case WM_RBUTTONDBLCLK:
543 case WM_MBUTTONDOWN:
544 case WM_MBUTTONDBLCLK:
545 case WM_XBUTTONDOWN:
546 case WM_XBUTTONDBLCLK:
547 {
548 SDL_Mouse *mouse = SDL_GetMouse();
549 if (checkTouch < 0) {
550 extrainfo = GetMessageExtraInfoAndCheckMousePacketTouch(&checkTouch);
551 }
552 if (!mouse->relative_mode || mouse->relative_mode_warp) {
553 if (((extrainfo & MOUSEEVENTF_FROMTOUCH) != MOUSEEVENTF_FROMTOUCH) && checkTouch) {
554 WIN_CheckWParamMouseButtons(wParam, data, 0);
555 }
556 }
557 }
558 break;
559
560 case WM_INPUT:
561 {
562 SDL_Mouse *mouse = SDL_GetMouse();
563 HRAWINPUT hRawInput = (HRAWINPUT)lParam;
564 RAWINPUT inp;
565 UINT size = sizeof(inp);
566 const SDL_bool isRelative = mouse->relative_mode || mouse->relative_mode_warp;
567 const SDL_bool isCapture = ((data->window->flags & SDL_WINDOW_MOUSE_CAPTURE) != 0);
568
569 if (!isRelative || mouse->focus != data->window) {
570 if (!isCapture) {
571 break;
572 }
573 }
574
575 GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
576
577 /* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
578 if (inp.header.dwType == RIM_TYPEMOUSE) {
579 extrainfo = GetMessageExtraInfoAndCheckMousePacketTouch(&checkTouch);
580 if (!checkTouch)
581 break;
582 if (isRelative) {
583 RAWMOUSE* rawmouse = &inp.data.mouse;
584
585 if ((rawmouse->usFlags & 0x01) == MOUSE_MOVE_RELATIVE) {
586 SDL_SendMouseMotion(data->window, 0, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY);
587 } else {
588 /* synthesize relative moves from the abs position */
589 static SDL_Point initialMousePoint;
590 if (initialMousePoint.x == 0 && initialMousePoint.y == 0) {
591 initialMousePoint.x = rawmouse->lLastX;
592 initialMousePoint.y = rawmouse->lLastY;
593 }
594
595 SDL_SendMouseMotion(data->window, 0, 1, (int)(rawmouse->lLastX-initialMousePoint.x), (int)(rawmouse->lLastY-initialMousePoint.y));
596
597 initialMousePoint.x = rawmouse->lLastX;
598 initialMousePoint.y = rawmouse->lLastY;
599 }
600 WIN_CheckRawMouseButtons(rawmouse->usButtonFlags, data);
601 } else if (isCapture) {
602 /* we check for where Windows thinks the system cursor lives in this case, so we don't really lose mouse accel, etc. */
603 POINT pt;
604 RECT hwndRect;
605 HWND currentHnd;
606
607 GetCursorPos(&pt);
608 currentHnd = WindowFromPoint(pt);
609 ScreenToClient(hwnd, &pt);
610 GetClientRect(hwnd, &hwndRect);
611
612 /* if in the window, WM_MOUSEMOVE, etc, will cover it. */
613 if(currentHnd != hwnd || pt.x < 0 || pt.y < 0 || pt.x > hwndRect.right || pt.y > hwndRect.right) {
614 SDL_SendMouseMotion(data->window, 0, 0, (int)pt.x, (int)pt.y);
615 SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT);
616 SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT);
617 SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
618 SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
619 SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
620 }
621 } else {
622 SDL_assert(0 && "Shouldn't happen");
623 }
624 }
625 }
626 break;
627
628 case WM_MOUSEWHEEL:
629 case WM_MOUSEHWHEEL:
630 {
631 short amount = GET_WHEEL_DELTA_WPARAM(wParam);
632 float fAmount = (float) amount / WHEEL_DELTA;
633 if (msg == WM_MOUSEWHEEL)
634 SDL_SendMouseWheel(data->window, 0, 0.0f, fAmount, SDL_MOUSEWHEEL_NORMAL);
635 else
636 SDL_SendMouseWheel(data->window, 0, fAmount, 0.0f, SDL_MOUSEWHEEL_NORMAL);
637 }
638 break;
639
640#ifdef WM_MOUSELEAVE
641 case WM_MOUSELEAVE:
642 if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
643 if (!IsIconic(hwnd)) {
644 SDL_Mouse *mouse;
645 POINT cursorPos;
646 GetCursorPos(&cursorPos);
647 ScreenToClient(hwnd, &cursorPos);
648 mouse = SDL_GetMouse();
649 if (!mouse->was_touch_mouse_events) { /* we're not a touch handler causing a mouse leave? */
650 SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
651 } else { /* touch handling? */
652 mouse->was_touch_mouse_events = SDL_FALSE; /* not anymore */
653 if (mouse->touch_mouse_events) { /* convert touch to mouse events */
654 SDL_SendMouseMotion(data->window, SDL_TOUCH_MOUSEID, 0, cursorPos.x, cursorPos.y);
655 } else { /* normal handling */
656 SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
657 }
658 }
659 }
661 }
662 returnCode = 0;
663 break;
664#endif /* WM_MOUSELEAVE */
665
666 case WM_KEYDOWN:
667 case WM_SYSKEYDOWN:
668 {
669 SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
670 const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
671
672 /* Detect relevant keyboard shortcuts */
673 if (keyboardState[SDL_SCANCODE_LALT] == SDL_PRESSED || keyboardState[SDL_SCANCODE_RALT] == SDL_PRESSED) {
674 /* ALT+F4: Close window */
675 if (code == SDL_SCANCODE_F4 && ShouldGenerateWindowCloseOnAltF4()) {
677 }
678 }
679
680 if (code != SDL_SCANCODE_UNKNOWN) {
682 }
683 }
684
685 returnCode = 0;
686 break;
687
688 case WM_SYSKEYUP:
689 case WM_KEYUP:
690 {
691 SDL_Scancode code = WindowsScanCodeToSDLScanCode(lParam, wParam);
692 const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
693
694 if (code != SDL_SCANCODE_UNKNOWN) {
695 if (code == SDL_SCANCODE_PRINTSCREEN &&
696 keyboardState[code] == SDL_RELEASED) {
698 }
700 }
701 }
702 returnCode = 0;
703 break;
704
705 case WM_UNICHAR:
706 if (wParam == UNICODE_NOCHAR) {
707 returnCode = 1;
708 break;
709 }
710 /* otherwise fall through to below */
711 case WM_CHAR:
712 {
713 char text[5];
714 if (WIN_ConvertUTF32toUTF8((UINT32)wParam, text)) {
716 }
717 }
718 returnCode = 0;
719 break;
720
721#ifdef WM_INPUTLANGCHANGE
722 case WM_INPUTLANGCHANGE:
723 {
726 }
727 returnCode = 1;
728 break;
729#endif /* WM_INPUTLANGCHANGE */
730
731 case WM_NCLBUTTONDOWN:
732 {
733 data->in_title_click = SDL_TRUE;
734 }
735 break;
736
737 case WM_CAPTURECHANGED:
738 {
739 data->in_title_click = SDL_FALSE;
740
741 /* The mouse may have been released during a modal loop */
742 WIN_CheckAsyncMouseRelease(data);
743 }
744 break;
745
746#ifdef WM_GETMINMAXINFO
747 case WM_GETMINMAXINFO:
748 {
749 MINMAXINFO *info;
750 RECT size;
751 int x, y;
752 int w, h;
753 int min_w, min_h;
754 int max_w, max_h;
755 BOOL constrain_max_size;
756
757 if (SDL_IsShapedWindow(data->window))
759
760 /* If this is an expected size change, allow it */
761 if (data->expected_resize) {
762 break;
763 }
764
765 /* Get the current position of our window */
766 GetWindowRect(hwnd, &size);
767 x = size.left;
768 y = size.top;
769
770 /* Calculate current size of our window */
771 SDL_GetWindowSize(data->window, &w, &h);
772 SDL_GetWindowMinimumSize(data->window, &min_w, &min_h);
773 SDL_GetWindowMaximumSize(data->window, &max_w, &max_h);
774
775 /* Store in min_w and min_h difference between current size and minimal
776 size so we don't need to call AdjustWindowRectEx twice */
777 min_w -= w;
778 min_h -= h;
779 if (max_w && max_h) {
780 max_w -= w;
781 max_h -= h;
782 constrain_max_size = TRUE;
783 } else {
784 constrain_max_size = FALSE;
785 }
786
788 LONG style = GetWindowLong(hwnd, GWL_STYLE);
789 /* DJM - according to the docs for GetMenu(), the
790 return value is undefined if hwnd is a child window.
791 Apparently it's too difficult for MS to check
792 inside their function, so I have to do it here.
793 */
794 BOOL menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
795 size.top = 0;
796 size.left = 0;
797 size.bottom = h;
798 size.right = w;
799
800 AdjustWindowRectEx(&size, style, menu, 0);
801 w = size.right - size.left;
802 h = size.bottom - size.top;
803 }
804
805 /* Fix our size to the current size */
806 info = (MINMAXINFO *) lParam;
808 info->ptMinTrackSize.x = w + min_w;
809 info->ptMinTrackSize.y = h + min_h;
810 if (constrain_max_size) {
811 info->ptMaxTrackSize.x = w + max_w;
812 info->ptMaxTrackSize.y = h + max_h;
813 }
814 } else {
815 info->ptMaxSize.x = w;
816 info->ptMaxSize.y = h;
817 info->ptMaxPosition.x = x;
818 info->ptMaxPosition.y = y;
819 info->ptMinTrackSize.x = w;
820 info->ptMinTrackSize.y = h;
821 info->ptMaxTrackSize.x = w;
822 info->ptMaxTrackSize.y = h;
823 }
824 }
825 returnCode = 0;
826 break;
827#endif /* WM_GETMINMAXINFO */
828
829 case WM_WINDOWPOSCHANGING:
830
831 if (data->expected_resize) {
832 returnCode = 0;
833 }
834 break;
835
836 case WM_WINDOWPOSCHANGED:
837 {
838 RECT rect;
839 int x, y;
840 int w, h;
841
842 if (data->initializing || data->in_border_change) {
843 break;
844 }
845
846 if (!GetClientRect(hwnd, &rect) || IsRectEmpty(&rect)) {
847 break;
848 }
849 ClientToScreen(hwnd, (LPPOINT) & rect);
850 ClientToScreen(hwnd, (LPPOINT) & rect + 1);
851
852 WIN_UpdateClipCursor(data->window);
853
854 x = rect.left;
855 y = rect.top;
857
858 w = rect.right - rect.left;
859 h = rect.bottom - rect.top;
861 h);
862
863 /* Forces a WM_PAINT event */
864 InvalidateRect(hwnd, NULL, FALSE);
865 }
866 break;
867
868 case WM_SIZE:
869 {
870 switch (wParam) {
871 case SIZE_MAXIMIZED:
876 break;
877 case SIZE_MINIMIZED:
880 break;
881 default:
884 break;
885 }
886 }
887 break;
888
889 case WM_SETCURSOR:
890 {
891 Uint16 hittest;
892
893 hittest = LOWORD(lParam);
894 if (hittest == HTCLIENT) {
895 SetCursor(SDL_cursor);
896 returnCode = TRUE;
898 SetCursor(NULL);
899 returnCode = TRUE;
900 }
901 }
902 break;
903
904 /* We were occluded, refresh our display */
905 case WM_PAINT:
906 {
907 RECT rect;
908 if (GetUpdateRect(hwnd, &rect, FALSE)) {
909 ValidateRect(hwnd, NULL);
911 0, 0);
912 }
913 }
914 returnCode = 0;
915 break;
916
917 /* We'll do our own drawing, prevent flicker */
918 case WM_ERASEBKGND:
919 {
920 }
921 return (1);
922
923 case WM_SYSCOMMAND:
924 {
925 if ((wParam & 0xFFF0) == SC_KEYMENU) {
926 return (0);
927 }
928
929#if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
930 /* Don't start the screensaver or blank the monitor in fullscreen apps */
931 if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
932 (wParam & 0xFFF0) == SC_MONITORPOWER) {
933 if (SDL_GetVideoDevice()->suspend_screensaver) {
934 return (0);
935 }
936 }
937#endif /* System has screensaver support */
938 }
939 break;
940
941 case WM_CLOSE:
942 {
944 }
945 returnCode = 0;
946 break;
947
948 case WM_TOUCH:
949 if (data->videodata->GetTouchInputInfo && data->videodata->CloseTouchInputHandle) {
950 UINT i, num_inputs = LOWORD(wParam);
951 SDL_bool isstack;
952 PTOUCHINPUT inputs = SDL_small_alloc(TOUCHINPUT, num_inputs, &isstack);
953 if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
954 RECT rect;
955 float x, y;
956
957 if (!GetClientRect(hwnd, &rect) ||
958 (rect.right == rect.left && rect.bottom == rect.top)) {
959 if (inputs) {
960 SDL_small_free(inputs, isstack);
961 }
962 break;
963 }
964 ClientToScreen(hwnd, (LPPOINT) & rect);
965 ClientToScreen(hwnd, (LPPOINT) & rect + 1);
966 rect.top *= 100;
967 rect.left *= 100;
968 rect.bottom *= 100;
969 rect.right *= 100;
970
971 for (i = 0; i < num_inputs; ++i) {
972 PTOUCHINPUT input = &inputs[i];
973
974 const SDL_TouchID touchId = (SDL_TouchID)((size_t)input->hSource);
975
976 /* TODO: Can we use GetRawInputDeviceInfo and HID info to
977 determine if this is a direct or indirect touch device?
978 */
979 if (SDL_AddTouch(touchId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) {
980 continue;
981 }
982
983 /* Get the normalized coordinates for the window */
984 x = (float)(input->x - rect.left)/(rect.right - rect.left);
985 y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
986
987 if (input->dwFlags & TOUCHEVENTF_DOWN) {
988 SDL_SendTouch(touchId, input->dwID, SDL_TRUE, x, y, 1.0f);
989 }
990 if (input->dwFlags & TOUCHEVENTF_MOVE) {
991 SDL_SendTouchMotion(touchId, input->dwID, x, y, 1.0f);
992 }
993 if (input->dwFlags & TOUCHEVENTF_UP) {
994 SDL_SendTouch(touchId, input->dwID, SDL_FALSE, x, y, 1.0f);
995 }
996 }
997 }
998 SDL_small_free(inputs, isstack);
999
1000 data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
1001 return 0;
1002 }
1003 break;
1004
1005 case WM_DROPFILES:
1006 {
1007 UINT i;
1008 HDROP drop = (HDROP) wParam;
1009 UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
1010 for (i = 0; i < count; ++i) {
1011 SDL_bool isstack;
1012 UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
1013 LPTSTR buffer = SDL_small_alloc(TCHAR, size, &isstack);
1014 if (buffer) {
1015 if (DragQueryFile(drop, i, buffer, size)) {
1016 char *file = WIN_StringToUTF8(buffer);
1017 SDL_SendDropFile(data->window, file);
1018 SDL_free(file);
1019 }
1020 SDL_small_free(buffer, isstack);
1021 }
1022 }
1023 SDL_SendDropComplete(data->window);
1024 DragFinish(drop);
1025 return 0;
1026 }
1027 break;
1028
1029 case WM_NCCALCSIZE:
1030 {
1031 Uint32 window_flags = SDL_GetWindowFlags(data->window);
1032 if (wParam == TRUE && (window_flags & SDL_WINDOW_BORDERLESS) && !(window_flags & SDL_WINDOW_FULLSCREEN)) {
1033 /* When borderless, need to tell windows that the size of the non-client area is 0 */
1034 if (!(window_flags & SDL_WINDOW_RESIZABLE)) {
1035 int w, h;
1036 NCCALCSIZE_PARAMS *params = (NCCALCSIZE_PARAMS *)lParam;
1037 w = data->window->windowed.w;
1038 h = data->window->windowed.h;
1039 params->rgrc[0].right = params->rgrc[0].left + w;
1040 params->rgrc[0].bottom = params->rgrc[0].top + h;
1041 }
1042 return 0;
1043 }
1044 }
1045 break;
1046
1047 case WM_NCHITTEST:
1048 {
1049 SDL_Window *window = data->window;
1050 if (window->hit_test) {
1051 POINT winpoint = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
1052 if (ScreenToClient(hwnd, &winpoint)) {
1053 const SDL_Point point = { (int) winpoint.x, (int) winpoint.y };
1054 const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
1055 switch (rc) {
1056 #define POST_HIT_TEST(ret) { SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIT_TEST, 0, 0); return ret; }
1057 case SDL_HITTEST_DRAGGABLE: POST_HIT_TEST(HTCAPTION);
1058 case SDL_HITTEST_RESIZE_TOPLEFT: POST_HIT_TEST(HTTOPLEFT);
1059 case SDL_HITTEST_RESIZE_TOP: POST_HIT_TEST(HTTOP);
1060 case SDL_HITTEST_RESIZE_TOPRIGHT: POST_HIT_TEST(HTTOPRIGHT);
1061 case SDL_HITTEST_RESIZE_RIGHT: POST_HIT_TEST(HTRIGHT);
1062 case SDL_HITTEST_RESIZE_BOTTOMRIGHT: POST_HIT_TEST(HTBOTTOMRIGHT);
1063 case SDL_HITTEST_RESIZE_BOTTOM: POST_HIT_TEST(HTBOTTOM);
1064 case SDL_HITTEST_RESIZE_BOTTOMLEFT: POST_HIT_TEST(HTBOTTOMLEFT);
1065 case SDL_HITTEST_RESIZE_LEFT: POST_HIT_TEST(HTLEFT);
1066 #undef POST_HIT_TEST
1067 case SDL_HITTEST_NORMAL: return HTCLIENT;
1068 }
1069 }
1070 /* If we didn't return, this will call DefWindowProc below. */
1071 }
1072 }
1073 break;
1074 }
1075
1076 /* If there's a window proc, assume it's going to handle messages */
1077 if (data->wndproc) {
1078 return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
1079 } else if (returnCode >= 0) {
1080 return returnCode;
1081 } else {
1082 return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
1083 }
1084}
1085
1086static void WIN_UpdateClipCursorForWindows()
1087{
1090
1091 if (_this) {
1092 for (window = _this->windows; window; window = window->next) {
1093 if (window->driverdata) {
1095 }
1096 }
1097 }
1098}
1099
1100/* A message hook called before TranslateMessage() */
1101static SDL_WindowsMessageHook g_WindowsMessageHook = NULL;
1102static void *g_WindowsMessageHookData = NULL;
1103
1105{
1106 g_WindowsMessageHook = callback;
1107 g_WindowsMessageHookData = userdata;
1108}
1109
1110void
1112{
1113 const Uint8 *keystate;
1114 MSG msg;
1115 DWORD start_ticks = GetTickCount();
1116
1118 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1119 if (g_WindowsMessageHook) {
1120 g_WindowsMessageHook(g_WindowsMessageHookData, msg.hwnd, msg.message, msg.wParam, msg.lParam);
1121 }
1122
1123 /* Always translate the message in case it's a non-SDL window (e.g. with Qt integration) */
1124 TranslateMessage(&msg);
1125 DispatchMessage(&msg);
1126
1127 /* Make sure we don't busy loop here forever if there are lots of events coming in */
1128 if (SDL_TICKS_PASSED(msg.time, start_ticks)) {
1129 break;
1130 }
1131 }
1132 }
1133
1134 /* Windows loses a shift KEYUP event when you have both pressed at once and let go of one.
1135 You won't get a KEYUP until both are released, and that keyup will only be for the second
1136 key you released. Take heroic measures and check the keystate as of the last handled event,
1137 and if we think a key is pressed when Windows doesn't, unstick it in SDL's state. */
1138 keystate = SDL_GetKeyboardState(NULL);
1139 if ((keystate[SDL_SCANCODE_LSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
1141 }
1142 if ((keystate[SDL_SCANCODE_RSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
1144 }
1145
1146 /* Update the clipping rect in case someone else has stolen it */
1147 WIN_UpdateClipCursorForWindows();
1148}
1149
1150/* to work around #3931, a bug introduced in Win10 Fall Creators Update (build nr. 16299)
1151 we need to detect the windows version. this struct and the function below does that.
1152 usually this struct and the corresponding function (RtlGetVersion) are in <Ntddk.h>
1153 but here we just load it dynamically */
1154struct SDL_WIN_OSVERSIONINFOW {
1155 ULONG dwOSVersionInfoSize;
1156 ULONG dwMajorVersion;
1157 ULONG dwMinorVersion;
1158 ULONG dwBuildNumber;
1159 ULONG dwPlatformId;
1160 WCHAR szCSDVersion[128];
1161};
1162
1163static SDL_bool
1164IsWinVistaOrNewer(void)
1165{
1166 DWORD version = GetVersion();
1167 DWORD major = (DWORD)(LOBYTE(LOWORD(version)));
1168 return (major >= 6)? SDL_TRUE : SDL_FALSE;
1169}
1170
1171static SDL_bool
1172IsWin10FCUorNewer(void)
1173{
1174 HMODULE handle = GetModuleHandleW(L"ntdll.dll");
1175 if (handle) {
1176 typedef LONG(WINAPI* RtlGetVersionPtr)(struct SDL_WIN_OSVERSIONINFOW*);
1177 RtlGetVersionPtr getVersionPtr = (RtlGetVersionPtr)GetProcAddress(handle, "RtlGetVersion");
1178 if (getVersionPtr != NULL) {
1179 struct SDL_WIN_OSVERSIONINFOW info;
1180 SDL_zero(info);
1181 info.dwOSVersionInfoSize = sizeof(info);
1182 if (getVersionPtr(&info) == 0) { /* STATUS_SUCCESS == 0 */
1183 if ((info.dwMajorVersion == 10 && info.dwMinorVersion == 0 && info.dwBuildNumber >= 16299) ||
1184 (info.dwMajorVersion == 10 && info.dwMinorVersion > 0) ||
1185 (info.dwMajorVersion > 10))
1186 {
1187 return SDL_TRUE;
1188 }
1189 }
1190 }
1191 }
1192 return SDL_FALSE;
1193}
1194
1195static int app_registered = 0;
1196LPTSTR SDL_Appname = NULL;
1198HINSTANCE SDL_Instance = NULL;
1199
1200/* Register the class for this application */
1201int
1202SDL_RegisterApp(char *name, Uint32 style, void *hInst)
1203{
1204 const char *hint;
1205 WNDCLASSEX wcex;
1206 TCHAR path[MAX_PATH];
1207
1208 /* Only do this once... */
1209 if (app_registered) {
1210 ++app_registered;
1211 return (0);
1212 }
1213 if (!name && !SDL_Appname) {
1214 name = "SDL_app";
1215#if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
1216 SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
1217#endif
1218 SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
1219 }
1220
1221 if (name) {
1223 SDL_Appstyle = style;
1224 SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
1225 }
1226
1227 /* Register the application class */
1228 wcex.cbSize = sizeof(WNDCLASSEX);
1229 wcex.hCursor = NULL;
1230 wcex.hIcon = NULL;
1231 wcex.hIconSm = NULL;
1232 wcex.lpszMenuName = NULL;
1233 wcex.lpszClassName = SDL_Appname;
1234 wcex.style = SDL_Appstyle;
1235 wcex.hbrBackground = NULL;
1236 wcex.lpfnWndProc = WIN_WindowProc;
1237 wcex.hInstance = SDL_Instance;
1238 wcex.cbClsExtra = 0;
1239 wcex.cbWndExtra = 0;
1240
1242 if (hint && *hint) {
1243 wcex.hIcon = LoadIcon(SDL_Instance, MAKEINTRESOURCE(SDL_atoi(hint)));
1244
1246 if (hint && *hint) {
1247 wcex.hIconSm = LoadIcon(SDL_Instance, MAKEINTRESOURCE(SDL_atoi(hint)));
1248 }
1249 } else {
1250 /* Use the first icon as a default icon, like in the Explorer */
1251 GetModuleFileName(SDL_Instance, path, MAX_PATH);
1252 ExtractIconEx(path, 0, &wcex.hIcon, &wcex.hIconSm, 1);
1253 }
1254
1255 if (!RegisterClassEx(&wcex)) {
1256 return SDL_SetError("Couldn't register application class");
1257 }
1258
1259 isVistaOrNewer = IsWinVistaOrNewer();
1260 isWin10FCUorNewer = IsWin10FCUorNewer();
1261
1262 app_registered = 1;
1263 return 0;
1264}
1265
1266/* Unregisters the windowclass registered in SDL_RegisterApp above. */
1267void
1269{
1270 WNDCLASSEX wcex;
1271
1272 /* SDL_RegisterApp might not have been called before */
1273 if (!app_registered) {
1274 return;
1275 }
1276 --app_registered;
1277 if (app_registered == 0) {
1278 /* Check for any registered window classes. */
1279 if (GetClassInfoEx(SDL_Instance, SDL_Appname, &wcex)) {
1280 UnregisterClass(SDL_Appname, SDL_Instance);
1281 if (wcex.hIcon) DestroyIcon(wcex.hIcon);
1282 if (wcex.hIconSm) DestroyIcon(wcex.hIconSm);
1283 }
1285 SDL_Appname = NULL;
1286 }
1287}
1288
1289#endif /* SDL_VIDEO_DRIVER_WINDOWS */
1290
1291/* vi: set ts=4 sw=4 expandtab: */
#define _THIS
#define SDL_assert(condition)
Definition: SDL_assert.h:169
int SDL_SendDropFile(SDL_Window *window, const char *file)
int SDL_SendDropComplete(SDL_Window *window)
#define SDL_SetError
#define SDL_GetWindowSize
#define SDL_GetMouseState
#define SDL_GetWindowFlags
#define SDL_GetKeyboardFocus
#define SDL_GetWindowMinimumSize
#define SDL_GetWindowMaximumSize
#define SDL_GetKeyboardState
#define SDL_free
#define SDL_memcmp
#define SDL_GetMouseFocus
#define SDL_GetHintBoolean
#define SDL_IsShapedWindow
#define SDL_atoi
#define SDL_snprintf
#define SDL_GetHint
int SDL_SendKeymapChangedEvent(void)
Definition: SDL_events.c:996
int SDL_SendSysWMEvent(SDL_SysWMmsg *message)
Definition: SDL_events.c:979
@ SDL_SYSWMEVENT
Definition: SDL_events.h:93
#define SDL_GetEventState(type)
Definition: SDL_events.h:772
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_ENABLE
Definition: SDL_events.h:759
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_HINT_WINDOWS_INTRESOURCE_ICON
A variable to specify custom icon resource id from RC file on Windows platform.
Definition: SDL_hints.h:240
#define SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH
Allow mouse click events when clicking to focus an SDL window.
Definition: SDL_hints.h:305
#define SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4
Tell SDL not to generate window-close events for Alt+F4 on Windows.
Definition: SDL_hints.h:932
#define SDL_HINT_WINDOWS_INTRESOURCE_ICON_SMALL
Definition: SDL_hints.h:241
#define SDL_small_alloc(type, count, pisstack)
Definition: SDL_internal.h:39
#define SDL_small_free(ptr, isstack)
Definition: SDL_internal.h:40
void SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle)
Definition: SDL_keyboard.c:865
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
int SDL_SendKeyboardText(const char *text)
Definition: SDL_keyboard.c:789
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:679
@ KMOD_CAPS
Definition: SDL_keycode.h:337
@ KMOD_NUM
Definition: SDL_keycode.h:336
int SDL_RegisterApp(char *name, Uint32 style, void *hInst)
void SDL_UnregisterApp(void)
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
Definition: SDL_mouse.c:605
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:211
SDL_Mouse * SDL_GetMouse(void)
Definition: SDL_mouse.c:178
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
Definition: SDL_mouse.c:611
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:301
#define SDL_BUTTON_X1
Definition: SDL_mouse.h:285
#define SDL_BUTTON_X2
Definition: SDL_mouse.h:286
#define SDL_BUTTON_MIDDLE
Definition: SDL_mouse.h:283
#define SDL_BUTTON_RIGHT
Definition: SDL_mouse.h:284
#define SDL_BUTTON_LEFT
Definition: SDL_mouse.h:282
@ SDL_MOUSEWHEEL_NORMAL
Definition: SDL_mouse.h:68
#define SDL_BUTTON_MMASK
Definition: SDL_mouse.h:288
#define SDL_BUTTON_LMASK
Definition: SDL_mouse.h:287
#define SDL_BUTTON_X1MASK
Definition: SDL_mouse.h:290
#define SDL_BUTTON_RMASK
Definition: SDL_mouse.h:289
#define SDL_BUTTON(X)
Definition: SDL_mouse.h:281
#define SDL_BUTTON_X2MASK
Definition: SDL_mouse.h:291
Uint32 SDL_MouseID
Definition: SDL_mouse_c.h:28
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
const GLfloat * params
GLuint GLsizei const GLchar * message
GLuint buffer
GLuint const GLchar * name
GLsizeiptr size
GLsizei const GLchar *const * path
GLenum GLenum GLenum input
GLfloat GLfloat GLfloat GLfloat h
GLubyte GLubyte GLubyte GLubyte w
SDL_Scancode
The SDL keyboard scancode representation.
Definition: SDL_scancode.h:44
@ SDL_SCANCODE_END
Definition: SDL_scancode.h:174
@ SDL_SCANCODE_F15
Definition: SDL_scancode.h:217
@ SDL_SCANCODE_KP_PLUS
Definition: SDL_scancode.h:186
@ SDL_SCANCODE_F4
Definition: SDL_scancode.h:156
@ SDL_SCANCODE_CAPSLOCK
Definition: SDL_scancode.h:151
@ SDL_SCANCODE_NONUSBACKSLASH
Definition: SDL_scancode.h:200
@ SDL_SCANCODE_KP_0
Definition: SDL_scancode.h:197
@ SDL_SCANCODE_KP_PERIOD
Definition: SDL_scancode.h:198
@ SDL_SCANCODE_F24
Definition: SDL_scancode.h:226
@ SDL_SCANCODE_AUDIOMUTE
Definition: SDL_scancode.h:355
@ SDL_SCANCODE_DELETE
Definition: SDL_scancode.h:173
@ SDL_SCANCODE_SLASH
Definition: SDL_scancode.h:149
@ SDL_SCANCODE_KP_EQUALS
Definition: SDL_scancode.h:214
@ SDL_SCANCODE_F21
Definition: SDL_scancode.h:223
@ SDL_SCANCODE_KP_6
Definition: SDL_scancode.h:193
@ SDL_SCANCODE_KP_7
Definition: SDL_scancode.h:194
@ SDL_SCANCODE_AC_REFRESH
Definition: SDL_scancode.h:366
@ SDL_SCANCODE_KP_9
Definition: SDL_scancode.h:196
@ SDL_SCANCODE_EXSEL
Definition: SDL_scancode.h:279
@ SDL_SCANCODE_VOLUMEUP
Definition: SDL_scancode.h:239
@ SDL_SCANCODE_APP2
Definition: SDL_scancode.h:389
@ SDL_SCANCODE_CRSEL
Definition: SDL_scancode.h:278
@ SDL_SCANCODE_NUMLOCKCLEAR
Definition: SDL_scancode.h:181
@ SDL_SCANCODE_PRINTSCREEN
Definition: SDL_scancode.h:166
@ SDL_SCANCODE_MAIL
Definition: SDL_scancode.h:358
@ SDL_SCANCODE_KP_3
Definition: SDL_scancode.h:190
@ SDL_SCANCODE_AUDIOPREV
Definition: SDL_scancode.h:352
@ SDL_SCANCODE_PAUSE
Definition: SDL_scancode.h:168
@ SDL_SCANCODE_RETURN
Definition: SDL_scancode.h:92
@ SDL_SCANCODE_HELP
Definition: SDL_scancode.h:228
@ SDL_SCANCODE_PAGEDOWN
Definition: SDL_scancode.h:175
@ SDL_SCANCODE_LSHIFT
Definition: SDL_scancode.h:329
@ SDL_SCANCODE_AUDIOSTOP
Definition: SDL_scancode.h:353
@ SDL_SCANCODE_LCTRL
Definition: SDL_scancode.h:328
@ SDL_SCANCODE_F16
Definition: SDL_scancode.h:218
@ SDL_SCANCODE_F22
Definition: SDL_scancode.h:224
@ SDL_SCANCODE_UNKNOWN
Definition: SDL_scancode.h:45
@ SDL_SCANCODE_AC_STOP
Definition: SDL_scancode.h:365
@ SDL_SCANCODE_AC_SEARCH
Definition: SDL_scancode.h:361
@ SDL_SCANCODE_F19
Definition: SDL_scancode.h:221
@ SDL_SCANCODE_EXECUTE
Definition: SDL_scancode.h:227
@ SDL_SCANCODE_RALT
Definition: SDL_scancode.h:334
@ SDL_SCANCODE_SYSREQ
Definition: SDL_scancode.h:269
@ SDL_SCANCODE_F17
Definition: SDL_scancode.h:219
@ SDL_SCANCODE_KP_ENTER
Definition: SDL_scancode.h:187
@ SDL_SCANCODE_AC_BACK
Definition: SDL_scancode.h:363
@ SDL_SCANCODE_PAGEUP
Definition: SDL_scancode.h:172
@ SDL_SCANCODE_AUDIOPLAY
Definition: SDL_scancode.h:354
@ SDL_SCANCODE_F23
Definition: SDL_scancode.h:225
@ SDL_SCANCODE_KP_1
Definition: SDL_scancode.h:188
@ SDL_SCANCODE_AC_BOOKMARKS
Definition: SDL_scancode.h:367
@ SDL_SCANCODE_DOWN
Definition: SDL_scancode.h:178
@ SDL_SCANCODE_RIGHT
Definition: SDL_scancode.h:176
@ SDL_SCANCODE_MODE
Definition: SDL_scancode.h:337
@ SDL_SCANCODE_KP_2
Definition: SDL_scancode.h:189
@ SDL_SCANCODE_KP_MULTIPLY
Definition: SDL_scancode.h:184
@ SDL_SCANCODE_APP1
Definition: SDL_scancode.h:388
@ SDL_SCANCODE_UP
Definition: SDL_scancode.h:179
@ SDL_SCANCODE_LEFT
Definition: SDL_scancode.h:177
@ SDL_SCANCODE_AUDIONEXT
Definition: SDL_scancode.h:351
@ SDL_SCANCODE_SELECT
Definition: SDL_scancode.h:230
@ SDL_SCANCODE_KP_4
Definition: SDL_scancode.h:191
@ SDL_SCANCODE_HOME
Definition: SDL_scancode.h:171
@ SDL_SCANCODE_F14
Definition: SDL_scancode.h:216
@ SDL_SCANCODE_LALT
Definition: SDL_scancode.h:330
@ SDL_SCANCODE_KP_8
Definition: SDL_scancode.h:195
@ SDL_SCANCODE_RCTRL
Definition: SDL_scancode.h:332
@ SDL_SCANCODE_F20
Definition: SDL_scancode.h:222
@ SDL_SCANCODE_CLEAR
Definition: SDL_scancode.h:271
@ SDL_SCANCODE_AC_HOME
Definition: SDL_scancode.h:362
@ SDL_SCANCODE_VOLUMEDOWN
Definition: SDL_scancode.h:240
@ SDL_SCANCODE_KP_DIVIDE
Definition: SDL_scancode.h:183
@ SDL_SCANCODE_F18
Definition: SDL_scancode.h:220
@ SDL_SCANCODE_F13
Definition: SDL_scancode.h:215
@ SDL_SCANCODE_MEDIASELECT
Definition: SDL_scancode.h:356
@ SDL_SCANCODE_RSHIFT
Definition: SDL_scancode.h:333
@ SDL_SCANCODE_INSERT
Definition: SDL_scancode.h:169
@ SDL_SCANCODE_AC_FORWARD
Definition: SDL_scancode.h:364
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
uint32_t Uint32
Definition: SDL_stdinc.h:203
uint16_t Uint16
Definition: SDL_stdinc.h:191
uint8_t Uint8
Definition: SDL_stdinc.h:179
void(* SDL_WindowsMessageHook)(void *userdata, void *hWnd, unsigned int message, Uint64 wParam, Sint64 lParam)
Set a function that is called for every windows message, before TranslateMessage()
Definition: SDL_system.h:49
void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata)
SDL_VideoDevice * SDL_GetVideoDevice(void)
Definition: SDL_video.c:583
@ SDL_SYSWM_WINDOWS
Definition: SDL_syswm.h:122
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:242
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, float x, float y, float pressure)
Definition: SDL_touch.c:364
int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
Definition: SDL_touch.c:155
@ SDL_TOUCH_DEVICE_DIRECT
Definition: SDL_touch.h:47
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
#define SDL_TOUCH_MOUSEID
Definition: SDL_touch.h:61
#define SDL_VERSION(x)
Macro to determine SDL version program was compiled against.
Definition: SDL_version.h:79
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
SDL_HitTestResult
Possible return values from the SDL_HitTest callback.
Definition: SDL_video.h:1021
@ SDL_HITTEST_DRAGGABLE
Definition: SDL_video.h:1023
@ SDL_HITTEST_RESIZE_LEFT
Definition: SDL_video.h:1031
@ SDL_HITTEST_RESIZE_TOP
Definition: SDL_video.h:1025
@ SDL_HITTEST_RESIZE_TOPRIGHT
Definition: SDL_video.h:1026
@ SDL_HITTEST_NORMAL
Definition: SDL_video.h:1022
@ SDL_HITTEST_RESIZE_BOTTOM
Definition: SDL_video.h:1029
@ SDL_HITTEST_RESIZE_BOTTOMRIGHT
Definition: SDL_video.h:1028
@ SDL_HITTEST_RESIZE_BOTTOMLEFT
Definition: SDL_video.h:1030
@ SDL_HITTEST_RESIZE_RIGHT
Definition: SDL_video.h:1027
@ SDL_HITTEST_RESIZE_TOPLEFT
Definition: SDL_video.h:1024
@ SDL_WINDOW_MOUSE_CAPTURE
Definition: SDL_video.h:116
@ SDL_WINDOW_RESIZABLE
Definition: SDL_video.h:105
@ SDL_WINDOW_FULLSCREEN
Definition: SDL_video.h:100
@ SDL_WINDOW_BORDERLESS
Definition: SDL_video.h:104
@ SDL_WINDOWEVENT_HIDDEN
Definition: SDL_video.h:150
@ SDL_WINDOWEVENT_CLOSE
Definition: SDL_video.h:167
@ SDL_WINDOWEVENT_RESIZED
Definition: SDL_video.h:155
@ SDL_WINDOWEVENT_SHOWN
Definition: SDL_video.h:149
@ SDL_WINDOWEVENT_MOVED
Definition: SDL_video.h:153
@ SDL_WINDOWEVENT_MINIMIZED
Definition: SDL_video.h:159
@ SDL_WINDOWEVENT_MAXIMIZED
Definition: SDL_video.h:160
@ SDL_WINDOWEVENT_RESTORED
Definition: SDL_video.h:161
@ SDL_WINDOWEVENT_EXPOSED
Definition: SDL_video.h:151
#define VK_OEM_102
Definition: SDL_vkeys.h:74
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:47
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:46
void WIN_CheckClipboardUpdate(struct SDL_VideoData *data)
HINSTANCE SDL_Instance
LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
LPTSTR SDL_Appname
void WIN_PumpEvents(_THIS)
Uint32 SDL_Appstyle
void WIN_ResetDeadKeys(void)
SDL_bool IME_HandleMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM *lParam, struct SDL_VideoData *videodata)
void WIN_UpdateKeymap(void)
HCURSOR SDL_cursor
int Win32_ResizeWindowShape(SDL_Window *window)
#define TOUCHEVENTF_MOVE
#define TOUCHEVENTF_DOWN
SDL_bool g_WindowFrameUsableWhileCursorHidden
#define TOUCHEVENTF_UP
SDL_bool g_WindowsEnableMessageLoop
void WIN_UpdateClipCursor(SDL_Window *window)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:167
#define TRUE
Definition: edid-parse.c:33
#define FALSE
Definition: edid-parse.c:34
EGLImageKHR EGLint EGLint * handle
Definition: eglext.h:937
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
static const SDL_Scancode windows_scancode_table[]
SDL_bool relative_mode
Definition: SDL_mouse_c.h:87
SDL_Window * focus
Definition: SDL_mouse_c.h:77
SDL_bool relative_mode_warp
Definition: SDL_mouse_c.h:88
SDL_bool touch_mouse_events
Definition: SDL_mouse_c.h:95
SDL_bool was_touch_mouse_events
Definition: SDL_mouse_c.h:97
The structure that defines a point (integer)
Definition: SDL_rect.h:49
int x
Definition: SDL_rect.h:50
int y
Definition: SDL_rect.h:51
union SDL_SysWMmsg::@15 msg
SDL_SYSWM_TYPE subsystem
Definition: SDL_syswm.h:141
SDL_version version
Definition: SDL_syswm.h:140
SDL_Window * windows
Definition: SDL_sysvideo.h:317
The type used to identify a window.
Definition: SDL_sysvideo.h:74
SDL_Window * next
Definition: SDL_sysvideo.h:114
SDL_Texture * button
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47
SDL_Rect rect
Definition: testrelative.c:27
static Uint32 callback(Uint32 interval, void *param)
Definition: testtimer.c:34
#define MAX_WMMSG
Definition: wmmsg.h:22
char * wmtab[]
Definition: wmmsg.h:24