【写在前面】

在 Qt 中,对于一个键盘事件QKeyEvent ,通常包含三种键值:

  1. key:Qt 键值,例如 Qt::Key_Escape
  2. nativeVirtualKey:本机虚拟键值,例如 VK_ESCAPE ( windows )。
  3. nativeScanCode:本机扫描码。

【正文开始】

 在 Qml 中,也存在着键盘事件:KeyEvent

看起来它与 QKeyEvent 没有什么太大的区别,然而实际上,它缺少 nativeVirtualKey

当然,很多时候我们仅仅使用它的 key 足矣,但是一个坑是 Qt 键值并没有包含所有的按键

来看下面代码:

void MyWindow::keyPressEvent(QKeyEvent *ev)
{
    qDebug().noquote() << "按键:" << ev->text() << hex
                       << "key:" << ev->key()
                       << "nativeScanCode:" << ev->nativeScanCode()
                       << "nativeVirtualKey:" << ev->nativeVirtualKey();
}

输出如下: 

两个都是按键1,但第一个是数字键1,第二个却是小键盘的数字键1。 

而它们的区别有两个,nativeScanCodenativeVirtualKey

事实上,当一个按键按下的时候,会发生以下转换:

前面提到了Qt 键值并没有包含所有的按键,因此可以想到,在 virtualKey 转换的时候,两个不同的按键1都被转换( 映射 )成了 Qt::Key_1

当然,如果仅仅是这样就算了,我们完全可以使用 nativeVirtualKey 来区分( 在C++中 ),然鹅在 Qml 中,恰好就没有 nativeVirtualKey,这™就很尴尬了好吗。

由于某些应用的特殊性( 例如:远程控制 ),因此我必须知道,到底是哪个按键按下了。

能想到的解决方法有两个:

  1. 不使用 Qml 的 KeyEvent,而是使用 keyPressEvent(QKeyEvent *event) 提供的 QKeyEvent::nativeVirtualKey 来区分。
  2. 使用 Qml 的 KeyEvent,但需要进行额外的判断,对于这种方法,由于所有的按键都有其 scanCode,所以我们最后还是可以通过 scanCode 来区分不同的按键。

【结语】

最后讲一下题外话。

因为我做的是远程控制,所以仅仅是区分不同的按键远远不够。

例如 Windows APISendInputkeybd_event( 被 SendInput 取代) 模拟按键事件时,就需要 virtualKey 值,也就是说最终还是得把 Qt Key 转换成 virtualKey

所以在使用第二种方法的时候,仍然要进行转换,这里给一个 KDE 的工具(但是不完整而且仍不能区分所有键,所以我自己用的改进了一下):KWindowSystem - kkeyserver.cpp Source File


梦起丶
38 声望2 粉丝

🎉专注于 C/C++/Qt/JS/Python 编程技巧🎉