From 03f8528315fa46c95991a34f3325d7b33ae5538c Mon Sep 17 00:00:00 2001
From: Edward Rudd <urkle@outoforder.cc>
Date: Sat, 02 May 2020 21:48:36 +0000
Subject: [PATCH] Update source to SDL2 2.0.12

---
 source/src/video/windows/SDL_windowsevents.c |  175 +++++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 124 insertions(+), 51 deletions(-)

diff --git a/source/src/video/windows/SDL_windowsevents.c b/source/src/video/windows/SDL_windowsevents.c
index e961cf5..d79d42c 100644
--- a/source/src/video/windows/SDL_windowsevents.c
+++ b/source/src/video/windows/SDL_windowsevents.c
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -47,9 +47,6 @@
 #include "wmmsg.h"
 #endif
 
-/* For processing mouse WM_*BUTTON* and WM_MOUSEMOVE message-data from GetMessageExtraInfo() */
-#define MOUSEEVENTF_FROMTOUCH 0xFF515700
-
 /* Masks for processing the windows KEYDOWN and KEYUP messages */
 #define REPEATED_KEYMASK    (1<<30)
 #define EXTENDED_KEYMASK    (1<<24)
@@ -86,7 +83,14 @@
 VKeytoScancode(WPARAM vkey)
 {
     switch (vkey) {
+/* Windows generates this virtual keycode for Keypad 5 when NumLock is off.
     case VK_CLEAR: return SDL_SCANCODE_CLEAR;
+*/
+    case VK_LEFT: return SDL_SCANCODE_LEFT;
+    case VK_UP: return SDL_SCANCODE_UP;
+    case VK_RIGHT: return SDL_SCANCODE_RIGHT;
+    case VK_DOWN: return SDL_SCANCODE_DOWN;
+
     case VK_MODECHANGE: return SDL_SCANCODE_MODE;
     case VK_SELECT: return SDL_SCANCODE_SELECT;
     case VK_EXECUTE: return SDL_SCANCODE_EXECUTE;
@@ -244,7 +248,7 @@
 
 /*
 * Some windows systems fail to send a WM_LBUTTONDOWN sometimes, but each mouse move contains the current button state also
-*  so this funciton reconciles our view of the world with the current buttons reported by windows
+*  so this function reconciles our view of the world with the current buttons reported by windows
 */
 static void
 WIN_CheckWParamMouseButtons(WPARAM wParam, SDL_WindowData *data, SDL_MouseID mouseID)
@@ -259,7 +263,6 @@
         data->mouse_button_flags = wParam;
     }
 }
-
 
 static void
 WIN_CheckRawMouseButtons(ULONG rawButtons, SDL_WindowData *data)
@@ -362,6 +365,37 @@
    This is used to implement a workaround.. */
 static SDL_bool isWin10FCUorNewer = SDL_FALSE;
 
+/* We want to generate mouse events from mouse and pen, and touch events from touchscreens */
+#define MI_WP_SIGNATURE         0xFF515700
+#define MI_WP_SIGNATURE_MASK    0xFFFFFF00
+#define IsTouchEvent(dw) ((dw) & MI_WP_SIGNATURE_MASK) == MI_WP_SIGNATURE
+
+typedef enum
+{
+    SDL_MOUSE_EVENT_SOURCE_UNKNOWN,
+    SDL_MOUSE_EVENT_SOURCE_MOUSE,
+    SDL_MOUSE_EVENT_SOURCE_TOUCH,
+    SDL_MOUSE_EVENT_SOURCE_PEN,
+} SDL_MOUSE_EVENT_SOURCE;
+
+static SDL_MOUSE_EVENT_SOURCE GetMouseMessageSource()
+{
+    LPARAM extrainfo = GetMessageExtraInfo();
+    /* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
+    /* Versions below Vista will set the low 7 bits to the Mouse ID and don't use bit 7:
+       Check bits 8-32 for the signature (which will indicate a Tablet PC Pen or Touch Device).
+       Only check bit 7 when Vista and up(Cleared=Pen, Set=Touch(which we need to filter out)),
+       when the signature is set. The Mouse ID will be zero for an actual mouse. */
+    if (IsTouchEvent(extrainfo)) {
+        if (extrainfo & 0x80) {
+            return SDL_MOUSE_EVENT_SOURCE_TOUCH;
+        } else {
+            return SDL_MOUSE_EVENT_SOURCE_PEN;
+        }
+    }
+    return SDL_MOUSE_EVENT_SOURCE_MOUSE;
+}
+
 LRESULT CALLBACK
 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
