Don't need to use raw input to track the mouse during mouse capture (thanks Brick!)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index 6307fac..60f87d7 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -742,6 +742,19 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_MOUSEMOVE:
{
SDL_Mouse *mouse = SDL_GetMouse();
+
+ if (!data->mouse_tracked) {
+ TRACKMOUSEEVENT trackMouseEvent;
+
+ trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
+ trackMouseEvent.dwFlags = TME_LEAVE;
+ trackMouseEvent.hwndTrack = data->hwnd;
+
+ if (TrackMouseEvent(&trackMouseEvent)) {
+ data->mouse_tracked = SDL_TRUE;
+ }
+ }
+
if (!mouse->relative_mode || mouse->relative_mode_warp) {
/* Only generate mouse events for real mouse */
if (GetMouseMessageSource() != SDL_MOUSE_EVENT_SOURCE_TOUCH &&
@@ -781,13 +794,10 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
RAWINPUT inp;
UINT size = sizeof(inp);
const SDL_bool isRelative = mouse->relative_mode || mouse->relative_mode_warp;
- const SDL_bool isCapture = ((data->window->flags & SDL_WINDOW_MOUSE_CAPTURE) != 0);
/* Relative mouse motion is delivered to the window with keyboard focus */
if (!isRelative || data->window != SDL_GetKeyboardFocus()) {
- if (!isCapture) {
- break;
- }
+ break;
}
GetRawInputData(hRawInput, RID_INPUT, &inp, &size, sizeof(RAWINPUTHEADER));
@@ -910,28 +920,6 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
WIN_CheckRawMouseButtons(rawmouse->usButtonFlags, data, mouseID);
- } else if (isCapture) {
- /* we check for where Windows thinks the system cursor lives in this case, so we don't really lose mouse accel, etc. */
- POINT pt;
- RECT hwndRect;
- HWND currentHnd;
-
- GetCursorPos(&pt);
- currentHnd = WindowFromPoint(pt);
- ScreenToClient(hwnd, &pt);
- GetClientRect(hwnd, &hwndRect);
-
- /* if in the window, WM_MOUSEMOVE, etc, will cover it. */
- if(currentHnd != hwnd || pt.x < 0 || pt.y < 0 || pt.x > hwndRect.right || pt.y > hwndRect.right) {
- SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
-
- SDL_SendMouseMotion(data->window, mouseID, 0, (int)pt.x, (int)pt.y);
- SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT);
- SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT);
- SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
- SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
- SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
- }
} else {
SDL_assert(0 && "Shouldn't happen");
}
@@ -951,7 +939,6 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
break;
-#ifdef WM_MOUSELEAVE
case WM_MOUSELEAVE:
if (SDL_GetMouseFocus() == data->window && !SDL_GetMouse()->relative_mode && !(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
if (!IsIconic(hwnd)) {
@@ -973,18 +960,16 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
}
- /* When WM_MOUSELEAVE is fired we can be assured that the cursor has left the window.
- Regardless of relative mode, it is important that mouse focus is reset as there is a potential
- race condition when in the process of leaving/entering relative mode, resulting in focus never
- being lost. This then causes a cascading failure where SDL_WINDOWEVENT_ENTER / SDL_WINDOWEVENT_LEAVE
- can stop firing permanently, due to the focus being in the wrong state and TrackMouseEvent never
- resubscribing. */
- if (!(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE))
+ /* When WM_MOUSELEAVE is fired we can be assured that the cursor has left the window */
+ if (!(data->window->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
SDL_SetMouseFocus(NULL);
+ }
+
+ /* Once we get WM_MOUSELEAVE we're guaranteed that the window is no longer tracked */
+ data->mouse_tracked = SDL_FALSE;
returnCode = 0;
break;
-#endif /* WM_MOUSELEAVE */
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
@@ -1467,6 +1452,31 @@ static void WIN_UpdateClipCursorForWindows()
}
}
+static void WIN_UpdateMouseCapture()
+{
+ SDL_Window* focusWindow = SDL_GetKeyboardFocus();
+
+ if (focusWindow && (focusWindow->flags & SDL_WINDOW_MOUSE_CAPTURE)) {
+ SDL_WindowData *data = (SDL_WindowData *) focusWindow->driverdata;
+
+ if (!data->mouse_tracked) {
+ POINT pt;
+
+ if (GetCursorPos(&pt) && ScreenToClient(data->hwnd, &pt)) {
+ SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0;
+ SDL_MouseID mouseID = SDL_GetMouse()->mouseID;
+
+ SDL_SendMouseMotion(data->window, mouseID, 0, (int)pt.x, (int)pt.y);
+ SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT);
+ SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT);
+ SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE);
+ SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1);
+ SDL_SendMouseButton(data->window, mouseID, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2);
+ }
+ }
+ }
+}
+
/* A message hook called before TranslateMessage() */
static SDL_WindowsMessageHook g_WindowsMessageHook = NULL;
static void *g_WindowsMessageHookData = NULL;
@@ -1584,6 +1594,9 @@ WIN_PumpEvents(_THIS)
/* Update the clipping rect in case someone else has stolen it */
WIN_UpdateClipCursorForWindows();
+
+ /* Update mouse capture */
+ WIN_UpdateMouseCapture();
}
diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c
index a43ea45..031fcc0 100644
--- a/src/video/windows/SDL_windowsmouse.c
+++ b/src/video/windows/SDL_windowsmouse.c
@@ -292,18 +292,22 @@ WIN_SetRelativeMouseMode(SDL_bool enabled)
static int
WIN_CaptureMouse(SDL_Window *window)
{
- if (!window) {
- SDL_Window *focusWin = SDL_GetKeyboardFocus();
- if (focusWin) {
- WIN_OnWindowEnter(SDL_GetVideoDevice(), focusWin); /* make sure WM_MOUSELEAVE messages are (re)enabled. */
+ if (window) {
+ SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
+ SetCapture(data->hwnd);
+ } else {
+ SDL_Window *focus_window = SDL_GetMouseFocus();
+
+ if (focus_window) {
+ SDL_WindowData *data = (SDL_WindowData *)focus_window->driverdata;
+ if (!data->mouse_tracked) {
+ SDL_SetMouseFocus(NULL);
+ }
}
+ ReleaseCapture();
}
- /* While we were thinking of SetCapture() when designing this API in SDL,
- we didn't count on the fact that SetCapture() only tracks while the
- left mouse button is held down! Instead, we listen for raw mouse input
- and manually query the mouse when it leaves the window. :/ */
- return ToggleRawInput(window != NULL);
+ return 0;
}
static Uint32
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index 8013d49..0cfc006 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -953,18 +953,6 @@ void WIN_OnWindowEnter(_THIS, SDL_Window * window)
if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) {
WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
}
-
-#ifdef WM_MOUSELEAVE
- {
- TRACKMOUSEEVENT trackMouseEvent;
-
- trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
- trackMouseEvent.dwFlags = TME_LEAVE;
- trackMouseEvent.hwndTrack = data->hwnd;
-
- TrackMouseEvent(&trackMouseEvent);
- }
-#endif /* WM_MOUSELEAVE */
}
void
diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h
index b7d1ce1..015fb0f 100644
--- a/src/video/windows/SDL_windowswindow.h
+++ b/src/video/windows/SDL_windowswindow.h
@@ -53,6 +53,7 @@ typedef struct
SDL_bool in_window_deactivation;
RECT cursor_clipped_rect;
SDL_Point last_raw_mouse_position;
+ SDL_bool mouse_tracked;
struct SDL_VideoData *videodata;
#if SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface;