70 const QString &specification,
71 const QString &defaultKeymapFile)
73 qCDebug(qLcEvdevKey,
"Try to create keyboard handler for \"%ls\" \"%ls\"",
74 qUtf16Printable(device), qUtf16Printable(specification));
76 QString keymapFile = defaultKeymapFile;
77 int repeatDelay = 400;
79 bool disableZap =
false;
80 bool enableCompose =
false;
83 const auto args = QStringView{specification}.split(u':');
84 for (
const auto &arg : args) {
85 if (arg.startsWith(
"keymap="_L1))
86 keymapFile = arg.mid(7).toString();
87 else if (arg ==
"disable-zap"_L1)
89 else if (arg ==
"enable-compose"_L1)
91 else if (arg.startsWith(
"repeat-delay="_L1))
92 repeatDelay = arg.mid(13).toInt();
93 else if (arg.startsWith(
"repeat-rate="_L1))
94 repeatRate = arg.mid(12).toInt();
95 else if (arg.startsWith(
"grab="_L1))
96 grab = arg.mid(5).toInt();
99 qCDebug(qLcEvdevKey,
"Opening keyboard at %ls", qUtf16Printable(device));
101 QFdContainer fd(qt_safe_open(device.toLocal8Bit().constData(), O_RDWR | O_NDELAY, 0));
103 qCDebug(qLcEvdevKey,
"Keyboard device could not be opened as read-write, trying read-only");
104 fd.reset(qt_safe_open(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0));
107 ::ioctl(fd.get(), EVIOCGRAB, grab);
108 if (repeatDelay > 0 && repeatRate > 0) {
109 int kbdrep[2] = { repeatDelay, repeatRate };
110 ::ioctl(fd.get(), EVIOCSREP, kbdrep);
113 return std::unique_ptr<QEvdevKeyboardHandler>(
new QEvdevKeyboardHandler(device, fd, disableZap, enableCompose, keymapFile));
115 qErrnoWarning(
"Cannot open keyboard input device '%ls'", qUtf16Printable(device));
138 struct ::input_event buffer[32];
142 int result = qt_safe_read(m_fd.get(),
reinterpret_cast<
char *>(buffer) + n,
sizeof(buffer) - n);
145 qWarning(
"evdevkeyboard: Got EOF from the input device");
147 }
else if (result < 0) {
148 if (errno != EINTR && errno != EAGAIN) {
149 qErrnoWarning(
"evdevkeyboard: Could not read from input device");
152 if (errno == ENODEV) {
161 if (n %
sizeof(buffer[0]) == 0)
166 n /=
sizeof(buffer[0]);
168 for (
int i = 0; i < n; ++i) {
169 if (buffer[i].type !=
EV_KEY)
172 quint16 code = buffer[i].code;
173 qint32 value = buffer[i].value;
176 ka = processKeycode(code, value != 0, value == 2);
179 case QKeycodeAction::CapsLockOn:
180 case QKeycodeAction::CapsLockOff:
181 switchLed(LED_CAPSL, ka == QKeycodeAction::CapsLockOn);
184 case QKeycodeAction::NumLockOn:
185 case QKeycodeAction::NumLockOff:
186 switchLed(LED_NUML, ka == QKeycodeAction::NumLockOn);
189 case QKeycodeAction::ScrollLockOn:
190 case QKeycodeAction::ScrollLockOff:
191 switchLed(LED_SCROLLL, ka == QKeycodeAction::ScrollLockOn);
218 QKeycodeAction result = QKeycodeAction::None;
219 bool first_press = pressed && !autorepeat;
221 const QKeyboardMap::Mapping *map_plain =
nullptr;
222 const QKeyboardMap::Mapping *map_withmod =
nullptr;
224 quint8 modifiers = m_modifiers;
227 for (
int i = 0; i < m_keymap_size && !(map_plain && map_withmod); ++i) {
228 const QKeyboardMap::Mapping *m = m_keymap + i;
229 if (m->keycode == keycode) {
230 if (m->modifiers == 0)
233 quint8 testmods = m_modifiers;
234 if (m_locks[0] && (m->flags & QKeyboardMap::IsLetter))
235 testmods ^= QKeyboardMap::ModShift;
237 testmods ^= QKeyboardMap::ModAltGr;
238 if (m->modifiers == testmods)
243 if (m_locks[0] && map_withmod && (map_withmod->flags & QKeyboardMap::IsLetter))
244 modifiers ^= QKeyboardMap::ModShift;
246 qCDebug(qLcEvdevKeyMap,
"Processing key event: keycode=%3d, modifiers=%02x pressed=%d, autorepeat=%d | plain=%d, withmod=%d, size=%d",
247 keycode, modifiers, pressed ? 1 : 0, autorepeat ? 1 : 0,
248 int(map_plain ? map_plain - m_keymap : -1),
249 int(map_withmod ? map_withmod - m_keymap : -1),
252 const QKeyboardMap::Mapping *it = map_withmod ? map_withmod : map_plain;
256 qCDebug(qLcEvdevKeyMap,
"Could not find a suitable mapping for keycode: %3d, modifiers: %02x", keycode, modifiers);
261 quint16 unicode = it->unicode;
262 quint32 qtcode = it->qtcode;
264 if ((it->flags & QKeyboardMap::IsModifier) && it->special) {
267 m_modifiers |= quint8(it->special);
269 m_modifiers &= ~quint8(it->special);
273 quint8 &lock = m_locks[qtcode - Qt::Key_CapsLock];
277 case Qt::Key_CapsLock : result = lock ? QKeycodeAction::CapsLockOn : QKeycodeAction::CapsLockOff;
break;
278 case Qt::Key_NumLock : result = lock ? QKeycodeAction::NumLockOn : QKeycodeAction::NumLockOff;
break;
279 case Qt::Key_ScrollLock: result = lock ? QKeycodeAction::ScrollLockOn : QKeycodeAction::ScrollLockOff;
break;
283 }
else if ((it->flags & QKeyboardMap::IsSystem) && it->special && first_press) {
284 switch (it->special) {
285 case QKeyboardMap::SystemReboot:
286 result = QKeycodeAction::Reboot;
289 case QKeyboardMap::SystemZap:
294 case QKeyboardMap::SystemConsolePrevious:
295 result = QKeycodeAction::PreviousConsole;
298 case QKeyboardMap::SystemConsoleNext:
299 result = QKeycodeAction::NextConsole;
303 if (it->special >= QKeyboardMap::SystemConsoleFirst &&
304 it->special <= QKeyboardMap::SystemConsoleLast) {
305 result = QKeycodeAction(
306 static_cast<
int>(QKeycodeAction::SwitchConsoleFirst)
307 + (it->special &
static_cast<
int>(QKeyboardMap::SystemConsoleMask)
308 &
static_cast<
int>(QKeycodeAction::SwitchConsoleMask)));
319 }
else if ((it->flags & QKeyboardMap::IsDead) && m_do_compose) {
321 if (first_press && m_composing == 1 && m_dead_unicode == unicode) {
324 }
else if (first_press && unicode != 0xffff) {
325 m_dead_unicode = unicode;
340 if ((it == map_plain && it != map_withmod) ||
341 (map_withmod && !(map_withmod->qtcode & modmask))) {
342 qtcode |= QKeyboardMap::toQtModifiers(modifiers);
345 if (m_composing == 2 && first_press && !(it->flags & QKeyboardMap::IsModifier)) {
347 if (unicode != 0xffff) {
350 for ( ; idx < m_keycompose_size; ++idx) {
351 if (m_keycompose[idx].first == unicode)
354 if (idx < m_keycompose_size) {
356 m_dead_unicode = unicode;
366 }
else if (m_composing == 1 && first_press && !(it->flags & QKeyboardMap::IsModifier)) {
369 if (unicode != 0xffff) {
372 for ( ; idx < m_keycompose_size; ++idx) {
373 if (m_keycompose[idx].first == m_dead_unicode && m_keycompose[idx].second == unicode)
376 if (idx < m_keycompose_size) {
377 quint16 composed = m_keycompose[idx].result;
378 if (composed != 0xffff) {
386 unicode = m_dead_unicode;
394 Qt::KeyboardModifiers qtmods = Qt::KeyboardModifiers(qtcode & modmask);
399 qCDebug(qLcEvdevKeyMap,
"Processing: uni=%04x, qt=%08x, qtmod=%08x", unicode, qtcode,
int(qtmods));
402 if (!m_locks[1] && (qtmods & Qt::KeypadModifier) &&
451 processKeyEvent(keycode, unicode, qtcode, qtmods, pressed, autorepeat);
459 qCDebug(qLcEvdevKey,
"Unload current keymap and restore built-in");
461 if (m_keymap && m_keymap != s_keymap_default)
463 if (m_keycompose && m_keycompose != s_keycompose_default)
464 delete [] m_keycompose;
466 m_keymap = s_keymap_default;
467 m_keymap_size =
sizeof(s_keymap_default) /
sizeof(s_keymap_default[0]);
468 m_keycompose = s_keycompose_default;
469 m_keycompose_size =
sizeof(s_keycompose_default) /
sizeof(s_keycompose_default[0]);
473 memset(m_locks, 0,
sizeof(m_locks));
475 m_dead_unicode = 0xffff;
479 memset(ledbits, 0,
sizeof(ledbits));
480 if (::ioctl(m_fd.get(), EVIOCGLED(
sizeof(ledbits)), ledbits) < 0) {
481 qWarning(
"evdevkeyboard: Failed to query led states");
482 switchLed(LED_NUML,
false);
483 switchLed(LED_CAPSL,
false);
484 switchLed(LED_SCROLLL,
false);
487 if ((ledbits[0]&0x02) > 0)
490 if ((ledbits[0]&0x01) > 0)
493 if ((ledbits[0]&0x04) > 0)
495 qCDebug(qLcEvdevKey,
"numlock=%d , capslock=%d, scrolllock=%d", m_locks[1], m_locks[0], m_locks[2]);
503 qCDebug(qLcEvdevKey,
"Loading keymap %ls", qUtf16Printable(file));
507 if (!f.open(QIODevice::ReadOnly)) {
508 qWarning(
"Could not open keymap file '%ls'", qUtf16Printable(file));
520 quint32 qmap_magic, qmap_version, qmap_keymap_size, qmap_keycompose_size;
524 ds >> qmap_magic >> qmap_version >> qmap_keymap_size >> qmap_keycompose_size;
526 if (ds.status() != QDataStream::Ok || qmap_magic != QKeyboardMap::FileMagic || qmap_version != 1 || qmap_keymap_size == 0) {
527 qWarning(
"'%ls' is not a valid .qmap keymap file", qUtf16Printable(file));
531 QKeyboardMap::Mapping *qmap_keymap =
new QKeyboardMap::Mapping[qmap_keymap_size];
532 QKeyboardMap::Composing *qmap_keycompose = qmap_keycompose_size ?
new QKeyboardMap::Composing[qmap_keycompose_size] : 0;
534 for (quint32 i = 0; i < qmap_keymap_size; ++i)
535 ds >> qmap_keymap[i];
536 for (quint32 i = 0; i < qmap_keycompose_size; ++i)
537 ds >> qmap_keycompose[i];
539 if (ds.status() != QDataStream::Ok) {
540 delete [] qmap_keymap;
541 delete [] qmap_keycompose;
543 qWarning(
"Keymap file '%ls' cannot be loaded.", qUtf16Printable(file));
550 m_keymap = qmap_keymap;
551 m_keymap_size = qmap_keymap_size;
552 m_keycompose = qmap_keycompose;
553 m_keycompose_size = qmap_keycompose_size;