src/video/windows/SDL_windowsevents.c
changeset 11758 c70cf178aacb
parent 11716 93edd752e966
child 11761 74f570e0b634
equal deleted inserted replaced
11757:72855e49c8cc 11758:c70cf178aacb
   357 ShouldGenerateWindowCloseOnAltF4(void)
   357 ShouldGenerateWindowCloseOnAltF4(void)
   358 {
   358 {
   359     return !SDL_GetHintBoolean(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, SDL_FALSE);
   359     return !SDL_GetHintBoolean(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, SDL_FALSE);
   360 }
   360 }
   361 
   361 
       
   362 /* Win10 "Fall Creators Update" introduced the bug that SetCursorPos() (as used by SDL_WarpMouseInWindow())
       
   363    doesn't reliably generate WM_MOUSEMOVE events anymore (see #3931) which breaks relative mouse mode via warping.
       
   364    This is used to implement a workaround.. */
       
   365 static SDL_bool isWin10FCUorNewer = SDL_FALSE;
       
   366 
   362 LRESULT CALLBACK
   367 LRESULT CALLBACK
   363 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   368 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   364 {
   369 {
   365     SDL_WindowData *data;
   370     SDL_WindowData *data;
   366     LRESULT returnCode = -1;
   371     LRESULT returnCode = -1;
   474         {
   479         {
   475             SDL_Mouse *mouse = SDL_GetMouse();
   480             SDL_Mouse *mouse = SDL_GetMouse();
   476             if (!mouse->relative_mode || mouse->relative_mode_warp) {
   481             if (!mouse->relative_mode || mouse->relative_mode_warp) {
   477                 SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0);
   482                 SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0);
   478                 SDL_SendMouseMotion(data->window, mouseID, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
   483                 SDL_SendMouseMotion(data->window, mouseID, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
       
   484                 if (isWin10FCUorNewer && mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
       
   485                     /* To work around #3931, Win10 bug introduced in Fall Creators Update, where
       
   486                        SetCursorPos() (SDL_WarpMouseInWindow()) doesn't reliably generate mouse events anymore,
       
   487                        after each windows mouse event generate a fake event for the middle of the window
       
   488                        if relative_mode_warp is used */
       
   489                     int center_x = 0, center_y = 0;
       
   490                     SDL_GetWindowSize(data->window, &center_x, &center_y);
       
   491                     center_x /= 2;
       
   492                     center_y /= 2;
       
   493                     SDL_SendMouseMotion(data->window, mouseID, 0, center_x, center_y);
       
   494                 }
   479             }
   495             }
   480         }
   496         }
   481         /* don't break here, fall through to check the wParam like the button presses */
   497         /* don't break here, fall through to check the wParam like the button presses */
   482     case WM_LBUTTONUP:
   498     case WM_LBUTTONUP:
   483     case WM_RBUTTONUP:
   499     case WM_RBUTTONUP:
  1049     if ((keystate[SDL_SCANCODE_RSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
  1065     if ((keystate[SDL_SCANCODE_RSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
  1050         SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RSHIFT);
  1066         SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RSHIFT);
  1051     }
  1067     }
  1052 }
  1068 }
  1053 
  1069 
       
  1070 /* to work around #3931, a bug introduced in Win10 Fall Creators Update (build nr. 16299)
       
  1071    we need to detect the windows version. this struct and the function below does that.
       
  1072    usually this struct and the corresponding function (RtlGetVersion) are in <Ntddk.h>
       
  1073    but here we just load it dynamically */
       
  1074 struct SDL_WIN_OSVERSIONINFOW {
       
  1075     ULONG dwOSVersionInfoSize;
       
  1076     ULONG dwMajorVersion;
       
  1077     ULONG dwMinorVersion;
       
  1078     ULONG dwBuildNumber;
       
  1079     ULONG dwPlatformId;
       
  1080     WCHAR szCSDVersion[128];
       
  1081 };
       
  1082 
       
  1083 static SDL_bool
       
  1084 IsWin10FCUorNewer(void)
       
  1085 {
       
  1086     typedef LONG(WINAPI* RtlGetVersionPtr)(struct SDL_WIN_OSVERSIONINFOW*);
       
  1087     struct SDL_WIN_OSVERSIONINFOW info;
       
  1088     SDL_zero(info);
       
  1089 
       
  1090     HMODULE handle = GetModuleHandleW(L"ntdll.dll");
       
  1091     if (handle) {
       
  1092         RtlGetVersionPtr getVersionPtr = (RtlGetVersionPtr)GetProcAddress(handle, "RtlGetVersion");
       
  1093         if (getVersionPtr != NULL) {
       
  1094             info.dwOSVersionInfoSize = sizeof(info);
       
  1095             if (getVersionPtr(&info) == 0) { /* STATUS_SUCCESS == 0 */
       
  1096                 if (   (info.dwMajorVersion == 10 && info.dwMinorVersion == 0 && info.dwBuildNumber >= 16299)
       
  1097                     || (info.dwMajorVersion == 10 && info.dwMinorVersion > 0)
       
  1098                     || (info.dwMajorVersion > 10) )
       
  1099                 {
       
  1100                     return SDL_TRUE;
       
  1101                 }
       
  1102             }
       
  1103         }
       
  1104     }
       
  1105     return SDL_FALSE;
       
  1106 }
       
  1107 
  1054 static int app_registered = 0;
  1108 static int app_registered = 0;
  1055 LPTSTR SDL_Appname = NULL;
  1109 LPTSTR SDL_Appname = NULL;
  1056 Uint32 SDL_Appstyle = 0;
  1110 Uint32 SDL_Appstyle = 0;
  1057 HINSTANCE SDL_Instance = NULL;
  1111 HINSTANCE SDL_Instance = NULL;
  1058 
  1112 
  1113 
  1167 
  1114     if (!RegisterClassEx(&wcex)) {
  1168     if (!RegisterClassEx(&wcex)) {
  1115         return SDL_SetError("Couldn't register application class");
  1169         return SDL_SetError("Couldn't register application class");
  1116     }
  1170     }
  1117 
  1171 
       
  1172     isWin10FCUorNewer = IsWin10FCUorNewer();
       
  1173 
  1118     app_registered = 1;
  1174     app_registered = 1;
  1119     return 0;
  1175     return 0;
  1120 }
  1176 }
  1121 
  1177 
  1122 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
  1178 /* Unregisters the windowclass registered in SDL_RegisterApp above. */