diff options
-rw-r--r-- | src/quick/items/qquickitem.cpp | 66 | ||||
-rw-r--r-- | src/quick/items/qquickitem_p.h | 4 | ||||
-rw-r--r-- | src/quick/util/qquickshortcut.cpp | 2 | ||||
-rw-r--r-- | tests/auto/quick/qquickitem/data/shortcutOverride.qml | 65 | ||||
-rw-r--r-- | tests/auto/quick/qquickitem/tst_qquickitem.cpp | 35 |
5 files changed, 171 insertions, 1 deletions
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index ca8ef7ba2e..504446a8be 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -333,6 +333,12 @@ QVariant QQuickItemKeyFilter::inputMethodQuery(Qt::InputMethodQuery query) const } #endif // im +void QQuickItemKeyFilter::shortcutOverride(QKeyEvent *event) +{ + if (m_next) + m_next->shortcutOverride(event); +} + void QQuickItemKeyFilter::componentComplete() { if (m_next) m_next->componentComplete(); @@ -935,6 +941,46 @@ bool QQuickKeysAttached::isConnected(const char *signalName) const */ /*! + \qmlsignal QtQuick::Keys::shortcutOverride(KeyEvent event) + \since 5.9 + + This signal is emitted when a key has been pressed that could potentially + be used as a shortcut. The \a event parameter provides information about + the event. + + Set \c event.accepted to \c true if you wish to prevent the pressed key + from being used as a shortcut by other types, such as \l Shortcut. For + example: + + \code + Item { + id: escapeItem + focus: true + + // Ensure that we get escape key press events first. + Keys.onShortcutOverride: event.accepted = (event.key === Qt.Key_Escape) + + Keys.onEscapePressed: { + console.log("escapeItem is handling escape"); + event.accepted = true; + } + } + + Shortcut { + sequence: "Escape" + onActivated: console.log("Shortcut is handling escape") + } + \endcode + + As with the other signals, \c shortcutOverride will only be emitted for an + item if that item has \l {Item::}{activeFocus}. + + The corresponding handler is \c onShortcutOverride. + + \sa Shortcut +*/ + +/*! \qmlsignal QtQuick::Keys::digit0Pressed(KeyEvent event) This signal is emitted when the digit '0' has been pressed. The \a event @@ -1426,6 +1472,16 @@ QVariant QQuickKeysAttached::inputMethodQuery(Qt::InputMethodQuery query) const } #endif // im +void QQuickKeysAttached::shortcutOverride(QKeyEvent *event) +{ + Q_D(QQuickKeysAttached); + QQuickKeyEvent &keyEvent = d->theKeyEvent; + keyEvent.reset(*event); + emit shortcutOverride(&keyEvent); + + event->setAccepted(keyEvent.isAccepted()); +} + QQuickKeysAttached *QQuickKeysAttached::qmlAttachedProperties(QObject *obj) { return new QQuickKeysAttached(obj); @@ -5019,6 +5075,13 @@ void QQuickItemPrivate::deliverInputMethodEvent(QInputMethodEvent *e) } #endif // im +void QQuickItemPrivate::deliverShortcutOverrideEvent(QKeyEvent *event) +{ + if (extra.isAllocated() && extra->keyHandler) { + extra->keyHandler->shortcutOverride(event); + } +} + /*! Called when \a change occurs for this item. @@ -7652,6 +7715,9 @@ bool QQuickItem::event(QEvent *ev) case QEvent::KeyRelease: d->deliverKeyEvent(static_cast<QKeyEvent*>(ev)); break; + case QEvent::ShortcutOverride: + d->deliverShortcutOverrideEvent(static_cast<QKeyEvent*>(ev)); + break; case QEvent::FocusIn: focusInEvent(static_cast<QFocusEvent*>(ev)); break; diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 3002b73a8c..c0c9bd46bd 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -559,6 +559,7 @@ public: #if QT_CONFIG(im) void deliverInputMethodEvent(QInputMethodEvent *); #endif + void deliverShortcutOverrideEvent(QKeyEvent *); bool isTransparentForPositioner() const; void setTransparentForPositioner(bool trans); @@ -622,6 +623,7 @@ public: virtual void inputMethodEvent(QInputMethodEvent *event, bool post); virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const; #endif + virtual void shortcutOverride(QKeyEvent *event); virtual void componentComplete(); bool m_processPost; @@ -813,6 +815,7 @@ Q_SIGNALS: void priorityChanged(); void pressed(QQuickKeyEvent *event); void released(QQuickKeyEvent *event); + void shortcutOverride(QQuickKeyEvent *event); void digit0Pressed(QQuickKeyEvent *event); void digit1Pressed(QQuickKeyEvent *event); void digit2Pressed(QQuickKeyEvent *event); @@ -861,6 +864,7 @@ private: void inputMethodEvent(QInputMethodEvent *, bool post) Q_DECL_OVERRIDE; QVariant inputMethodQuery(Qt::InputMethodQuery query) const Q_DECL_OVERRIDE; #endif + void shortcutOverride(QKeyEvent *event) override; static QByteArray keyToSignal(int key); bool isConnected(const char *signalName) const; diff --git a/src/quick/util/qquickshortcut.cpp b/src/quick/util/qquickshortcut.cpp index a0a58f2e02..72d9c889e3 100644 --- a/src/quick/util/qquickshortcut.cpp +++ b/src/quick/util/qquickshortcut.cpp @@ -73,7 +73,7 @@ It is also possible to set multiple shortcut \l sequences, so that the shortcut can be \l activated via several different sequences of key presses. - \sa Keys + \sa Keys, {Keys::}{shortcutOverride()} */ /*! \qmlsignal QtQuick::Shortcut::activated() diff --git a/tests/auto/quick/qquickitem/data/shortcutOverride.qml b/tests/auto/quick/qquickitem/data/shortcutOverride.qml new file mode 100644 index 0000000000..fab9175c17 --- /dev/null +++ b/tests/auto/quick/qquickitem/data/shortcutOverride.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Window 2.1 + +Item { + property int escapeHandlerActivationCount: 0 + property int shortcutActivationCount: 0 + property alias escapeItem: escapeItem + + Item { + id: escapeItem + objectName: "escapeItem" + focus: true + + // By accepting shortcut override events when the key is Qt.Key_Escape, + // we can ensure that our Keys.onEscapePressed handler (below) will be called. + Keys.onShortcutOverride: event.accepted = (event.key === Qt.Key_Escape) + + Keys.onEscapePressed: { + // Pretend that we just did some really important stuff that was triggered + // by the escape key (like might occur in a popup that has a keyboard shortcut editor, for example). + // Now that we're done, we no longer need focus, so we won't accept future shorcut override events. + focus = false; + event.accepted = true; + ++escapeHandlerActivationCount; + } + } + + Shortcut { + sequence: "Escape" + onActivated: ++shortcutActivationCount + } +} diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp index d0139b6cdf..8d974f4d17 100644 --- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp @@ -172,6 +172,8 @@ private slots: void ignoreButtonPressNotInAcceptedMouseButtons(); + void shortcutOverride(); + private: enum PaintOrderOp { @@ -2036,6 +2038,39 @@ void tst_qquickitem::ignoreButtonPressNotInAcceptedMouseButtons() QCOMPARE(item.releaseCount, 1); } +void tst_qquickitem::shortcutOverride() +{ + QQuickView view; + view.setSource(testFileUrl("shortcutOverride.qml")); + ensureFocus(&view); + + QCOMPARE(view.rootObject()->property("escapeHandlerActivationCount").toInt(), 0); + QCOMPARE(view.rootObject()->property("shortcutActivationCount").toInt(), 0); + + QQuickItem *escapeItem = view.rootObject()->property("escapeItem").value<QQuickItem*>(); + QVERIFY(escapeItem); + QVERIFY(escapeItem->hasActiveFocus()); + + // escapeItem's onEscapePressed handler should accept the first escape press event. + QTest::keyPress(&view, Qt::Key_Escape); + QCOMPARE(view.rootObject()->property("escapeHandlerActivationCount").toInt(), 1); + QCOMPARE(view.rootObject()->property("shortcutActivationCount").toInt(), 0); + // Now it shouldn't have focus, so it can't handle the next escape press event. + QVERIFY(!escapeItem->hasActiveFocus()); + + QTest::keyRelease(&view, Qt::Key_Escape); + QCOMPARE(view.rootObject()->property("escapeHandlerActivationCount").toInt(), 1); + QCOMPARE(view.rootObject()->property("shortcutActivationCount").toInt(), 0); + + QTest::keyPress(&view, Qt::Key_Escape); + QCOMPARE(view.rootObject()->property("escapeHandlerActivationCount").toInt(), 1); + QCOMPARE(view.rootObject()->property("shortcutActivationCount").toInt(), 1); + + QTest::keyRelease(&view, Qt::Key_Escape); + QCOMPARE(view.rootObject()->property("escapeHandlerActivationCount").toInt(), 1); + QCOMPARE(view.rootObject()->property("shortcutActivationCount").toInt(), 1); +} + QTEST_MAIN(tst_qquickitem) #include "tst_qquickitem.moc" |