QKeyEvent nativeVirtualKey n'est pas défini

Nov 17 2020

J'ai besoin du code de clé natif d'une clé dans mon application QML. J'ai le gestionnaire de clé suivant dans un élément QML.

            Keys.onPressed: {
                console.log("Key: ", event.key)
                console.log("Native: ", event.nativeVirtualKey);
                event.accepted = true
            }

Le event.keyfonctionne bien lorsque vous appuyez sur les touches, mais le event.nativeVirtualKeyn'était pas défini. par exemple.

qml: Key:  70
qml: Native:  undefined

Quelque chose ne va pas avec mon code? Comment puis-je obtenir la nativeVirtualKey?

Je vois maintenant dans la documentation que "Remarque: la clé virtuelle native peut être 0, même si l'événement de clé contient des informations étendues." https://doc.qt.io/qt-5/qkeyevent.html#nativeVirtualKey Malheureusement, il n'y a aucune mention du moment ou des conditions qui provoquent la disparition de la clé native virtuelle.

Réponses

3 eyllanesc Nov 17 2020 at 02:14

Comme je l'ai déjà souligné dans cette réponse : KeyEventn'est pas un QKeyEventmais un QObject qui expose certaines propriétés mais pas toutes. Une solution de contournement consiste à créer un QObject qui installe un filtre d'événement sur l'élément et expose cette propriété:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickItem>

class KeyHelper: public QObject{
    Q_OBJECT
    Q_PROPERTY(QQuickItem* target READ target WRITE setTarget NOTIFY targetChanged)
public:
    using QObject::QObject;
    QQuickItem* target() const {
        return m_target;
    }
    void setTarget(QQuickItem* item){
        if(m_target)
            m_target->removeEventFilter(this);
        m_target = item;
        if(m_target)
            m_target->installEventFilter(this);
        Q_EMIT targetChanged(m_target);
    }
    bool eventFilter(QObject *watched, QEvent *event){
        if(watched == m_target && event->type() == QEvent::KeyPress){
            if(QKeyEvent *ke = static_cast<QKeyEvent *>(event))
                Q_EMIT nativeVirtualKeyChanged(ke->nativeVirtualKey());
        }
        return QObject::eventFilter(watched, event);
    }
signals:
    void nativeVirtualKeyChanged(quint32 nativeVirtualKey);
    void targetChanged(QQuickItem* item);
private:
    QPointer<QQuickItem> m_target;

};

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    qmlRegisterType<KeyHelper>("qt.keyhelper", 1, 0, "KeyHelper");

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

#include "main.moc"
import QtQuick 2.12
import QtQuick.Window 2.12
import qt.keyhelper 1.0

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")
    Item {
        id: item
        focus: true
        anchors.fill: parent
    }
   KeyHelper{
       target: item
       onNativeVirtualKeyChanged: console.log(nativeVirtualKey)
    }
}
Mark Nov 17 2020 at 05:35

Voici un léger ajustement de la réponse de @ eyllanesc qui remplace eventFilterle reconditionnement du QEvent en tant que QVariantMap afin qu'il puisse être directement appelé avec des fonctions qui attendent l' KeyEventAPI.

class KeyHelper: public QObject{
     ... // same as @ellyanesc's answer

     bool eventFilter(QObject *watched, QEvent *event){
         if(watched == m_target && event->type() == QEvent::KeyPress){
             if(QKeyEvent *ke = static_cast<QKeyEvent *>(event)) {
                 // it seems we cannot send the event in a signal since it doesnt inherit from QObject.
                 // copy the relevant values to an event object
                 QVariantMap eventObject;
                 eventObject["key"] = ke->key();
                 eventObject["modifiers"] = int(ke->modifiers());
                 eventObject["nativeVirtualKey"] = ke->nativeVirtualKey();
                 eventObject["nativeModifiers"] = ke->nativeModifiers();
                 Q_EMIT nativeKeyPress(eventObject);
             }
         }
         return QObject::eventFilter(watched, event);
     }

signals:
     void nativeKeyPress(QVariantMap event); 

     ... // same as @ellyanesc's answer
};

Et puis dans le fichier qml

        KeyHelper{
            target: ...
            onNativeKeyPress: {
                console.log("native key press ", JSON.stringify(event))
            }
         }