macOS: Add support for context menu keyboard hotkey

macOS 15 introduced the ability to trigger context menus via a keyboard
hotkey (Ctrl+Return by default). We now catch this hotkey, propagate it
as a normal key event first (in case the application wants to handle it
by itself), and trigger a QContextMenuEvent if the system determines that
the action should result in a context menu.

[ChangeLog][macOS] The context menu keyboard hotkey available on macOS
15 is now propagated as a QContextMenuEvent if the corresponding
QKeyEvent is not accepted.

Task-number: QTBUG-67331
Change-Id: I3a64a9a18d2caf767fc32637d314a06465aae88f
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit e7c8c2ccc859f8083fb3bf442647b0a315cf1b60)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Tor Arne Vestbø 2024-10-11 15:22:19 +02:00 committed by Qt Cherry-pick Bot
parent 2997feb230
commit 037e14dd07
2 changed files with 56 additions and 0 deletions

View File

@ -250,6 +250,25 @@ static bool sendAsShortcut(const KeyEvent &keyEvent, QWindow *window)
}
}
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(150000)
- (void)contextMenuKeyDown:(NSEvent *)nsevent
{
qCDebug(lcQpaKeys) << "Handling context menu key down for" << nsevent;
if ([self isTransparentForUserInput])
return [super contextMenuKeyDown:nsevent];
if ([self handleKeyEvent:nsevent]) {
qCDebug(lcQpaKeys) << "Accepted context menu event as regular key down";
m_acceptedKeyDowns.insert(nsevent.keyCode);
} else {
// Forward up the responder chain to trigger default system
// behavior of calling showContextMenuForSelection.
[super contextMenuKeyDown:nsevent];
}
}
#endif
@end
// -------------------------------------------------------------------------

View File

@ -39,6 +39,43 @@
return [super supplementalTargetForAction:action sender:sender];
}
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(150000)
- (void)showContextMenuForSelection:(id)sender
{
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[NSEvent mouseLocation]
toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
auto *keyMapper = QCocoaIntegration::instance()->keyMapper();
auto keyboardModifiers = keyMapper->queryKeyboardModifiers();
// We currently propagate this as QContextMenuEvent::Reason::Keyboard,
// but we can also get here via an accessibility ShowMenu action, in
// which case QContextMenuEvent::Reason::Other reason might fit better.
// Unfortunately QWSI/QGuiApplication/QWidgetWindow doesn't handle that
// yet. FIXME: Teach other parts of Qt about QContextMenuEvent::Other.
const bool mouseTriggered = false;
qCDebug(lcQpaMenus) << "Initiating context menu at"
<< windowPoint.toPoint() << "in" << m_platformWindow
<< "with" << keyboardModifiers;
bool accepted = QWindowSystemInterface::handleContextMenuEvent<
QWindowSystemInterface::SynchronousDelivery>(
m_platformWindow->window(), mouseTriggered,
windowPoint.toPoint(), screenPoint.toPoint(),
keyboardModifiers);
qCDebug(lcQpaMenus) << "Context menu event accepted =" << accepted;
// If the view does not support a context menu we should pass
// the request up the responder chain.
if (!accepted)
[[self nextResponder] tryToPerform:_cmd with:sender];
}
#endif
@end
@interface QNSViewMenuHelper ()