From 037e14dd07aba0b03579ea74d0e7915fed99b6d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 11 Oct 2024 15:22:19 +0200 Subject: [PATCH] macOS: Add support for context menu keyboard hotkey MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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ø Reviewed-by: Ulf Hermann Reviewed-by: Volker Hilsheimer (cherry picked from commit e7c8c2ccc859f8083fb3bf442647b0a315cf1b60) Reviewed-by: Qt Cherry-pick Bot --- src/plugins/platforms/cocoa/qnsview_keys.mm | 19 ++++++++++ src/plugins/platforms/cocoa/qnsview_menus.mm | 37 ++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm index abee622e65f..aa224682d50 100644 --- a/src/plugins/platforms/cocoa/qnsview_keys.mm +++ b/src/plugins/platforms/cocoa/qnsview_keys.mm @@ -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 // ------------------------------------------------------------------------- diff --git a/src/plugins/platforms/cocoa/qnsview_menus.mm b/src/plugins/platforms/cocoa/qnsview_menus.mm index 28409369756..9c3121ab387 100644 --- a/src/plugins/platforms/cocoa/qnsview_menus.mm +++ b/src/plugins/platforms/cocoa/qnsview_menus.mm @@ -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 ()