From 72379ba510cb6229f65c92d34709264e417448e6 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Tue, 25 Aug 2020 21:22:00 -0700 Subject: [PATCH] windows: Fix handling of swapped mouse buttons GetAsyncKeyState() and GetRawInputData() report the state of the physical buttons without applying the user's primary/secondary mouse button swap preference. Swap the buttons returned from these functions, so we expose a consistent view of the buttons to SDL callers. This new behavior also matches the behavior of macOS and X11 backends. See the Remarks section of the GetAsyncKeyState() function on MSDN. --- src/video/windows/SDL_windowsevents.c | 72 +++++++++++++++++---------- src/video/windows/SDL_windowsmouse.c | 6 ++- 2 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 05b21e921..553fe00b6 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -244,8 +244,17 @@ WIN_ShouldIgnoreFocusClick() } static void -WIN_CheckWParamMouseButton(SDL_bool bwParamMousePressed, SDL_bool bSDLMousePressed, SDL_WindowData *data, Uint8 button, SDL_MouseID mouseID) +WIN_CheckWParamMouseButton(SDL_bool bwParamMousePressed, Uint32 mouseFlags, SDL_bool bSwapButtons, SDL_WindowData *data, Uint8 button, SDL_MouseID mouseID) { + if (bSwapButtons) { + if (button == SDL_BUTTON_LEFT) { + button = SDL_BUTTON_RIGHT; + } + else if (button == SDL_BUTTON_RIGHT) { + button = SDL_BUTTON_LEFT; + } + } + if (data->focus_click_pending & SDL_BUTTON(button)) { /* Ignore the button click for activation */ if (!bwParamMousePressed) { @@ -257,9 +266,9 @@ WIN_CheckWParamMouseButton(SDL_bool bwParamMousePressed, SDL_bool bSDLMousePress } } - if (bwParamMousePressed && !bSDLMousePressed) { + if (bwParamMousePressed && !(mouseFlags & SDL_BUTTON(button))) { SDL_SendMouseButton(data->window, mouseID, SDL_PRESSED, button); - } else if (!bwParamMousePressed && bSDLMousePressed) { + } else if (!bwParamMousePressed && (mouseFlags & SDL_BUTTON(button))) { SDL_SendMouseButton(data->window, mouseID, SDL_RELEASED, button); } } @@ -273,11 +282,14 @@ WIN_CheckWParamMouseButtons(WPARAM wParam, SDL_WindowData *data, SDL_MouseID mou { if (wParam != data->mouse_button_flags) { Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL); - WIN_CheckWParamMouseButton((wParam & MK_LBUTTON), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, mouseID); - WIN_CheckWParamMouseButton((wParam & MK_MBUTTON), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, mouseID); - WIN_CheckWParamMouseButton((wParam & MK_RBUTTON), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, mouseID); - WIN_CheckWParamMouseButton((wParam & MK_XBUTTON1), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, mouseID); - WIN_CheckWParamMouseButton((wParam & MK_XBUTTON2), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, mouseID); + + /* WM_LBUTTONDOWN and friends handle button swapping for us. No need to check SM_SWAPBUTTON here. */ + WIN_CheckWParamMouseButton((wParam & MK_LBUTTON), mouseFlags, SDL_FALSE, data, SDL_BUTTON_LEFT, mouseID); + WIN_CheckWParamMouseButton((wParam & MK_MBUTTON), mouseFlags, SDL_FALSE, data, SDL_BUTTON_MIDDLE, mouseID); + WIN_CheckWParamMouseButton((wParam & MK_RBUTTON), mouseFlags, SDL_FALSE, data, SDL_BUTTON_RIGHT, mouseID); + WIN_CheckWParamMouseButton((wParam & MK_XBUTTON1), mouseFlags, SDL_FALSE, data, SDL_BUTTON_X1, mouseID); + WIN_CheckWParamMouseButton((wParam & MK_XBUTTON2), mouseFlags, SDL_FALSE, data, SDL_BUTTON_X2, mouseID); + data->mouse_button_flags = wParam; } } @@ -287,26 +299,27 @@ WIN_CheckRawMouseButtons(ULONG rawButtons, SDL_WindowData *data) { if (rawButtons != data->mouse_button_flags) { Uint32 mouseFlags = SDL_GetMouseState(NULL, NULL); + SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0; if ((rawButtons & RI_MOUSE_BUTTON_1_DOWN)) - WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_1_DOWN), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0); + WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_1_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_LEFT, 0); if ((rawButtons & RI_MOUSE_BUTTON_1_UP)) - WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_1_UP), (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0); + WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_1_UP), mouseFlags, swapButtons, data, SDL_BUTTON_LEFT, 0); if ((rawButtons & RI_MOUSE_BUTTON_2_DOWN)) - WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_2_DOWN), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0); + WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_2_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_RIGHT, 0); if ((rawButtons & RI_MOUSE_BUTTON_2_UP)) - WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_2_UP), (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0); + WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_2_UP), mouseFlags, swapButtons, data, SDL_BUTTON_RIGHT, 0); if ((rawButtons & RI_MOUSE_BUTTON_3_DOWN)) - WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_3_DOWN), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0); + WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_3_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_MIDDLE, 0); if ((rawButtons & RI_MOUSE_BUTTON_3_UP)) - WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_3_UP), (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0); + WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_3_UP), mouseFlags, swapButtons, data, SDL_BUTTON_MIDDLE, 0); if ((rawButtons & RI_MOUSE_BUTTON_4_DOWN)) - WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_4_DOWN), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0); + WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_4_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_X1, 0); if ((rawButtons & RI_MOUSE_BUTTON_4_UP)) - WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_4_UP), (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0); + WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_4_UP), mouseFlags, swapButtons, data, SDL_BUTTON_X1, 0); if ((rawButtons & RI_MOUSE_BUTTON_5_DOWN)) - WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_5_DOWN), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0); + WIN_CheckWParamMouseButton((rawButtons & RI_MOUSE_BUTTON_5_DOWN), mouseFlags, swapButtons, data, SDL_BUTTON_X2, 0); if ((rawButtons & RI_MOUSE_BUTTON_5_UP)) - WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_5_UP), (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0); + WIN_CheckWParamMouseButton(!(rawButtons & RI_MOUSE_BUTTON_5_UP), mouseFlags, swapButtons, data, SDL_BUTTON_X2, 0); data->mouse_button_flags = rawButtons; } } @@ -316,31 +329,33 @@ WIN_CheckAsyncMouseRelease(SDL_WindowData *data) { Uint32 mouseFlags; SHORT keyState; + SDL_bool swapButtons; /* mouse buttons may have changed state here, we need to resync them, but we will get a WM_MOUSEMOVE right away which will fix things up if in non raw mode also */ mouseFlags = SDL_GetMouseState(NULL, NULL); + swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0; keyState = GetAsyncKeyState(VK_LBUTTON); if (!(keyState & 0x8000)) { - WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_LMASK), data, SDL_BUTTON_LEFT, 0); + WIN_CheckWParamMouseButton(SDL_FALSE, mouseFlags, swapButtons, data, SDL_BUTTON_LEFT, 0); } keyState = GetAsyncKeyState(VK_RBUTTON); if (!(keyState & 0x8000)) { - WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_RMASK), data, SDL_BUTTON_RIGHT, 0); + WIN_CheckWParamMouseButton(SDL_FALSE, mouseFlags, swapButtons, data, SDL_BUTTON_RIGHT, 0); } keyState = GetAsyncKeyState(VK_MBUTTON); if (!(keyState & 0x8000)) { - WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_MMASK), data, SDL_BUTTON_MIDDLE, 0); + WIN_CheckWParamMouseButton(SDL_FALSE, mouseFlags, swapButtons, data, SDL_BUTTON_MIDDLE, 0); } keyState = GetAsyncKeyState(VK_XBUTTON1); if (!(keyState & 0x8000)) { - WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X1MASK), data, SDL_BUTTON_X1, 0); + WIN_CheckWParamMouseButton(SDL_FALSE, mouseFlags, swapButtons, data, SDL_BUTTON_X1, 0); } keyState = GetAsyncKeyState(VK_XBUTTON2); if (!(keyState & 0x8000)) { - WIN_CheckWParamMouseButton(SDL_FALSE, (mouseFlags & SDL_BUTTON_X2MASK), data, SDL_BUTTON_X2, 0); + WIN_CheckWParamMouseButton(SDL_FALSE, mouseFlags, swapButtons, data, SDL_BUTTON_X2, 0); } data->mouse_button_flags = 0; } @@ -485,11 +500,12 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) break; } if (LOWORD(wParam) == WA_CLICKACTIVE) { + SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0; if (GetAsyncKeyState(VK_LBUTTON)) { - data->focus_click_pending |= SDL_BUTTON_LMASK; + data->focus_click_pending |= !swapButtons ? SDL_BUTTON_LMASK : SDL_BUTTON_RMASK; } if (GetAsyncKeyState(VK_RBUTTON)) { - data->focus_click_pending |= SDL_BUTTON_RMASK; + data->focus_click_pending |= !swapButtons ? SDL_BUTTON_RMASK : SDL_BUTTON_LMASK; } if (GetAsyncKeyState(VK_MBUTTON)) { data->focus_click_pending |= SDL_BUTTON_MMASK; @@ -658,9 +674,11 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) /* 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, 0, 0, (int)pt.x, (int)pt.y); - SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_LEFT); - SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_RIGHT); + SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_LEFT : SDL_BUTTON_RIGHT); + SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, !swapButtons ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT); SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_MIDDLE); SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X1); SDL_SendMouseButton(data->window, 0, GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_PRESSED : SDL_RELEASED, SDL_BUTTON_X2); diff --git a/src/video/windows/SDL_windowsmouse.c b/src/video/windows/SDL_windowsmouse.c index 9fdb911cc..ddbdf5348 100644 --- a/src/video/windows/SDL_windowsmouse.c +++ b/src/video/windows/SDL_windowsmouse.c @@ -276,12 +276,14 @@ WIN_GetGlobalMouseState(int *x, int *y) { Uint32 retval = 0; POINT pt = { 0, 0 }; + SDL_bool swapButtons = GetSystemMetrics(SM_SWAPBUTTON) != 0; + GetCursorPos(&pt); *x = (int) pt.x; *y = (int) pt.y; - retval |= GetAsyncKeyState(VK_LBUTTON) & 0x8000 ? SDL_BUTTON_LMASK : 0; - retval |= GetAsyncKeyState(VK_RBUTTON) & 0x8000 ? SDL_BUTTON_RMASK : 0; + retval |= GetAsyncKeyState(!swapButtons ? VK_LBUTTON : VK_RBUTTON) & 0x8000 ? SDL_BUTTON_LMASK : 0; + retval |= GetAsyncKeyState(!swapButtons ? VK_RBUTTON : VK_LBUTTON) & 0x8000 ? SDL_BUTTON_RMASK : 0; retval |= GetAsyncKeyState(VK_MBUTTON) & 0x8000 ? SDL_BUTTON_MMASK : 0; retval |= GetAsyncKeyState(VK_XBUTTON1) & 0x8000 ? SDL_BUTTON_X1MASK : 0; retval |= GetAsyncKeyState(VK_XBUTTON2) & 0x8000 ? SDL_BUTTON_X2MASK : 0;