Clean up cancel operation handling on OS X

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 <tim@klingt.org>
Reviewed-by: Morten Johan Sørvig <morten.sorvig@theqtcompany.com>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@theqtcompany.com>
This commit is contained in:
Tor Arne Vestbø 2015-09-04 17:56:30 +02:00
parent b2e664df61
commit 126c2cb8fb
23 changed files with 106 additions and 101 deletions

View File

@ -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 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 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 Backspace \li (none) \li Meta+H \li (none) \li (none)
\row \li Cancel \li Escape \li Escape, Ctrl+. \li Escape \li Escape
\endtable \endtable
Note that, since the key sequences used for the standard shortcuts differ Note that, since the key sequences used for the standard shortcuts differ
@ -752,6 +753,7 @@ static const struct {
\value ZoomIn Zoom in. \value ZoomIn Zoom in.
\value ZoomOut Zoom out. \value ZoomOut Zoom out.
\value FullScreen Toggle the window state to/from full screen. \value FullScreen Toggle the window state to/from full screen.
\value Cancel Cancel the current operation.
*/ */
/*! /*!

View File

@ -137,7 +137,8 @@ public:
FullScreen, FullScreen,
Deselect, Deselect,
DeleteCompleteLine, DeleteCompleteLine,
Backspace Backspace,
Cancel
}; };
Q_ENUM(StandardKey) Q_ENUM(StandardKey)

View File

@ -323,7 +323,9 @@ const QKeyBinding QPlatformThemePrivate::keyBindings[] = {
{QKeySequence::FullScreen, 1, Qt::Key_F11, KB_Win | KB_KDE}, {QKeySequence::FullScreen, 1, Qt::Key_F11, KB_Win | KB_KDE},
{QKeySequence::Deselect, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_A, KB_X11}, {QKeySequence::Deselect, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_A, KB_X11},
{QKeySequence::DeleteCompleteLine, 0, Qt::CTRL | Qt::Key_U, 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)); const uint QPlatformThemePrivate::numberOfKeyBindings = sizeof(QPlatformThemePrivate::keyBindings)/(sizeof(QKeyBinding));

View File

@ -270,7 +270,6 @@ public: // for QNSView
QPointer<QWindow> m_enterLeaveTargetWindow; QPointer<QWindow> m_enterLeaveTargetWindow;
bool m_windowUnderMouse; bool m_windowUnderMouse;
bool m_ignoreWindowShouldClose;
bool m_inConstructor; bool m_inConstructor;
bool m_inSetVisible; bool m_inSetVisible;
bool m_inSetGeometry; bool m_inSetGeometry;

View File

@ -345,7 +345,6 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_synchedWindowState(Qt::WindowActive) , m_synchedWindowState(Qt::WindowActive)
, m_windowModality(Qt::NonModal) , m_windowModality(Qt::NonModal)
, m_windowUnderMouse(false) , m_windowUnderMouse(false)
, m_ignoreWindowShouldClose(false)
, m_inConstructor(true) , m_inConstructor(true)
, m_inSetVisible(false) , m_inSetVisible(false)
, m_inSetGeometry(false) , m_inSetGeometry(false)
@ -1219,9 +1218,10 @@ void QCocoaWindow::windowDidEndLiveResize()
bool QCocoaWindow::windowShouldClose() bool QCocoaWindow::windowShouldClose()
{ {
// might have been set from qnsview.mm // This callback should technically only determine if the window
if (m_ignoreWindowShouldClose) // should (be allowed to) close, but since our QPA API to determine
return false; // that also involves actually closing the window we do both at the
// same time, instead of doing the latter in windowWillClose.
bool accepted = false; bool accepted = false;
QWindowSystemInterface::handleCloseEvent(window(), &accepted); QWindowSystemInterface::handleCloseEvent(window(), &accepted);
QWindowSystemInterface::flushWindowSystemEvents(); QWindowSystemInterface::flushWindowSystemEvents();

View File

@ -76,6 +76,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
bool m_resendKeyEvent; bool m_resendKeyEvent;
bool m_scrolling; bool m_scrolling;
bool m_exposedOnMoveToWindow; bool m_exposedOnMoveToWindow;
NSEvent *m_currentlyInterpretedKeyEvent;
} }
- (id)init; - (id)init;
@ -131,7 +132,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
- (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType; - (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType;
- (void)keyDown:(NSEvent *)theEvent; - (void)keyDown:(NSEvent *)theEvent;
- (void)keyUp:(NSEvent *)theEvent; - (void)keyUp:(NSEvent *)theEvent;
- (BOOL)performKeyEquivalent:(NSEvent *)theEvent;
- (void)registerDragTypes; - (void)registerDragTypes;
- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender; - (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender;

View File

@ -152,6 +152,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self]; m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self];
m_resendKeyEvent = false; m_resendKeyEvent = false;
m_scrolling = false; m_scrolling = false;
m_currentlyInterpretedKeyEvent = 0;
if (!touchDevice) { if (!touchDevice) {
touchDevice = new QTouchDevice; touchDevice = new QTouchDevice;
@ -1449,21 +1450,17 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
QObject *fo = QGuiApplication::focusObject(); QObject *fo = QGuiApplication::focusObject();
if (m_sendKeyEvent && fo) { 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); QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints);
if (QCoreApplication::sendEvent(fo, &queryEvent)) { if (QCoreApplication::sendEvent(fo, &queryEvent)) {
bool imEnabled = queryEvent.value(Qt::ImEnabled).toBool(); bool imEnabled = queryEvent.value(Qt::ImEnabled).toBool();
Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt()); Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt());
if (imEnabled && !(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || hints & Qt::ImhHiddenText)) { 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 // 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]]; [self interpretKeyEvents:[NSArray arrayWithObject:nsevent]];
m_currentlyInterpretedKeyEvent = 0;
} }
} }
m_platformWindow->m_ignoreWindowShouldClose = false;;
} }
if (m_resendKeyEvent) if (m_resendKeyEvent)
m_sendKeyEvent = true; m_sendKeyEvent = true;
@ -1491,21 +1488,23 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
[self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)]; [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) { NSEvent *currentEvent = [NSApp currentEvent];
QChar ch = [chars characterAtIndex:0]; if (!currentEvent || currentEvent.type != NSKeyDown)
Qt::Key qtKey = qt_mac_cocoaKey2QtKey(ch); return;
// check for Command + Key_Period
if ([nsevent modifierFlags] & NSCommandKeyMask // Handling the key event may recurse back here through interpretKeyEvents
&& qtKey == Qt::Key_Period) { // (when IM is enabled), so we need to guard against that.
[self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)]; if (currentEvent == m_currentlyInterpretedKeyEvent)
return YES; return;
}
} // Send Command+Key_Period and Escape as normal keypresses so that
return [super performKeyEquivalent:nsevent]; // 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 - (void)flagsChanged:(NSEvent *)nsevent

View File

@ -2286,16 +2286,12 @@ bool QColorDialogPrivate::handleColorPickingMouseButtonRelease(QMouseEvent *e)
bool QColorDialogPrivate::handleColorPickingKeyPress(QKeyEvent *e) bool QColorDialogPrivate::handleColorPickingKeyPress(QKeyEvent *e)
{ {
Q_Q(QColorDialog); Q_Q(QColorDialog);
switch (e->key()) { if (e->matches(QKeySequence::Cancel)) {
case Qt::Key_Escape:
releaseColorPicking(); releaseColorPicking();
q->setCurrentColor(beforeScreenColorPicking); q->setCurrentColor(beforeScreenColorPicking);
break; } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
case Qt::Key_Return:
case Qt::Key_Enter:
q->setCurrentColor(grabScreenColor(QCursor::pos())); q->setCurrentColor(grabScreenColor(QCursor::pos()));
releaseColorPicking(); releaseColorPicking();
break;
} }
e->accept(); e->accept();
return true; return true;

View File

@ -651,11 +651,9 @@ void QDialog::keyPressEvent(QKeyEvent *e)
// Calls reject() if Escape is pressed. Simulates a button // Calls reject() if Escape is pressed. Simulates a button
// click for the default button if Enter is pressed. Move focus // click for the default button if Enter is pressed. Move focus
// for the arrow keys. Ignore the rest. // for the arrow keys. Ignore the rest.
#ifdef Q_OS_MAC if (e->matches(QKeySequence::Cancel)) {
if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) {
reject(); reject();
} else } else
#endif
if (!e->modifiers() || (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) { if (!e->modifiers() || (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) {
switch (e->key()) { switch (e->key()) {
case Qt::Key_Enter: case Qt::Key_Enter:
@ -671,9 +669,6 @@ void QDialog::keyPressEvent(QKeyEvent *e)
} }
} }
break; break;
case Qt::Key_Escape:
reject();
break;
default: default:
e->ignore(); e->ignore();
return; return;

View File

@ -3778,6 +3778,12 @@ void QFileDialogPrivate::_q_nativeEnterDirectory(const QUrl &directory)
bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) { bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) {
Q_Q(QFileDialog); Q_Q(QFileDialog);
if (event->matches(QKeySequence::Cancel)) {
q->hide();
return true;
}
switch (event->key()) { switch (event->key()) {
case Qt::Key_Backspace: case Qt::Key_Backspace:
_q_navigateToParent(); _q_navigateToParent();
@ -3793,9 +3799,6 @@ bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) {
return true; return true;
} }
break; break;
case Qt::Key_Escape:
q->hide();
return true;
default: default:
break; break;
} }
@ -3982,7 +3985,7 @@ void QFileDialogLineEdit::keyPressEvent(QKeyEvent *e)
int key = e->key(); int key = e->key();
QLineEdit::keyPressEvent(e); QLineEdit::keyPressEvent(e);
if (key != Qt::Key_Escape && key != Qt::Key_Back) if (!e->matches(QKeySequence::Cancel) && key != Qt::Key_Back)
e->accept(); e->accept();
} }

View File

@ -1450,11 +1450,8 @@ void QMessageBox::changeEvent(QEvent *ev)
void QMessageBox::keyPressEvent(QKeyEvent *e) void QMessageBox::keyPressEvent(QKeyEvent *e)
{ {
Q_D(QMessageBox); Q_D(QMessageBox);
if (e->key() == Qt::Key_Escape
#ifdef Q_OS_MAC if (e->matches(QKeySequence::Cancel)) {
|| (e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period)
#endif
) {
if (d->detectedEscapeButton) { if (d->detectedEscapeButton) {
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
d->detectedEscapeButton->animateClick(); d->detectedEscapeButton->animateClick();

View File

@ -411,7 +411,8 @@ void QProgressDialog::setCancelButton(QPushButton *cancelButton)
if (cancelButton) { if (cancelButton) {
connect(d->cancel, SIGNAL(clicked()), this, SIGNAL(canceled())); connect(d->cancel, SIGNAL(clicked()), this, SIGNAL(canceled()));
#ifndef QT_NO_SHORTCUT #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 #endif
} else { } else {
#ifndef QT_NO_SHORTCUT #ifndef QT_NO_SHORTCUT

View File

@ -455,6 +455,12 @@ bool QAbstractItemDelegatePrivate::editorEventFilter(QObject *object, QEvent *ev
if (editorHandlesKeyEvent(editor, keyEvent)) if (editorHandlesKeyEvent(editor, keyEvent))
return false; return false;
if (keyEvent->matches(QKeySequence::Cancel)) {
// don't commit data
emit q->closeEditor(editor, QAbstractItemDelegate::RevertModelCache);
return true;
}
switch (keyEvent->key()) { switch (keyEvent->key()) {
case Qt::Key_Tab: case Qt::Key_Tab:
if (tryFixup(editor)) { if (tryFixup(editor)) {
@ -479,10 +485,6 @@ bool QAbstractItemDelegatePrivate::editorEventFilter(QObject *object, QEvent *ev
QMetaObject::invokeMethod(q, "_q_commitDataAndCloseEditor", QMetaObject::invokeMethod(q, "_q_commitDataAndCloseEditor",
Qt::QueuedConnection, Q_ARG(QWidget*, editor)); Qt::QueuedConnection, Q_ARG(QWidget*, editor));
return false; return false;
case Qt::Key_Escape:
// don't commit data
emit q->closeEditor(editor, QAbstractItemDelegate::RevertModelCache);
return true;
default: default:
return false; return false;
} }
@ -509,7 +511,7 @@ bool QAbstractItemDelegatePrivate::editorEventFilter(QObject *object, QEvent *ev
emit q->closeEditor(editor, QAbstractItemDelegate::NoHint); emit q->closeEditor(editor, QAbstractItemDelegate::NoHint);
} }
} else if (event->type() == QEvent::ShortcutOverride) { } else if (event->type() == QEvent::ShortcutOverride) {
if (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Escape) { if (static_cast<QKeyEvent*>(event)->matches(QKeySequence::Cancel)) {
event->accept(); event->accept();
return true; return true;
} }

View File

@ -459,7 +459,7 @@ bool QWhatsThisPrivate::eventFilter(QObject *o, QEvent *e)
{ {
QKeyEvent* kev = (QKeyEvent*)e; QKeyEvent* kev = (QKeyEvent*)e;
if (kev->key() == Qt::Key_Escape) { if (kev->matches(QKeySequence::Cancel)) {
QWhatsThis::leaveWhatsThisMode(); QWhatsThis::leaveWhatsThisMode();
return true; return true;
} else if (customWhatsThis) { } else if (customWhatsThis) {

View File

@ -9349,7 +9349,8 @@ void QWidget::tabletEvent(QTabletEvent *event)
call the base class implementation if you do not act upon the key. call the base class implementation if you do not act upon the key.
The default implementation closes popup widgets if the user 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. parent can interpret it.
Note that QKeyEvent starts with isAccepted() == true, so you do not 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) void QWidget::keyPressEvent(QKeyEvent *event)
{ {
if ((windowType() == Qt::Popup) && event->key() == Qt::Key_Escape) { if ((windowType() == Qt::Popup) && event->matches(QKeySequence::Cancel)) {
event->accept(); event->accept();
close(); close();
} else { } else {

View File

@ -1337,6 +1337,11 @@ bool QCompleter::eventFilter(QObject *o, QEvent *e)
} }
// default implementation for keys not handled by the widget when popup is open // 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) { switch (key) {
#ifdef QT_KEYPAD_NAVIGATION #ifdef QT_KEYPAD_NAVIGATION
case Qt::Key_Select: case Qt::Key_Select:
@ -1357,7 +1362,6 @@ bool QCompleter::eventFilter(QObject *o, QEvent *e)
break; break;
case Qt::Key_Backtab: case Qt::Key_Backtab:
case Qt::Key_Escape:
d->popup->hide(); d->popup->hide();
break; break;

View File

@ -1221,16 +1221,14 @@ void QAbstractButton::keyPressEvent(QKeyEvent *e)
} }
break; break;
} }
case Qt::Key_Escape: default:
if (d->down) { if (e->matches(QKeySequence::Cancel) && d->down) {
setDown(false); setDown(false);
repaint(); //flush paint event before invoking potentially expensive operation repaint(); //flush paint event before invoking potentially expensive operation
QApplication::flush(); QApplication::flush();
d->emitReleased(); d->emitReleased();
break; return;
} }
// fall through
default:
e->ignore(); e->ignore();
} }
} }

View File

@ -776,7 +776,7 @@ bool QCalendarTextNavigator::eventFilter(QObject *o, QEvent *e)
applyDate(); applyDate();
emit editingFinished(); emit editingFinished();
removeDateLabel(); removeDateLabel();
} else if (ke->key() == Qt::Key_Escape) { } else if (ke->matches(QKeySequence::Cancel)) {
removeDateLabel(); removeDateLabel();
} else if (e->type() == QEvent::KeyPress) { } else if (e->type() == QEvent::KeyPress) {
createDateLabel(); createDateLabel();
@ -3078,8 +3078,7 @@ void QCalendarWidget::resizeEvent(QResizeEvent * event)
void QCalendarWidget::keyPressEvent(QKeyEvent * event) void QCalendarWidget::keyPressEvent(QKeyEvent * event)
{ {
Q_D(QCalendarWidget); 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->yearEdit->setValue(yearShown());
d->_q_yearEditingFinished(); d->_q_yearEditingFinished();
return; return;

View File

@ -654,8 +654,9 @@ void QComboBoxPrivateContainer::changeEvent(QEvent *e)
bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e) bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e)
{ {
switch (e->type()) { switch (e->type()) {
case QEvent::ShortcutOverride: case QEvent::ShortcutOverride: {
switch (static_cast<QKeyEvent*>(e)->key()) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(e);
switch (keyEvent->key()) {
case Qt::Key_Enter: case Qt::Key_Enter:
case Qt::Key_Return: case Qt::Key_Return:
#ifdef QT_KEYPAD_NAVIGATION #ifdef QT_KEYPAD_NAVIGATION
@ -667,17 +668,21 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e)
} }
return true; return true;
case Qt::Key_Down: case Qt::Key_Down:
if (!(static_cast<QKeyEvent*>(e)->modifiers() & Qt::AltModifier)) if (!(keyEvent->modifiers() & Qt::AltModifier))
break; break;
// fall through // fall through
case Qt::Key_F4: case Qt::Key_F4:
case Qt::Key_Escape:
combo->hidePopup(); combo->hidePopup();
return true; return true;
default: default:
if (keyEvent->matches(QKeySequence::Cancel)) {
combo->hidePopup();
return true;
}
break; break;
} }
break; break;
}
case QEvent::MouseMove: case QEvent::MouseMove:
if (isVisible()) { if (isVisible()) {
QMouseEvent *m = static_cast<QMouseEvent *>(e); QMouseEvent *m = static_cast<QMouseEvent *>(e);

View File

@ -2655,7 +2655,7 @@ bool QCalendarPopup::event(QEvent *event)
{ {
if (event->type() == QEvent::KeyPress) { if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key()== Qt::Key_Escape) if (keyEvent->matches(QKeySequence::Cancel))
dateChanged = false; dateChanged = false;
} }
return QWidget::event(event); return QWidget::event(event);

View File

@ -197,7 +197,7 @@ bool QAlphaWidget::eventFilter(QObject *o, QEvent *e)
break; break;
case QEvent::KeyPress: { case QEvent::KeyPress: {
QKeyEvent *ke = (QKeyEvent*)e; QKeyEvent *ke = (QKeyEvent*)e;
if (ke->key() == Qt::Key_Escape) { if (ke->matches(QKeySequence::Cancel)) {
showWidget = false; showWidget = false;
} else { } else {
duration = 0; duration = 0;

View File

@ -2679,7 +2679,7 @@ QMenu::event(QEvent *e)
if (kev->key() == Qt::Key_Up || kev->key() == Qt::Key_Down 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_Left || kev->key() == Qt::Key_Right
|| kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return || kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return
|| kev->key() == Qt::Key_Escape) { || kev->matches(QKeySequence::Cancel)) {
e->accept(); e->accept();
return true; return true;
} }
@ -2965,27 +2965,6 @@ void QMenu::keyPressEvent(QKeyEvent *e)
} }
break; break;
case Qt::Key_Escape:
#ifdef QT_KEYPAD_NAVIGATION
case Qt::Key_Back:
#endif
key_consumed = true;
if (d->tornoff) {
close();
return;
}
{
QPointer<QWidget> caused = d->causedPopup.widget;
d->hideMenu(this); // hide after getting causedPopup
#ifndef QT_NO_MENUBAR
if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
mb->d_func()->setCurrentAction(d->menuAction);
mb->d_func()->setKeyboardMode(true);
}
#endif
}
break;
case Qt::Key_Space: case Qt::Key_Space:
if (!style()->styleHint(QStyle::SH_Menu_SpaceActivatesItem, 0, this)) if (!style()->styleHint(QStyle::SH_Menu_SpaceActivatesItem, 0, this))
break; break;
@ -3022,6 +3001,28 @@ void QMenu::keyPressEvent(QKeyEvent *e)
key_consumed = false; 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<QWidget> caused = d->causedPopup.widget;
d->hideMenu(this); // hide after getting causedPopup
#ifndef QT_NO_MENUBAR
if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) {
mb->d_func()->setCurrentAction(d->menuAction);
mb->d_func()->setKeyboardMode(true);
}
#endif
}
}
if (!key_consumed) { // send to menu bar if (!key_consumed) { // send to menu bar
if ((!e->modifiers() || e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ShiftModifier) && if ((!e->modifiers() || e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ShiftModifier) &&
e->text().length()==1) { e->text().length()==1) {

View File

@ -1122,14 +1122,14 @@ void QMenuBar::keyPressEvent(QKeyEvent *e)
} }
break; } break; }
case Qt::Key_Escape: default:
key_consumed = false;
}
if (!key_consumed && e->matches(QKeySequence::Cancel)) {
d->setCurrentAction(0); d->setCurrentAction(0);
d->setKeyboardMode(false); d->setKeyboardMode(false);
key_consumed = true; key_consumed = true;
break;
default:
key_consumed = false;
} }
if(!key_consumed && if(!key_consumed &&
@ -1432,7 +1432,7 @@ bool QMenuBar::event(QEvent *e)
case QEvent::ShortcutOverride: { case QEvent::ShortcutOverride: {
QKeyEvent *kev = static_cast<QKeyEvent*>(e); QKeyEvent *kev = static_cast<QKeyEvent*>(e);
//we only filter out escape if there is a current action //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(); e->accept();
return true; return true;
} }