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.
Cameron Gutman 2020-08-25 21:22:00 -07:00
parent 771732ed32
commit 72379ba510
2 changed files with 49 additions and 29 deletions

View File

@ -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);

View File

@ -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;