@@ -426,13 +460,12 @@
             POINT cursorPos;
             BOOL minimized;
 
-            /* Don't mark the window as shown if it's activated before being shown */
-            if (!IsWindowVisible(hwnd)) {
-                break;
-            }
-
             minimized = HIWORD(wParam);
             if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
+                /* Don't mark the window as shown if it's activated before being shown */
+                if (!IsWindowVisible(hwnd)) {
+                    break;
+                }
                 if (LOWORD(wParam) == WA_CLICKACTIVE) {
                     if (GetAsyncKeyState(VK_LBUTTON)) {
                         data->focus_click_pending |= SDL_BUTTON_LMASK;
@@ -450,7 +483,7 @@
                         data->focus_click_pending |= SDL_BUTTON_X2MASK;
                     }
                 }
-                
+
                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
                 if (SDL_GetKeyboardFocus() != data->window) {
                     SDL_SetKeyboardFocus(data->window);
@@ -479,7 +512,7 @@
                     WIN_ResetDeadKeys();
                 }
 
-                if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect) == 0)) {
+                if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect)) == 0) {
                     ClipCursor(NULL);
                     SDL_zero(data->cursor_clipped_rect);
                 }
@@ -494,19 +527,24 @@
         {
             SDL_Mouse *mouse = SDL_GetMouse();
             if (!mouse->relative_mode || mouse->relative_mode_warp) {
-                SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0);
-                SDL_SendMouseMotion(data->window, mouseID, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
-                if (isWin10FCUorNewer && mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
-                    /* To work around #3931, Win10 bug introduced in Fall Creators Update, where
-                       SetCursorPos() (SDL_WarpMouseInWindow()) doesn't reliably generate mouse events anymore,
-                       after each windows mouse event generate a fake event for the middle of the window
-                       if relative_mode_warp is used */
-                    int center_x = 0, center_y = 0;
-                    SDL_GetWindowSize(data->window, &center_x, &center_y);
-                    center_x /= 2;
-                    center_y /= 2;
-                    SDL_SendMouseMotion(data->window, mouseID, 0, center_x, center_y);
+                /* Only generate mouse events for real mouse */
+                if (GetMouseMessageSource() != SDL_MOUSE_EVENT_SOURCE_TOUCH) {
+                    SDL_SendMouseMotion(data->window, 0, 0, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+                    if (isWin10FCUorNewer && mouse->relative_mode_warp) {
+                        /* To work around #3931, Win10 bug introduced in Fall Creators Update, where
+                           SetCursorPos() (SDL_WarpMouseInWindow()) doesn't reliably generate mouse events anymore,
+                           after each windows mouse event generate a fake event for the middle of the window
+                           if relative_mode_warp is used */
+                        int center_x = 0, center_y = 0;
+                        SDL_GetWindowSize(data->window, &center_x, &center_y);
+                        center_x /= 2;
+                        center_y /= 2;
+                        SDL_SendMouseMotion(data->window, 0, 0, center_x, center_y);
+                    }
                 }
+            } else {
+                /* We still need to update focus */
+                SDL_SetMouseFocus(data->window);
             }
         }
         /* don't break here, fall through to check the wParam like the button presses */
@@ -525,8 +563,9 @@
         {
             SDL_Mouse *mouse = SDL_GetMouse();
             if (!mouse->relative_mode || mouse->relative_mode_warp) {
-                SDL_MouseID mouseID = (((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) ? SDL_TOUCH_MOUSEID : 0);
-                WIN_CheckWParamMouseButtons(wParam, data, mouseID);
+                if (GetMouseMessageSource() != SDL_MOUSE_EVENT_SOURCE_TOUCH) {
+                    WIN_CheckWParamMouseButtons(wParam, data, 0);
+                }
             }
         }
         break;
@@ -548,8 +587,11 @@
 
             GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
 
-            /* Mouse data */
+            /* Mouse data (ignoring synthetic mouse events generated for touchscreens) */
             if (inp.header.dwType == RIM_TYPEMOUSE) {
+                if (GetMouseMessageSource() == SDL_MOUSE_EVENT_SOURCE_TOUCH) {
+                    break;
+                }
                 if (isRelative) {
                     RAWMOUSE* rawmouse = &inp.data.mouse;
 
@@ -557,16 +599,22 @@
                         SDL_SendMouseMotion(data->window, 0, 1, (int)rawmouse->lLastX, (int)rawmouse->lLastY);
                     } else {
                         /* synthesize relative moves from the abs position */
-                        static SDL_Point initialMousePoint;
-                        if (initialMousePoint.x == 0 && initialMousePoint.y == 0) {
-                            initialMousePoint.x = rawmouse->lLastX;
-                            initialMousePoint.y = rawmouse->lLastY;
+                        static SDL_Point lastMousePoint;
+                        SDL_bool virtual_desktop = (rawmouse->usFlags & MOUSE_VIRTUAL_DESKTOP) ? SDL_TRUE : SDL_FALSE;
+                        int w = GetSystemMetrics(virtual_desktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN);
+                        int h = GetSystemMetrics(virtual_desktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN);
+                        int x = (int)(((float)rawmouse->lLastX / 65535.0f) * w);
+                        int y = (int)(((float)rawmouse->lLastY / 65535.0f) * h);
+
+                        if (lastMousePoint.x == 0 && lastMousePoint.y == 0) {
+                            lastMousePoint.x = x;
+                            lastMousePoint.y = y;
                         }
 
-                        SDL_SendMouseMotion(data->window, 0, 1, (int)(rawmouse->lLastX-initialMousePoint.x), (int)(rawmouse->lLastY-initialMousePoint.y));
+                        SDL_SendMouseMotion(data->window, 0, 1, (int)(x-lastMousePoint.x), (int)(y-lastMousePoint.y));
 
-                        initialMousePoint.x = rawmouse->lLastX;
-                        initialMousePoint.y = rawmouse->lLastY;
+                        lastMousePoint.x = x;
+                        lastMousePoint.y = y;
                     }
                     WIN_CheckRawMouseButtons(rawmouse->usButtonFlags, data);
                 } else if (isCapture) {
@@ -612,10 +660,21 @@
     case WM_MOUSELEAVE:
         if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
             if (!IsIconic(hwnd)) {
+                SDL_Mouse *mouse;
                 POINT cursorPos;
                 GetCursorPos(&cursorPos);
                 ScreenToClient(hwnd, &cursorPos);
-                SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
+                mouse = SDL_GetMouse();
+                if (!mouse->was_touch_mouse_events) { /* we're not a touch handler causing a mouse leave? */
+                    SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
+                } else { /* touch handling? */
+                    mouse->was_touch_mouse_events = SDL_FALSE; /* not anymore */
+                    if (mouse->touch_mouse_events) { /* convert touch to mouse events */
+                        SDL_SendMouseMotion(data->window, SDL_TOUCH_MOUSEID, 0, cursorPos.x, cursorPos.y);
+                    } else { /* normal handling */
+                        SDL_SendMouseMotion(data->window, 0, 0, cursorPos.x, cursorPos.y);
+                    }
+               }
             }
             SDL_SetMouseFocus(NULL);
         }
@@ -714,8 +773,9 @@
             int max_w, max_h;
             BOOL constrain_max_size;
 
-            if (SDL_IsShapedWindow(data->window))
+            if (SDL_IsShapedWindow(data->window)) {
                 Win32_ResizeWindowShape(data->window);
+            }
 
             /* If this is an expected size change, allow it */
             if (data->expected_resize) {
@@ -817,8 +877,7 @@
 
             w = rect.right - rect.left;
             h = rect.bottom - rect.top;
-            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
-                                h);
+            SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w, h);
 
             /* Forces a WM_PAINT event */
             InvalidateRect(hwnd, NULL, FALSE);
@@ -867,8 +926,7 @@
             RECT rect;
             if (GetUpdateRect(hwnd, &rect, FALSE)) {
                 ValidateRect(hwnd, NULL);
-                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
-                                    0, 0);
+                SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
             }
         }
         returnCode = 0;
@@ -908,7 +966,8 @@
     case WM_TOUCH:
         if (data->videodata->GetTouchInputInfo && data->videodata->CloseTouchInputHandle) {
             UINT i, num_inputs = LOWORD(wParam);
-            PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
+            SDL_bool isstack;
+            PTOUCHINPUT inputs = SDL_small_alloc(TOUCHINPUT, num_inputs, &isstack);
             if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
                 RECT rect;
                 float x, y;
@@ -916,7 +975,7 @@
                 if (!GetClientRect(hwnd, &rect) ||
                     (rect.right == rect.left && rect.bottom == rect.top)) {
                     if (inputs) {
-                        SDL_stack_free(inputs);
+                        SDL_small_free(inputs, isstack);
                     }
                     break;
                 }
@@ -931,7 +990,11 @@
                     PTOUCHINPUT input = &inputs[i];
 
                     const SDL_TouchID touchId = (SDL_TouchID)((size_t)input->hSource);
-                    if (SDL_AddTouch(touchId, "") < 0) {
+
+                    /* TODO: Can we use GetRawInputDeviceInfo and HID info to
+                       determine if this is a direct or indirect touch device?
+                     */
+                    if (SDL_AddTouch(touchId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) {
                         continue;
                     }
 
@@ -940,17 +1003,17 @@
                     y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
 
                     if (input->dwFlags & TOUCHEVENTF_DOWN) {
-                        SDL_SendTouch(touchId, input->dwID, SDL_TRUE, x, y, 1.0f);
+                        SDL_SendTouch(touchId, input->dwID, data->window, SDL_TRUE, x, y, 1.0f);
                     }
                     if (input->dwFlags & TOUCHEVENTF_MOVE) {
-                        SDL_SendTouchMotion(touchId, input->dwID, x, y, 1.0f);
+                        SDL_SendTouchMotion(touchId, input->dwID, data->window, x, y, 1.0f);
                     }
                     if (input->dwFlags & TOUCHEVENTF_UP) {
-                        SDL_SendTouch(touchId, input->dwID, SDL_FALSE, x, y, 1.0f);
+                        SDL_SendTouch(touchId, input->dwID, data->window, SDL_FALSE, x, y, 1.0f);
                     }
                 }
             }
-            SDL_stack_free(inputs);
+            SDL_small_free(inputs, isstack);
 
             data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
             return 0;
@@ -963,15 +1026,16 @@
             HDROP drop = (HDROP) wParam;
             UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
             for (i = 0; i < count; ++i) {
+                SDL_bool isstack;
                 UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
-                LPTSTR buffer = SDL_stack_alloc(TCHAR, size);
+                LPTSTR buffer = SDL_small_alloc(TCHAR, size, &isstack);
                 if (buffer) {
                     if (DragQueryFile(drop, i, buffer, size)) {
                         char *file = WIN_StringToUTF8(buffer);
                         SDL_SendDropFile(data->window, file);
                         SDL_free(file);
                     }
-                    SDL_stack_free(buffer);
+                    SDL_small_free(buffer, isstack);
                 }
             }
             SDL_SendDropComplete(data->window);
@@ -1067,6 +1131,7 @@
     const Uint8 *keystate;
     MSG msg;
     DWORD start_ticks = GetTickCount();
+    int new_messages = 0;
 
     if (g_WindowsEnableMessageLoop) {
         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
@@ -1080,7 +1145,15 @@
 
             /* Make sure we don't busy loop here forever if there are lots of events coming in */
             if (SDL_TICKS_PASSED(msg.time, start_ticks)) {
-                break;
+                /* We might get a few new messages generated by the Steam overlay or other application hooks
+                   In this case those messages will be processed before any pending input, so we want to continue after those messages.
+                   (thanks to Peter Deayton for his investigation here)
+                 */
+                const int MAX_NEW_MESSAGES = 3;
+                ++new_messages;
+                if (new_messages > MAX_NEW_MESSAGES) {
+                    break;
+                }
             }
         }
     }

--
Gitblit v1.9.3