Last active
August 29, 2015 14:20
-
-
Save dvolosnykh/65819bca1693b0e82058 to your computer and use it in GitHub Desktop.
RFC: Custom keys support.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp | |
index 07d7636..69ce2ae 100644 | |
--- a/src/quick/items/qquickitem.cpp | |
+++ b/src/quick/items/qquickitem.cpp | |
@@ -72,6 +72,7 @@ | |
#endif | |
#include <algorithm> | |
+#include <cctype> | |
#include <float.h> | |
// XXX todo Check that elements that create items handle memory correctly after visual ownership change | |
@@ -743,63 +744,34 @@ void QQuickKeyNavigationAttached::setFocusNavigation(QQuickItem *currentItem, co | |
while (currentItem != initialItem && isNextItem); | |
} | |
-struct SigMap { | |
- int key; | |
- const char *sig; | |
-}; | |
- | |
-const SigMap sigMap[] = { | |
- { Qt::Key_Left, "leftPressed" }, | |
- { Qt::Key_Right, "rightPressed" }, | |
- { Qt::Key_Up, "upPressed" }, | |
- { Qt::Key_Down, "downPressed" }, | |
- { Qt::Key_Tab, "tabPressed" }, | |
- { Qt::Key_Backtab, "backtabPressed" }, | |
- { Qt::Key_Asterisk, "asteriskPressed" }, | |
- { Qt::Key_NumberSign, "numberSignPressed" }, | |
- { Qt::Key_Escape, "escapePressed" }, | |
- { Qt::Key_Return, "returnPressed" }, | |
- { Qt::Key_Enter, "enterPressed" }, | |
- { Qt::Key_Delete, "deletePressed" }, | |
- { Qt::Key_Space, "spacePressed" }, | |
- { Qt::Key_Back, "backPressed" }, | |
- { Qt::Key_Cancel, "cancelPressed" }, | |
- { Qt::Key_Select, "selectPressed" }, | |
- { Qt::Key_Yes, "yesPressed" }, | |
- { Qt::Key_No, "noPressed" }, | |
- { Qt::Key_Context1, "context1Pressed" }, | |
- { Qt::Key_Context2, "context2Pressed" }, | |
- { Qt::Key_Context3, "context3Pressed" }, | |
- { Qt::Key_Context4, "context4Pressed" }, | |
- { Qt::Key_Call, "callPressed" }, | |
- { Qt::Key_Hangup, "hangupPressed" }, | |
- { Qt::Key_Flip, "flipPressed" }, | |
- { Qt::Key_Menu, "menuPressed" }, | |
- { Qt::Key_VolumeUp, "volumeUpPressed" }, | |
- { Qt::Key_VolumeDown, "volumeDownPressed" }, | |
- { 0, 0 } | |
-}; | |
- | |
const QByteArray QQuickKeysAttached::keyToSignal(int key) | |
{ | |
- QByteArray keySignal; | |
- if (key >= Qt::Key_0 && key <= Qt::Key_9) { | |
- keySignal = "digit0Pressed"; | |
- keySignal[5] = '0' + (key - Qt::Key_0); | |
- } else { | |
- int i = 0; | |
- while (sigMap[i].key && sigMap[i].key != key) | |
- ++i; | |
- keySignal = sigMap[i].sig; | |
+ Q_D(QQuickKeysAttached); | |
+ | |
+ Q_FOREACH(const QMetaEnum& metaEnum, d->enums) { | |
+ const char* const keyName = metaEnum.valueToKey(key); | |
+ if (keyName == 0) continue; | |
+ | |
+ QByteArray keySignal(keyName + 4); | |
+ Q_ASSERT(!keySignal.isEmpty()); | |
+ | |
+ if (key >= Qt::Key_0 && key <= Qt::Key_9) | |
+ keySignal.prepend("digit"); | |
+ else if (key >= Qt::Key_A && key <= Qt::Key_Z) | |
+ keySignal.prepend("letter"); | |
+ else | |
+ keySignal[0] = std::tolower(keySignal[0]); | |
+ return keySignal; | |
} | |
- return keySignal; | |
+ | |
+ return QByteArray(); | |
} | |
bool QQuickKeysAttached::isConnected(const char *signalName) | |
{ | |
Q_D(QQuickKeysAttached); | |
int signal_index = d->signalIndex(signalName); | |
- return d->isSignalConnected(signal_index); | |
+ return (signal_index >= 0 && d->isSignalConnected(signal_index)); | |
} | |
/*! | |
@@ -1282,6 +1254,7 @@ QQuickKeysAttached::QQuickKeysAttached(QObject *parent) | |
d->item = qmlobject_cast<QQuickItem*>(parent); | |
if (d->item != parent) | |
qWarning() << "Could not attach Keys property to: " << parent << " is not an Item"; | |
+ d->enums << QMetaEnum::fromType<Qt::Key>(); | |
} | |
QQuickKeysAttached::~QQuickKeysAttached() | |
@@ -1320,78 +1293,87 @@ void QQuickKeysAttached::componentComplete() | |
void QQuickKeysAttached::keyPressed(QKeyEvent *event, bool post) | |
{ | |
+ handleKey(event, post, true); | |
+} | |
+ | |
+void QQuickKeysAttached::keyReleased(QKeyEvent *event, bool post) | |
+{ | |
+ handleKey(event, post, false); | |
+} | |
+ | |
+void QQuickKeysAttached::handleKey(QKeyEvent* event, bool post, bool press) | |
+{ | |
Q_D(QQuickKeysAttached); | |
- if (post != m_processPost || !d->enabled || d->inPress) { | |
+ | |
+ if (post != m_processPost || !d->enabled || (press ? d->inPress : d->inRelease)) { | |
event->ignore(); | |
- QQuickItemKeyFilter::keyPressed(event, post); | |
+ if (press) | |
+ QQuickItemKeyFilter::keyPressed(event, post); | |
+ else | |
+ QQuickItemKeyFilter::keyReleased(event, post); | |
return; | |
} | |
// first process forwards | |
if (d->item && d->item->window()) { | |
- d->inPress = true; | |
+ if (press) | |
+ d->inPress = true; | |
+ else | |
+ d->inRelease = true; | |
+ | |
for (int ii = 0; ii < d->targets.count(); ++ii) { | |
QQuickItem *i = d->targets.at(ii); | |
if (i && i->isVisible()) { | |
event->accept(); | |
QCoreApplication::sendEvent(i, event); | |
if (event->isAccepted()) { | |
- d->inPress = false; | |
+ if (press) | |
+ d->inPress = false; | |
+ else | |
+ d->inRelease = false; | |
return; | |
} | |
} | |
} | |
- d->inPress = false; | |
+ if (press) | |
+ d->inPress = false; | |
+ else | |
+ d->inRelease = false; | |
} | |
QQuickKeyEvent ke(*event); | |
QByteArray keySignal = keyToSignal(event->key()); | |
if (!keySignal.isEmpty()) { | |
+ keySignal += (press ? "Pressed" : "Released"); | |
keySignal += "(QQuickKeyEvent*)"; | |
if (isConnected(keySignal)) { | |
// If we specifically handle a key then default to accepted | |
ke.setAccepted(true); | |
- int idx = QQuickKeysAttached::staticMetaObject.indexOfSignal(keySignal); | |
- metaObject()->method(idx).invoke(this, Qt::DirectConnection, Q_ARG(QQuickKeyEvent*, &ke)); | |
+ const QMetaObject* const mobj = metaObject(); | |
+ int idx = mobj->indexOfSignal(keySignal); | |
+ mobj->method(idx).invoke(this, Qt::DirectConnection, Q_ARG(QQuickKeyEvent*, &ke)); | |
} | |
} | |
- if (!ke.isAccepted()) | |
- emit pressed(&ke); | |
+ if (!ke.isAccepted()) { | |
+ if (press) | |
+ emit pressed(&ke); | |
+ else | |
+ emit released(&ke); | |
+ } | |
event->setAccepted(ke.isAccepted()); | |
- if (!event->isAccepted()) QQuickItemKeyFilter::keyPressed(event, post); | |
+ if (!event->isAccepted()) { | |
+ if (press) | |
+ QQuickItemKeyFilter::keyPressed(event, post); | |
+ else | |
+ QQuickItemKeyFilter::keyReleased(event, post); | |
+ } | |
} | |
-void QQuickKeysAttached::keyReleased(QKeyEvent *event, bool post) | |
+void QQuickKeysAttached::registerKeys(const QMetaEnum& keys) | |
{ | |
Q_D(QQuickKeysAttached); | |
- if (post != m_processPost || !d->enabled || d->inRelease) { | |
- event->ignore(); | |
- QQuickItemKeyFilter::keyReleased(event, post); | |
- return; | |
- } | |
- | |
- if (d->item && d->item->window()) { | |
- d->inRelease = true; | |
- for (int ii = 0; ii < d->targets.count(); ++ii) { | |
- QQuickItem *i = d->targets.at(ii); | |
- if (i && i->isVisible()) { | |
- event->accept(); | |
- QCoreApplication::sendEvent(i, event); | |
- if (event->isAccepted()) { | |
- d->inRelease = false; | |
- return; | |
- } | |
- } | |
- } | |
- d->inRelease = false; | |
- } | |
- | |
- QQuickKeyEvent ke(*event); | |
- emit released(&ke); | |
- event->setAccepted(ke.isAccepted()); | |
- | |
- if (!event->isAccepted()) QQuickItemKeyFilter::keyReleased(event, post); | |
+ d->enums.prepend(keys); | |
} | |
#ifndef QT_NO_IM | |
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h | |
index 64d8bd0..400b012 100644 | |
--- a/src/quick/items/qquickitem_p.h | |
+++ b/src/quick/items/qquickitem_p.h | |
@@ -728,9 +728,10 @@ public: | |
QQuickItem *imeItem; | |
QList<QQuickItem *> targets; | |
QQuickItem *item; | |
+ QList<QMetaEnum> enums; | |
}; | |
-class QQuickKeysAttached : public QObject, public QQuickItemKeyFilter | |
+class Q_QUICK_PRIVATE_EXPORT QQuickKeysAttached : public QObject, public QQuickItemKeyFilter | |
{ | |
Q_OBJECT | |
Q_DECLARE_PRIVATE(QQuickKeysAttached) | |
@@ -813,9 +814,18 @@ Q_SIGNALS: | |
void volumeUpPressed(QQuickKeyEvent *event); | |
void volumeDownPressed(QQuickKeyEvent *event); | |
+protected: | |
+ template<typename T> | |
+ void registerKeySet() | |
+ { | |
+ registerKeys(QMetaEnum::fromType<T>()); | |
+ } | |
+ | |
private: | |
void keyPressed(QKeyEvent *event, bool post) Q_DECL_OVERRIDE; | |
void keyReleased(QKeyEvent *event, bool post) Q_DECL_OVERRIDE; | |
+ void handleKey(QKeyEvent* event, bool post, bool press); | |
+ void registerKeys(const QMetaEnum& keys); | |
#ifndef QT_NO_IM | |
void inputMethodEvent(QInputMethodEvent *, bool post) Q_DECL_OVERRIDE; | |
QVariant inputMethodQuery(Qt::InputMethodQuery query) const Q_DECL_OVERRIDE; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "customkeys.h" | |
CustomKeys::CustomKeys(QObject *parent) | |
: QQuickKeysAttached(parent) | |
{ | |
registerKeySet<Key>(); | |
} | |
CustomKeys* CustomKeys::qmlAttachedProperties(QObject *object) | |
{ | |
return new CustomKeys(object); | |
} | |
void CustomKeys::connectNotify(const QMetaMethod& signal) | |
{ | |
qDebug() << signal.methodSignature() << "connected:" << isSignalConnected(signal); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef CUSTOMKEYS_H | |
#define CUSTOMKEYS_H | |
#include <QtQuick/private/qquickitem_p.h> | |
class CustomKeys : public QQuickKeysAttached | |
{ | |
Q_OBJECT | |
public: | |
enum Key { | |
Key_RenamedSpace = Qt::Key_Space | |
}; | |
Q_ENUM(Key) | |
explicit CustomKeys(QObject *parent = 0); | |
static CustomKeys *qmlAttachedProperties(QObject *object); | |
signals: | |
void renamedSpacePressed(QQuickKeyEvent *event); | |
protected: | |
void connectNotify(const QMetaMethod& signal); | |
}; | |
QML_DECLARE_TYPEINFO(CustomKeys, QML_HAS_ATTACHED_PROPERTIES) | |
#endif // CUSTOMKEYS_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Custom 0.1 | |
import QtQuick 2.4 | |
import QtQuick.Window 2.0 | |
Window { | |
width: 200 | |
height: 200 | |
visible: true | |
Rectangle { | |
anchors.fill: parent | |
color: "salmon" | |
focus: true | |
CustomKeys.onSpacePressed: console.log("Space key was pressed") | |
CustomKeys.onRenamedSpacePressed: console.log("Renamed space key was pressed") | |
CustomKeys.onReturnPressed: console.log("Return was pressed") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment