WindowsQPA: Make custom titlebar respect swapped mouse buttons

Custom titlebar input handling is done on WM_NCHITTEST, which is handled
at the WinAPI level. The WinAPI does not take into account the swapped
mouse buttons when querying the state of VK_LEFTBUTTON and
VK_RIGHTBUTTON with GetAsyncKeyState, so this behavior has to be
implemented manually. In case of swapped mouse buttons,
GetSystemMetrics(SM_SWAPBUTTON) will return true. This patch inverses
the meaning of Right and Left buttons in case
GetSystemMetrics(SM_SWAPBUTTON) returns true.

Pick-to: 6.9
Change-Id: Ie46e130dc0bb49de318c8d04a3cc426f7a346b5b
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: Zhao Yuhang <2546789017@qq.com>
This commit is contained in:
Wladimir Leuschner 2025-04-04 11:25:14 +02:00
parent a7d8d3ecdd
commit 6273e2e0ed

View File

@ -3313,16 +3313,23 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re
const int titleBarHeight = getTitleBarHeight_sys(savedDpi()); const int titleBarHeight = getTitleBarHeight_sys(savedDpi());
const int titleButtonWidth = titleBarHeight * 1.5; const int titleButtonWidth = titleBarHeight * 1.5;
int buttons = 1; int buttons = 1;
const bool mouseButtonsSwapped = GetSystemMetrics(SM_SWAPBUTTON);
auto mouseButtons = Qt::NoButton;
if (mouseButtonsSwapped)
mouseButtons = GetAsyncKeyState(VK_LBUTTON) != 0 ? Qt::RightButton : (GetAsyncKeyState(VK_RBUTTON) ? Qt::LeftButton : Qt::NoButton);
else
mouseButtons = GetAsyncKeyState(VK_LBUTTON) != 0 ? Qt::LeftButton : (GetAsyncKeyState(VK_RBUTTON) ? Qt::RightButton : Qt::NoButton);
if (globalPos.y() < geom.top() + titleBarHeight) { if (globalPos.y() < geom.top() + titleBarHeight) {
if (m_data.flags.testFlags(Qt::WindowCloseButtonHint) || isDefaultTitleBar) { if (m_data.flags.testFlags(Qt::WindowCloseButtonHint) || isDefaultTitleBar) {
if ((globalPos.x() > geom.right() - titleButtonWidth * buttons) && (globalPos.x() <= geom.right())) { if ((globalPos.x() > geom.right() - titleButtonWidth * buttons) && (globalPos.x() <= geom.right())) {
if (GetAsyncKeyState(VK_LBUTTON)) if (mouseButtons == Qt::LeftButton)
*result = HTCLOSE; *result = HTCLOSE;
} }
buttons++; buttons++;
} if (m_data.flags.testFlags(Qt::WindowMaximizeButtonHint) || isDefaultTitleBar) { } if (m_data.flags.testFlags(Qt::WindowMaximizeButtonHint) || isDefaultTitleBar) {
if ((globalPos.x() > geom.right() - titleButtonWidth * buttons) && (globalPos.x() <= geom.right() - titleButtonWidth * (buttons-1))){ if ((globalPos.x() > geom.right() - titleButtonWidth * buttons) && (globalPos.x() <= geom.right() - titleButtonWidth * (buttons-1))){
if (GetAsyncKeyState(VK_LBUTTON)) { if (mouseButtons == Qt::LeftButton) {
if (IsZoomed(m_data.hwnd)) if (IsZoomed(m_data.hwnd))
*result = HTSIZE; *result = HTSIZE;
else else
@ -3332,18 +3339,17 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re
buttons++; buttons++;
} if (m_data.flags.testFlags(Qt::WindowMinimizeButtonHint) || isDefaultTitleBar) { } if (m_data.flags.testFlags(Qt::WindowMinimizeButtonHint) || isDefaultTitleBar) {
if ((globalPos.x() > geom.right() - titleButtonWidth * buttons) && (globalPos.x() <= geom.right() - titleButtonWidth * (buttons-1))){ if ((globalPos.x() > geom.right() - titleButtonWidth * buttons) && (globalPos.x() <= geom.right() - titleButtonWidth * (buttons-1))){
if (GetAsyncKeyState(VK_LBUTTON)) if (mouseButtons == Qt::LeftButton)
*result = HTMINBUTTON; *result = HTMINBUTTON;
} }
buttons++; buttons++;
} if ((isCustomized || isDefaultTitleBar) && } if ((isCustomized || isDefaultTitleBar) &&
*result == HTCLIENT){ *result == HTCLIENT){
QWindow* wnd = window(); QWindow* wnd = window();
auto buttons = GetAsyncKeyState(VK_LBUTTON) != 0 ? Qt::LeftButton : Qt::NoButton; if (mouseButtons != Qt::NoButton) {
if (buttons != Qt::NoButton) { QMouseEvent event(QEvent::MouseButtonPress, localPos, globalPos, mouseButtons, mouseButtons, Qt::NoModifier);
QMouseEvent event(QEvent::MouseButtonPress, localPos, globalPos, buttons, buttons, Qt::NoModifier);
QGuiApplication::sendEvent(wnd, &event); QGuiApplication::sendEvent(wnd, &event);
if (!event.isAccepted() && GetAsyncKeyState(VK_RBUTTON)) if (!event.isAccepted() && mouseButtons == Qt::RightButton)
*result = HTSYSMENU; *result = HTSYSMENU;
else if (!event.isAccepted()) else if (!event.isAccepted())
*result = HTCAPTION; *result = HTCAPTION;