Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-26139

copy/past shortcuts don't work if AA_MacPluginApplication is set

    XMLWordPrintable

Details

    • Bug
    • Resolution: Incomplete
    • Not Evaluated
    • None
    • 4.8.1
    • None
    • MacOSX cocoa (tested on 10.7.3, but not restricted to that platform)

    Description

      If you use (cocoa-based) Qt in a plugin for a non Qt application, shortcuts that are present and enabled in a menu item will always execute the menu item (even if the focus widget overrides them).

      In our software, this problem triggers for the copy/past shortcuts in QLineEdit fields. We have a normal document window with Cmd+X/C/V as cut/copy/past shortscuts in the menu items. As well as an 'inspector' tool window that allows to edit properties. The document window is not under our control (cocoa app), the 'inspector' window is a plugin written using Qt.

      Using the shortcuts for cut/copy/paste in the edit fields in the 'inspector' window only works when the corresponding menu item is disabled (ex: no selection in the document).

      I made a small sample application (attached) that can be build with Qt Creator to reproduce this issue. It has a cocoa based menu item (Cmd+X) in the main menu bar and some qt based menu items in the main window. If the menu item is triggered, a message is displayed. The window has two components, a QLineEdit and QCheckBox. If the checkbox has the focus Cmd+X/C/V brings up the message.
      If the line edit has focus, Cmd+C/V does copy/paste. However Cmd+X still shows the message instead of cutting the selected text.

      After some digging I found out that Cmd+Key shortcuts are called keyEquivalents in cocoa and are handled differently from normal keyDown events. The key equivalent is first passed to the key window (and sub views), if that one doesn't handle it, it is passed to the menu items, and if none of those handle it, it is passed to the first responder (and down the responder chain).

      (see https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/EventOverview/HandlingKeyEvents/HandlingKeyEvents.html#//apple_ref/doc/uid/10000060i-CH7-SW1,
      Handling Key Equivalents).

      In normal cocoa, the NSView objects listens to key equivalents.
      However Qt doesn't use those native components, instead the menu item forwards this message to the focus widget when necessary (see QCocoaMenu, menuHasKeyEquivalent).

      This means that when the menu isn't managed by Qt, key equivalents are never delivered to the focus widget. The problem can be fixed for Qt managed windows by forwarding the key equivalents when they are passed to the window instead of waiting until they are passed to the menu.

      Adding the following method to qcocoasharedwindowmethods_mac.h does the trick:
      (you need to make qt_sendSpontaneousEvent, qt_dispatchKeyEvent and cocoaKey2QtKey available to make it build though)

      • (BOOL)performKeyEquivalent:(NSEvent *)event
        {
        // Qt doesn't use cocoa native widgets, so key equivalents
        // like Cmd+X/C/V for 'cut/copy/paste' for widgets like QLineEdit
        // are not handled by default. We pass these along to the focus widget if necessary.
        // note: Similar code in QCocoaMenu, menuHasKeyEquivalent,
        // however that code isn't triggered when the menu items aren't handled by Qt
        // (for example when using Qt as a plugin).

      QWidget *widget = 0;
      if (qApp->activePopupWidget())
      widget = (qApp->activePopupWidget()->focusWidget()
      ? qApp->activePopupWidget()->focusWidget()
      : qApp->activePopupWidget());
      else if (QApplicationPrivate::focus_widget)
      widget = QApplicationPrivate::focus_widget;
      // If we could not find any receivers, pass it to the active window
      if (!widget)
      widget = qApp->activeWindow();

      if ( widget )
      {
      NSString *keyChars = [event charactersIgnoringModifiers];
      if ([keyChars length] == 1)
      {
      QChar ch([keyChars characterAtIndex:0]);
      if (ch.isLower())
      ch = ch.toUpper();
      Qt::Key qtKey = cocoaKey2QtKey(ch);
      Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([event modifierFlags]);

      QKeyEvent accel_ev(QEvent::ShortcutOverride, qtKey, keyMods);
      accel_ev.ignore();
      qt_sendSpontaneousEvent(widget, &accel_ev);
      if (accel_ev.isAccepted())

      { // The focus widget overrides the behavior of the shortcut, // send the right key event to the widget and block others // from using it. qt_dispatchKeyEvent(event, widget); return YES; }

      }
      }

      return [super performKeyEquivalent:event];
      }

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            Unassigned Unassigned
            bramt@enfocus.be Bram Tassyns
            Votes:
            1 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes