最近在做一个数控机床CNC的嵌入式QT项目,当用户按设备上的小键盘区1 - 9的按键时,需要映射到其它的键值,而不是Qt::Key_1 - Qt::Key_9。
尝试过单独起一个线程,从linux直接读取键值,用open("/dev/input/event3", O_RDWR)这种方法;也尝试过直接调QKeyEvent的nativeScanCode()方法获取硬件按键的键值。但这两种方法都有同一个问题,就是如果我有文本编辑器控件,这时用户按了小键盘的1,虽然我可以捕获这个scan code硬件按键的键值去处理自己的逻辑,但我却无法阻止文本编辑器上输入了个1,当然,我更不想自己去自定义一个文本编辑器。
最后,我想到了改QT源码中键值映射这部分的代码,然后重新编译QT库放到板卡上。
下面来看QT这部分的源码:
首先看qkbdlinuxinput_qws.cpp
QWSLinuxInputKbPrivate::QWSLinuxInputKbPrivate(QWSLinuxInputKeyboardHandler *h, const QString &device)
: m_handler(h), m_fd(-1), m_tty_fd(-1), m_orig_kbmode(K_XLATE)
{
.
.
.
QString dev = QLatin1String("/dev/input/event1");
.
.
.
m_fd = QT_OPEN(dev.toLocal8Bit().constData(), O_RDWR, 0);
.
.
.
connect(notifier, SIGNAL(activated(int)), this, SLOT(readKeycode()));
.
.
.
}
先给dev 指定linux输入设备,这里是/dev/input/event1。然后调用QT_OPEN打开这个设备,最后指定信号槽,当收到信号时,去调用readKeycode()方法读取键值。
接下来看readKeycode()方法
void QWSLinuxInputKbPrivate::readKeycode()
{
.
.
.
QWSKeyboardHandler::KeycodeAction ka;
ka = m_handler->processKeycode(code, value != 0, value == 2);
.
.
.
}
直接将读取出来的code键值传给QWSKeyboardHandler的processKeycode方法去处理。
我们再来看QWSKeyboardHandler的processKeycode()方法
QWSKeyboardHandler::KeycodeAction QWSKeyboardHandler::processKeycode(quint16 keycode, bool pressed, bool autorepeat)
{
.
.
.
// get a specific and plain mapping for the keycode and the current modifiers
for (int i = 0; i < d->m_keymap_size && !(map_plain && map_withmod); ++i) {
const QWSKeyboard::Mapping *m = d->m_keymap + i;
if (m->keycode == keycode) {
if (m->modifiers == 0)
map_plain = m;
.
.
.
const QWSKeyboard::Mapping *it = map_withmod ? map_withmod : map_plain;
.
.
.
quint16 unicode = it->unicode;
quint32 qtcode = it->qtcode;
.
.
.
processKeyEvent(unicode, qtcode & ~modmask, Qt::KeyboardModifiers(qtcode & modmask), pressed, autorepeat);
.
.
.
}
先遍历d->m_keymap键值表,然后根据scan code的键值拿到对应键值表的 QWSKeyboard::Mapping结构体,并将这个结构体赋值给指针it,这个it->qtcode就是映射后的QT键值,最后再调processKeyEvent将这个映射后的键值交给后面的逻辑去处理。
从这里,我们可以看出,想要修改QT键值映射,那么必须修改这个QT的键值映射表,也就是qkbd_defaultmap_qws_p.h这个头文件。从QWSKeyboard::Mapping结构体中,我们可以看到,这个二维数组的每个数据项,第一个数据是scan code,也就是从linux层返回的键值;而第三个数据项就是映射后的QT键值。
所以,如果想修改键值映射,那么直接修改qkbd_defaultmap_qws_p.h这个键值表头文件,然后重新编译QT库放到板卡上就可以了。