From 126c2cb8fbb50848a5006fd25e83b8afc7b3e781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 4 Sep 2015 17:56:30 +0200 Subject: [PATCH] Clean up cancel operation handling on OS X MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The logic for handling cancel operations was spread out through the code base and sometimes hard-coded to only include the Escape key shortcut, missing the Command+. shortcut. We now intercept both attempts at cancel operations from the system through cancelOperation, which we forward as normal key events. A new QKeySequence::StandardKey has been added for the Cancel sequence, which maps to Escape on all platforms, and Command+. in addition for OS X. The hard-coded logic in QWidget and subclasses for dealing with closing the dialogs has been replaced with this key sequence, which allows clients to override the behavior. Note that the widget code is not wrapped in checks for QT_NO_SHORTCUT, as we don't care about keeping widgets building and working under that define. The logic in QCocoaWindow to bypass windowShouldClose when delivering IM events has been removed as we now handle that specific case by also forwarding Escape as a cancel operation. Task-number: QTBUG-47557 Task-number: QTBUG-45771 Task-number: QTBUG-44076 Change-Id: Ibe0b3a4819f8659d246a2142dd7d9cd3a826ef78 Reviewed-by: Tim Blechmann Reviewed-by: Morten Johan Sørvig Reviewed-by: Tor Arne Vestbø --- src/gui/kernel/qkeysequence.cpp | 2 + src/gui/kernel/qkeysequence.h | 3 +- src/gui/kernel/qplatformtheme.cpp | 4 +- src/plugins/platforms/cocoa/qcocoawindow.h | 1 - src/plugins/platforms/cocoa/qcocoawindow.mm | 8 ++-- src/plugins/platforms/cocoa/qnsview.h | 2 +- src/plugins/platforms/cocoa/qnsview.mm | 37 ++++++++------- src/widgets/dialogs/qcolordialog.cpp | 8 +--- src/widgets/dialogs/qdialog.cpp | 7 +-- src/widgets/dialogs/qfiledialog.cpp | 11 +++-- src/widgets/dialogs/qmessagebox.cpp | 7 +-- src/widgets/dialogs/qprogressdialog.cpp | 3 +- .../itemviews/qabstractitemdelegate.cpp | 12 ++--- src/widgets/kernel/qwhatsthis.cpp | 2 +- src/widgets/kernel/qwidget.cpp | 5 ++- src/widgets/util/qcompleter.cpp | 6 ++- src/widgets/widgets/qabstractbutton.cpp | 8 ++-- src/widgets/widgets/qcalendarwidget.cpp | 5 +-- src/widgets/widgets/qcombobox.cpp | 15 ++++--- src/widgets/widgets/qdatetimeedit.cpp | 2 +- src/widgets/widgets/qeffects.cpp | 2 +- src/widgets/widgets/qmenu.cpp | 45 ++++++++++--------- src/widgets/widgets/qmenubar.cpp | 12 ++--- 23 files changed, 106 insertions(+), 101 deletions(-) diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index ffa9b87147..881d7cc76a 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -291,6 +291,7 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni \row \li InsertParagraphSeparator \li Enter \li Enter \li Enter \li Enter \row \li InsertLineSeparator \li Shift+Enter \li Meta+Enter, Meta+O \li Shift+Enter \li Shift+Enter \row \li Backspace \li (none) \li Meta+H \li (none) \li (none) + \row \li Cancel \li Escape \li Escape, Ctrl+. \li Escape \li Escape \endtable Note that, since the key sequences used for the standard shortcuts differ @@ -752,6 +753,7 @@ static const struct { \value ZoomIn Zoom in. \value ZoomOut Zoom out. \value FullScreen Toggle the window state to/from full screen. + \value Cancel Cancel the current operation. */ /*! diff --git a/src/gui/kernel/qkeysequence.h b/src/gui/kernel/qkeysequence.h index d6171c86f2..98a611aab5 100644 --- a/src/gui/kernel/qkeysequence.h +++ b/src/gui/kernel/qkeysequence.h @@ -137,7 +137,8 @@ public: FullScreen, Deselect, DeleteCompleteLine, - Backspace + Backspace, + Cancel }; Q_ENUM(StandardKey) diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index 36a71fe2da..ce8548f628 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -323,7 +323,9 @@ const QKeyBinding QPlatformThemePrivate::keyBindings[] = { {QKeySequence::FullScreen, 1, Qt::Key_F11, KB_Win | KB_KDE}, {QKeySequence::Deselect, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_A, KB_X11}, {QKeySequence::DeleteCompleteLine, 0, Qt::CTRL | Qt::Key_U, KB_X11}, - {QKeySequence::Backspace, 0, Qt::META | Qt::Key_H, KB_Mac} + {QKeySequence::Backspace, 0, Qt::META | Qt::Key_H, KB_Mac}, + {QKeySequence::Cancel, 0, Qt::Key_Escape, KB_All}, + {QKeySequence::Cancel, 0, Qt::CTRL | Qt::Key_Period, KB_Mac} }; const uint QPlatformThemePrivate::numberOfKeyBindings = sizeof(QPlatformThemePrivate::keyBindings)/(sizeof(QKeyBinding)); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 51679116b5..05e6cf3c9e 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -270,7 +270,6 @@ public: // for QNSView QPointer m_enterLeaveTargetWindow; bool m_windowUnderMouse; - bool m_ignoreWindowShouldClose; bool m_inConstructor; bool m_inSetVisible; bool m_inSetGeometry; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 5606f050a3..8a8e03d283 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -345,7 +345,6 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_synchedWindowState(Qt::WindowActive) , m_windowModality(Qt::NonModal) , m_windowUnderMouse(false) - , m_ignoreWindowShouldClose(false) , m_inConstructor(true) , m_inSetVisible(false) , m_inSetGeometry(false) @@ -1219,9 +1218,10 @@ void QCocoaWindow::windowDidEndLiveResize() bool QCocoaWindow::windowShouldClose() { - // might have been set from qnsview.mm - if (m_ignoreWindowShouldClose) - return false; + // This callback should technically only determine if the window + // should (be allowed to) close, but since our QPA API to determine + // that also involves actually closing the window we do both at the + // same time, instead of doing the latter in windowWillClose. bool accepted = false; QWindowSystemInterface::handleCloseEvent(window(), &accepted); QWindowSystemInterface::flushWindowSystemEvents(); diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 14a61554a3..028a34af1c 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -76,6 +76,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); bool m_resendKeyEvent; bool m_scrolling; bool m_exposedOnMoveToWindow; + NSEvent *m_currentlyInterpretedKeyEvent; } - (id)init; @@ -131,7 +132,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); - (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType; - (void)keyDown:(NSEvent *)theEvent; - (void)keyUp:(NSEvent *)theEvent; -- (BOOL)performKeyEquivalent:(NSEvent *)theEvent; - (void)registerDragTypes; - (NSDragOperation)handleDrag:(id )sender; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 4db55c1b73..7da0c4d402 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -152,6 +152,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self]; m_resendKeyEvent = false; m_scrolling = false; + m_currentlyInterpretedKeyEvent = 0; if (!touchDevice) { touchDevice = new QTouchDevice; @@ -1449,21 +1450,17 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) QObject *fo = QGuiApplication::focusObject(); if (m_sendKeyEvent && fo) { - // if escape is pressed we don't want interpretKeyEvents to close a dialog. This will be done via QWindowSystemInterface - if (keyCode == Qt::Key_Escape) - m_platformWindow->m_ignoreWindowShouldClose = true; - QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints); if (QCoreApplication::sendEvent(fo, &queryEvent)) { bool imEnabled = queryEvent.value(Qt::ImEnabled).toBool(); Qt::InputMethodHints hints = static_cast(queryEvent.value(Qt::ImHints).toUInt()); if (imEnabled && !(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || hints & Qt::ImhHiddenText)) { // pass the key event to the input method. note that m_sendKeyEvent may be set to false during this call + m_currentlyInterpretedKeyEvent = nsevent; [self interpretKeyEvents:[NSArray arrayWithObject:nsevent]]; + m_currentlyInterpretedKeyEvent = 0; } } - - m_platformWindow->m_ignoreWindowShouldClose = false;; } if (m_resendKeyEvent) m_sendKeyEvent = true; @@ -1491,21 +1488,23 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)]; } -- (BOOL)performKeyEquivalent:(NSEvent *)nsevent +- (void)cancelOperation:(id)sender { - NSString *chars = [nsevent charactersIgnoringModifiers]; + Q_UNUSED(sender); - if ([nsevent type] == NSKeyDown && [chars length] > 0) { - QChar ch = [chars characterAtIndex:0]; - Qt::Key qtKey = qt_mac_cocoaKey2QtKey(ch); - // check for Command + Key_Period - if ([nsevent modifierFlags] & NSCommandKeyMask - && qtKey == Qt::Key_Period) { - [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)]; - return YES; - } - } - return [super performKeyEquivalent:nsevent]; + NSEvent *currentEvent = [NSApp currentEvent]; + if (!currentEvent || currentEvent.type != NSKeyDown) + return; + + // Handling the key event may recurse back here through interpretKeyEvents + // (when IM is enabled), so we need to guard against that. + if (currentEvent == m_currentlyInterpretedKeyEvent) + return; + + // Send Command+Key_Period and Escape as normal keypresses so that + // the key sequence is delivered through Qt. That way clients can + // intercept the shortcut and override its effect. + [self handleKeyEvent:currentEvent eventType:int(QEvent::KeyPress)]; } - (void)flagsChanged:(NSEvent *)nsevent diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index 2ebbaaee10..468bffe49e 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -2286,16 +2286,12 @@ bool QColorDialogPrivate::handleColorPickingMouseButtonRelease(QMouseEvent *e) bool QColorDialogPrivate::handleColorPickingKeyPress(QKeyEvent *e) { Q_Q(QColorDialog); - switch (e->key()) { - case Qt::Key_Escape: + if (e->matches(QKeySequence::Cancel)) { releaseColorPicking(); q->setCurrentColor(beforeScreenColorPicking); - break; - case Qt::Key_Return: - case Qt::Key_Enter: + } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { q->setCurrentColor(grabScreenColor(QCursor::pos())); releaseColorPicking(); - break; } e->accept(); return true; diff --git a/src/widgets/dialogs/qdialog.cpp b/src/widgets/dialogs/qdialog.cpp index d04241fee0..5124960ab4 100644 --- a/src/widgets/dialogs/qdialog.cpp +++ b/src/widgets/dialogs/qdialog.cpp @@ -651,11 +651,9 @@ void QDialog::keyPressEvent(QKeyEvent *e) // Calls reject() if Escape is pressed. Simulates a button // click for the default button if Enter is pressed. Move focus // for the arrow keys. Ignore the rest. -#ifdef Q_OS_MAC - if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) { + if (e->matches(QKeySequence::Cancel)) { reject(); } else -#endif if (!e->modifiers() || (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) { switch (e->key()) { case Qt::Key_Enter: @@ -671,9 +669,6 @@ void QDialog::keyPressEvent(QKeyEvent *e) } } break; - case Qt::Key_Escape: - reject(); - break; default: e->ignore(); return; diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp index 81beccd5c8..ee2b1e6dae 100644 --- a/src/widgets/dialogs/qfiledialog.cpp +++ b/src/widgets/dialogs/qfiledialog.cpp @@ -3778,6 +3778,12 @@ void QFileDialogPrivate::_q_nativeEnterDirectory(const QUrl &directory) bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) { Q_Q(QFileDialog); + + if (event->matches(QKeySequence::Cancel)) { + q->hide(); + return true; + } + switch (event->key()) { case Qt::Key_Backspace: _q_navigateToParent(); @@ -3793,9 +3799,6 @@ bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) { return true; } break; - case Qt::Key_Escape: - q->hide(); - return true; default: break; } @@ -3982,7 +3985,7 @@ void QFileDialogLineEdit::keyPressEvent(QKeyEvent *e) int key = e->key(); QLineEdit::keyPressEvent(e); - if (key != Qt::Key_Escape && key != Qt::Key_Back) + if (!e->matches(QKeySequence::Cancel) && key != Qt::Key_Back) e->accept(); } diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp index ef9b55acd6..8a48100ea7 100644 --- a/src/widgets/dialogs/qmessagebox.cpp +++ b/src/widgets/dialogs/qmessagebox.cpp @@ -1450,11 +1450,8 @@ void QMessageBox::changeEvent(QEvent *ev) void QMessageBox::keyPressEvent(QKeyEvent *e) { Q_D(QMessageBox); - if (e->key() == Qt::Key_Escape -#ifdef Q_OS_MAC - || (e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) -#endif - ) { + + if (e->matches(QKeySequence::Cancel)) { if (d->detectedEscapeButton) { #ifdef Q_OS_MAC d->detectedEscapeButton->animateClick(); diff --git a/src/widgets/dialogs/qprogressdialog.cpp b/src/widgets/dialogs/qprogressdialog.cpp index 97e9267a9d..bbb251c8b2 100644 --- a/src/widgets/dialogs/qprogressdialog.cpp +++ b/src/widgets/dialogs/qprogressdialog.cpp @@ -411,7 +411,8 @@ void QProgressDialog::setCancelButton(QPushButton *cancelButton) if (cancelButton) { connect(d->cancel, SIGNAL(clicked()), this, SIGNAL(canceled())); #ifndef QT_NO_SHORTCUT - d->escapeShortcut = new QShortcut(Qt::Key_Escape, this, SIGNAL(canceled())); + // FIXME: This only registers the primary key sequence of the cancel action + d->escapeShortcut = new QShortcut(QKeySequence::Cancel, this, SIGNAL(canceled())); #endif } else { #ifndef QT_NO_SHORTCUT diff --git a/src/widgets/itemviews/qabstractitemdelegate.cpp b/src/widgets/itemviews/qabstractitemdelegate.cpp index 6efe5ccb71..c2dd1ec8fd 100644 --- a/src/widgets/itemviews/qabstractitemdelegate.cpp +++ b/src/widgets/itemviews/qabstractitemdelegate.cpp @@ -455,6 +455,12 @@ bool QAbstractItemDelegatePrivate::editorEventFilter(QObject *object, QEvent *ev if (editorHandlesKeyEvent(editor, keyEvent)) return false; + if (keyEvent->matches(QKeySequence::Cancel)) { + // don't commit data + emit q->closeEditor(editor, QAbstractItemDelegate::RevertModelCache); + return true; + } + switch (keyEvent->key()) { case Qt::Key_Tab: if (tryFixup(editor)) { @@ -479,10 +485,6 @@ bool QAbstractItemDelegatePrivate::editorEventFilter(QObject *object, QEvent *ev QMetaObject::invokeMethod(q, "_q_commitDataAndCloseEditor", Qt::QueuedConnection, Q_ARG(QWidget*, editor)); return false; - case Qt::Key_Escape: - // don't commit data - emit q->closeEditor(editor, QAbstractItemDelegate::RevertModelCache); - return true; default: return false; } @@ -509,7 +511,7 @@ bool QAbstractItemDelegatePrivate::editorEventFilter(QObject *object, QEvent *ev emit q->closeEditor(editor, QAbstractItemDelegate::NoHint); } } else if (event->type() == QEvent::ShortcutOverride) { - if (static_cast(event)->key() == Qt::Key_Escape) { + if (static_cast(event)->matches(QKeySequence::Cancel)) { event->accept(); return true; } diff --git a/src/widgets/kernel/qwhatsthis.cpp b/src/widgets/kernel/qwhatsthis.cpp index 1e437c4fb7..81de2f25ca 100644 --- a/src/widgets/kernel/qwhatsthis.cpp +++ b/src/widgets/kernel/qwhatsthis.cpp @@ -459,7 +459,7 @@ bool QWhatsThisPrivate::eventFilter(QObject *o, QEvent *e) { QKeyEvent* kev = (QKeyEvent*)e; - if (kev->key() == Qt::Key_Escape) { + if (kev->matches(QKeySequence::Cancel)) { QWhatsThis::leaveWhatsThisMode(); return true; } else if (customWhatsThis) { diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 2c9cc5c07b..66c86a7bce 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -9349,7 +9349,8 @@ void QWidget::tabletEvent(QTabletEvent *event) call the base class implementation if you do not act upon the key. The default implementation closes popup widgets if the user - presses Esc. Otherwise the event is ignored, so that the widget's + presses the key sequence for QKeySequence::Cancel (typically the + Escape key). Otherwise the event is ignored, so that the widget's parent can interpret it. Note that QKeyEvent starts with isAccepted() == true, so you do not @@ -9362,7 +9363,7 @@ void QWidget::tabletEvent(QTabletEvent *event) void QWidget::keyPressEvent(QKeyEvent *event) { - if ((windowType() == Qt::Popup) && event->key() == Qt::Key_Escape) { + if ((windowType() == Qt::Popup) && event->matches(QKeySequence::Cancel)) { event->accept(); close(); } else { diff --git a/src/widgets/util/qcompleter.cpp b/src/widgets/util/qcompleter.cpp index fedc928f61..559f024e5f 100644 --- a/src/widgets/util/qcompleter.cpp +++ b/src/widgets/util/qcompleter.cpp @@ -1337,6 +1337,11 @@ bool QCompleter::eventFilter(QObject *o, QEvent *e) } // default implementation for keys not handled by the widget when popup is open + if (ke->matches(QKeySequence::Cancel)) { + d->popup->hide(); + return true; + } + switch (key) { #ifdef QT_KEYPAD_NAVIGATION case Qt::Key_Select: @@ -1357,7 +1362,6 @@ bool QCompleter::eventFilter(QObject *o, QEvent *e) break; case Qt::Key_Backtab: - case Qt::Key_Escape: d->popup->hide(); break; diff --git a/src/widgets/widgets/qabstractbutton.cpp b/src/widgets/widgets/qabstractbutton.cpp index 292bbc3325..a1707b9cab 100644 --- a/src/widgets/widgets/qabstractbutton.cpp +++ b/src/widgets/widgets/qabstractbutton.cpp @@ -1221,16 +1221,14 @@ void QAbstractButton::keyPressEvent(QKeyEvent *e) } break; } - case Qt::Key_Escape: - if (d->down) { + default: + if (e->matches(QKeySequence::Cancel) && d->down) { setDown(false); repaint(); //flush paint event before invoking potentially expensive operation QApplication::flush(); d->emitReleased(); - break; + return; } - // fall through - default: e->ignore(); } } diff --git a/src/widgets/widgets/qcalendarwidget.cpp b/src/widgets/widgets/qcalendarwidget.cpp index 2150fc7a50..48b224fe13 100644 --- a/src/widgets/widgets/qcalendarwidget.cpp +++ b/src/widgets/widgets/qcalendarwidget.cpp @@ -776,7 +776,7 @@ bool QCalendarTextNavigator::eventFilter(QObject *o, QEvent *e) applyDate(); emit editingFinished(); removeDateLabel(); - } else if (ke->key() == Qt::Key_Escape) { + } else if (ke->matches(QKeySequence::Cancel)) { removeDateLabel(); } else if (e->type() == QEvent::KeyPress) { createDateLabel(); @@ -3078,8 +3078,7 @@ void QCalendarWidget::resizeEvent(QResizeEvent * event) void QCalendarWidget::keyPressEvent(QKeyEvent * event) { Q_D(QCalendarWidget); - if(d->yearEdit->isVisible()&& event->key() == Qt::Key_Escape) - { + if (d->yearEdit->isVisible()&& event->matches(QKeySequence::Cancel)) { d->yearEdit->setValue(yearShown()); d->_q_yearEditingFinished(); return; diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp index 89fd3d3d57..aab28bf18a 100644 --- a/src/widgets/widgets/qcombobox.cpp +++ b/src/widgets/widgets/qcombobox.cpp @@ -654,8 +654,9 @@ void QComboBoxPrivateContainer::changeEvent(QEvent *e) bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e) { switch (e->type()) { - case QEvent::ShortcutOverride: - switch (static_cast(e)->key()) { + case QEvent::ShortcutOverride: { + QKeyEvent *keyEvent = static_cast(e); + switch (keyEvent->key()) { case Qt::Key_Enter: case Qt::Key_Return: #ifdef QT_KEYPAD_NAVIGATION @@ -667,17 +668,21 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e) } return true; case Qt::Key_Down: - if (!(static_cast(e)->modifiers() & Qt::AltModifier)) + if (!(keyEvent->modifiers() & Qt::AltModifier)) break; // fall through case Qt::Key_F4: - case Qt::Key_Escape: combo->hidePopup(); return true; default: + if (keyEvent->matches(QKeySequence::Cancel)) { + combo->hidePopup(); + return true; + } break; } - break; + break; + } case QEvent::MouseMove: if (isVisible()) { QMouseEvent *m = static_cast(e); diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp index a8da78a025..42987df3ec 100644 --- a/src/widgets/widgets/qdatetimeedit.cpp +++ b/src/widgets/widgets/qdatetimeedit.cpp @@ -2655,7 +2655,7 @@ bool QCalendarPopup::event(QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); - if (keyEvent->key()== Qt::Key_Escape) + if (keyEvent->matches(QKeySequence::Cancel)) dateChanged = false; } return QWidget::event(event); diff --git a/src/widgets/widgets/qeffects.cpp b/src/widgets/widgets/qeffects.cpp index 708e90cc32..b256861d08 100644 --- a/src/widgets/widgets/qeffects.cpp +++ b/src/widgets/widgets/qeffects.cpp @@ -197,7 +197,7 @@ bool QAlphaWidget::eventFilter(QObject *o, QEvent *e) break; case QEvent::KeyPress: { QKeyEvent *ke = (QKeyEvent*)e; - if (ke->key() == Qt::Key_Escape) { + if (ke->matches(QKeySequence::Cancel)) { showWidget = false; } else { duration = 0; diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 0556c02b64..6e37f91197 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -2679,7 +2679,7 @@ QMenu::event(QEvent *e) if (kev->key() == Qt::Key_Up || kev->key() == Qt::Key_Down || kev->key() == Qt::Key_Left || kev->key() == Qt::Key_Right || kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return - || kev->key() == Qt::Key_Escape) { + || kev->matches(QKeySequence::Cancel)) { e->accept(); return true; } @@ -2965,27 +2965,6 @@ void QMenu::keyPressEvent(QKeyEvent *e) } break; - case Qt::Key_Escape: -#ifdef QT_KEYPAD_NAVIGATION - case Qt::Key_Back: -#endif - key_consumed = true; - if (d->tornoff) { - close(); - return; - } - { - QPointer caused = d->causedPopup.widget; - d->hideMenu(this); // hide after getting causedPopup -#ifndef QT_NO_MENUBAR - if (QMenuBar *mb = qobject_cast(caused)) { - mb->d_func()->setCurrentAction(d->menuAction); - mb->d_func()->setKeyboardMode(true); - } -#endif - } - break; - case Qt::Key_Space: if (!style()->styleHint(QStyle::SH_Menu_SpaceActivatesItem, 0, this)) break; @@ -3022,6 +3001,28 @@ void QMenu::keyPressEvent(QKeyEvent *e) key_consumed = false; } + if (!key_consumed && (e->matches(QKeySequence::Cancel) +#ifdef QT_KEYPAD_NAVIGATION + || e->key() == Qt::Key_Back +#endif + )) { + key_consumed = true; + if (d->tornoff) { + close(); + return; + } + { + QPointer caused = d->causedPopup.widget; + d->hideMenu(this); // hide after getting causedPopup +#ifndef QT_NO_MENUBAR + if (QMenuBar *mb = qobject_cast(caused)) { + mb->d_func()->setCurrentAction(d->menuAction); + mb->d_func()->setKeyboardMode(true); + } +#endif + } + } + if (!key_consumed) { // send to menu bar if ((!e->modifiers() || e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ShiftModifier) && e->text().length()==1) { diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp index d382131075..2e48607f82 100644 --- a/src/widgets/widgets/qmenubar.cpp +++ b/src/widgets/widgets/qmenubar.cpp @@ -1122,14 +1122,14 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) } break; } - case Qt::Key_Escape: + default: + key_consumed = false; + } + + if (!key_consumed && e->matches(QKeySequence::Cancel)) { d->setCurrentAction(0); d->setKeyboardMode(false); key_consumed = true; - break; - - default: - key_consumed = false; } if(!key_consumed && @@ -1432,7 +1432,7 @@ bool QMenuBar::event(QEvent *e) case QEvent::ShortcutOverride: { QKeyEvent *kev = static_cast(e); //we only filter out escape if there is a current action - if (kev->key() == Qt::Key_Escape && d->currentAction) { + if (kev->matches(QKeySequence::Cancel) && d->currentAction) { e->accept(); return true; }