QKeyEvent nativeVirtualKey là không xác định

Nov 17 2020

Tôi cần mã khóa gốc của khóa trong ứng dụng QML của mình. Tôi có trình xử lý khóa sau trong một mục QML.

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

Các event.keyhoạt động tốt khi nhấn các phím, nhưng event.nativeVirtualKeykhông xác định được. ví dụ.

qml: Key:  70
qml: Native:  undefined

Có gì đó sai với mã của tôi? Làm cách nào để tải nativeVirtualKey?

Tôi hiện thấy trong tài liệu rằng "Lưu ý: Khóa ảo gốc có thể bằng 0, ngay cả khi sự kiện khóa chứa thông tin mở rộng." https://doc.qt.io/qt-5/qkeyevent.html#nativeVirtualKey Thật không may, không có đề cập đến khi nào hoặc điều kiện nào khiến khóa gốc ảo biến mất.

Trả lời

3 eyllanesc Nov 17 2020 at 02:14

Như tôi đã chỉ ra trong câu trả lời này : KeyEventkhông phải là một QKeyEventmà là một QObject hiển thị một số thuộc tính nhưng không phải tất cả. Cách giải quyết là tạo QObject cài đặt bộ lọc sự kiện cho mục và hiển thị thuộc tính đó:

#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

Đây là một điều chỉnh nhỏ về câu trả lời của @ eyllanesc thay thế eventFilterđể đóng gói lại QEvent dưới dạng QVariantMap để nó có thể được gọi trực tiếp với các hàm mong đợi 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
};

Và sau đó trong tệp qml

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