Qml 中的那些坑(三)---KeyEvent 的 key / virtualKey / scanCode
【写在前面】
在 Qt 中,对于一个键盘事件QKeyEvent
,通常包含三种键值:
-
key:Qt 键值,例如
Qt::Key_Escape
。 -
nativeVirtualKey:本机虚拟键值,例如
VK_ESCAPE
( windows )。 -
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。
而它们的区别有两个,nativeScanCode
和 nativeVirtualKey
。
事实上,当一个按键按下的时候,会发生以下转换:
前面提到了Qt 键值并没有包含所有的按键,因此可以想到,在 virtualKey
转换的时候,两个不同的按键1都被转换( 映射 )成了 Qt::Key_1
。
当然,如果仅仅是这样就算了,我们完全可以使用 nativeVirtualKey
来区分( 在C++中 ),然鹅在 Qml 中,恰好就没有 nativeVirtualKey
,这™就很尴尬了好吗。
由于某些应用的特殊性( 例如:远程控制 ),因此我必须知道,到底是哪个按键按下了。
能想到的解决方法有两个:
-
不使用 Qml 的
KeyEvent
,而是使用keyPressEvent(QKeyEvent *event)
提供的QKeyEvent::nativeVirtualKey
来区分。 -
使用 Qml 的
KeyEvent
,但需要进行额外的判断,对于这种方法,由于所有的按键都有其scanCode
,所以我们最后还是可以通过scanCode
来区分不同的按键。
【结语】
最后讲一下题外话。
因为我做的是远程控制,所以仅仅是区分不同的按键远远不够。
例如 Windows API
的 SendInput
或 keybd_event
( 被 SendInput
取代) 模拟按键事件时,就需要 virtualKey
值,也就是说最终还是得把 Qt Key
转换成 virtualKey
。
所以在使用第二种方法的时候,仍然要进行转换,这里给一个 KDE 的工具(但是不完整而且仍不能区分所有键,所以我自己用的改进了一下):KWindowSystem - kkeyserver.cpp Source File