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