Skip to content

Instantly share code, notes, and snippets.

@dvolosnykh
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dvolosnykh/65819bca1693b0e82058 to your computer and use it in GitHub Desktop.
Save dvolosnykh/65819bca1693b0e82058 to your computer and use it in GitHub Desktop.
RFC: Custom keys support.
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;
#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);
}
#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
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