9#include <QtWaylandCompositor/QWaylandKeymap>
10#include <QtWaylandCompositor/QWaylandCompositor>
11#include <QtWaylandCompositor/QWaylandSeat>
12#include <QtWaylandCompositor/QWaylandClient>
14#include <QtCore/QFile>
15#include <QtCore/QStandardPaths>
20#if QT_CONFIG(xkbcommon)
23#include <xkbcommon/xkbcommon-names.h>
26#ifndef XKB_MOD_NAME_MOD5
27#define XKB_MOD_NAME_MOD5 "Mod5"
33QWaylandKeyboardPrivate::QWaylandKeyboardPrivate(QWaylandSeat *seat)
38QWaylandKeyboardPrivate::~QWaylandKeyboardPrivate()
40#if QT_CONFIG(xkbcommon)
43 munmap(keymap_area, keymap_size);
50QWaylandKeyboardPrivate *QWaylandKeyboardPrivate::get(QWaylandKeyboard *keyboard)
52 return keyboard->d_func();
55void QWaylandKeyboardPrivate::checkFocusResource(Resource *keyboardResource)
57 if (!keyboardResource || !focus)
61 if (focusResource == keyboardResource)
65 if (wl_resource_get_client(focus->resource()) == keyboardResource->client()) {
66 sendEnter(focus, keyboardResource);
67 focusResource = keyboardResource;
71void QWaylandKeyboardPrivate::sendEnter(QWaylandSurface *surface, Resource *keyboardResource)
73 uint32_t serial = compositor()->nextSerial();
74 send_modifiers(keyboardResource->handle, serial, modsDepressed, modsLatched, modsLocked, group);
75 send_enter(keyboardResource->handle, serial, surface->resource(), QByteArray::fromRawData((
char *)keys.data(), keys.size() *
sizeof(uint32_t)));
78void QWaylandKeyboardPrivate::focused(QWaylandSurface *surface)
80 if (surface && surface->isCursorSurface())
82 if (focus != surface) {
84 uint32_t serial = compositor()->nextSerial();
85 send_leave(focusResource->handle, serial, focus->resource());
87 focusDestroyListener.reset();
89 focusDestroyListener.listenForDestruction(surface->resource());
92 Resource *resource = surface ? resourceMap().value(surface->waylandClient()) : 0;
94 if (resource && (focus != surface || focusResource != resource))
95 sendEnter(surface, resource);
97 focusResource = resource;
99 Q_EMIT q_func()->focusChanged(focus);
103void QWaylandKeyboardPrivate::keyboard_bind_resource(wl_keyboard::Resource *resource)
106 if (resource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
107 send_repeat_info(resource->handle, repeatRate, repeatDelay);
109#if QT_CONFIG(xkbcommon)
111 send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
112 keymap_fd, keymap_size);
116 int null_fd = open(
"/dev/null", O_RDONLY);
117 send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP,
121 checkFocusResource(resource);
124void QWaylandKeyboardPrivate::keyboard_destroy_resource(wl_keyboard::Resource *resource)
126 if (focusResource == resource)
127 focusResource =
nullptr;
130void QWaylandKeyboardPrivate::keyboard_release(wl_keyboard::Resource *resource)
132 wl_resource_destroy(resource->handle);
135void QWaylandKeyboardPrivate::keyEvent(uint code, uint32_t state)
137 uint key = toWaylandKey(code);
139 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
146void QWaylandKeyboardPrivate::sendKeyEvent(uint code, uint32_t state)
148 uint32_t time = compositor()->currentTimeMsecs();
149 uint32_t serial = compositor()->nextSerial();
150 uint key = toWaylandKey(code);
152 send_key(focusResource->handle, serial, time, key, state);
155#if QT_CONFIG(xkbcommon)
156void QWaylandKeyboardPrivate::maybeUpdateXkbScanCodeTable()
158 if (!scanCodesByQtKey.isEmpty() || !xkbState())
161 if (xkb_keymap *keymap = xkb_state_get_keymap(xkbState())) {
162 xkb_keymap_key_for_each(keymap, [](xkb_keymap *keymap, xkb_keycode_t keycode,
void *d){
163 auto *scanCodesByQtKey =
static_cast<QMap<ScanCodeKey, uint>*>(d);
164 uint numLayouts = xkb_keymap_num_layouts_for_key(keymap, keycode);
165 for (uint layout = 0; layout < numLayouts; ++layout) {
166 const xkb_keysym_t *syms =
nullptr;
167 xkb_keymap_key_get_syms_by_level(keymap, keycode, layout, 0, &syms);
171 Qt::KeyboardModifiers mods = {};
172 int qtKey = QXkbCommon::keysymToQtKey(syms[0], mods,
nullptr, 0,
false,
false);
174 scanCodesByQtKey->insert({layout, qtKey}, keycode);
176 }, &scanCodesByQtKey);
178 shiftIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
179 controlIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
180 altIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT);
181 mod5Index = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD5);
185void QWaylandKeyboardPrivate::resetKeyboardState()
190 while (!keys.isEmpty()) {
191 uint32_t code = fromWaylandKey(keys.first());
192 keyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED);
193 updateModifierState(code, WL_KEYBOARD_KEY_STATE_RELEASED);
198void QWaylandKeyboardPrivate::updateModifierState(uint code, uint32_t state)
200#if QT_CONFIG(xkbcommon)
204 xkb_state_update_key(xkbState(), code, state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP);
206 uint32_t modsDepressed = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_DEPRESSED);
207 uint32_t modsLatched = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_LATCHED);
208 uint32_t modsLocked = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_LOCKED);
209 uint32_t group = xkb_state_serialize_layout(xkbState(), XKB_STATE_LAYOUT_EFFECTIVE);
211 if (
this->modsDepressed == modsDepressed
212 &&
this->modsLatched == modsLatched
213 &&
this->modsLocked == modsLocked
214 &&
this->group == group)
217 this->modsDepressed = modsDepressed;
218 this->modsLatched = modsLatched;
219 this->modsLocked = modsLocked;
223 send_modifiers(focusResource->handle, compositor()->nextSerial(), modsDepressed,
224 modsLatched, modsLocked, group);
226 Qt::KeyboardModifiers currentState = Qt::NoModifier;
227 if (xkb_state_mod_index_is_active(xkbState(), shiftIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
228 currentState |= Qt::ShiftModifier;
229 if (xkb_state_mod_index_is_active(xkbState(), controlIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
230 currentState |= Qt::ControlModifier;
231 if (xkb_state_mod_index_is_active(xkbState(), altIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
232 currentState |= Qt::AltModifier;
233 if (mod5Index != XKB_MOD_INVALID
234 && xkb_state_mod_index_is_active(xkbState(), mod5Index, XKB_STATE_MODS_EFFECTIVE) == 1)
235 currentState |= Qt::GroupSwitchModifier;
236 currentModifierState = currentState;
247void QWaylandKeyboardPrivate::maybeUpdateKeymap()
251 if (!pendingKeymap || !keys.isEmpty())
254 pendingKeymap =
false;
255#if QT_CONFIG(xkbcommon)
260 const auto resMap = resourceMap();
261 for (Resource *res : resMap) {
262 send_keymap(res->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymap_fd, keymap_size);
265 xkb_state_update_mask(xkbState(), 0, modsLatched, modsLocked, 0, 0, 0);
267 send_modifiers(focusResource->handle,
268 compositor()->nextSerial(),
283#define QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET 8
285uint QWaylandKeyboardPrivate::fromWaylandKey(
const uint key)
287#if QT_CONFIG(xkbcommon)
288 const uint offset = QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET;
295uint QWaylandKeyboardPrivate::toWaylandKey(
const uint nativeScanCode)
297#if QT_CONFIG(xkbcommon)
298 const uint offset = QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET;
299 Q_ASSERT(nativeScanCode >= offset);
300 return nativeScanCode - offset;
302 return nativeScanCode;
306#if QT_CONFIG(xkbcommon)
307static int createAnonymousFile(size_t size)
309 QString path = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
313 QByteArray name = QFile::encodeName(path + QStringLiteral(
"/qtwayland-XXXXXX"));
315 int fd = mkstemp(name.data());
319 long flags = fcntl(fd, F_GETFD);
320 if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
324 unlink(name.constData());
329 if (ftruncate(fd, size) < 0) {
337void QWaylandKeyboardPrivate::createXKBState(xkb_keymap *keymap)
339 char *keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
341 qWarning(
"Failed to compile global XKB keymap");
345 keymap_size = strlen(keymap_str) + 1;
348 keymap_fd = createAnonymousFile(keymap_size);
350 qWarning(
"Failed to create anonymous file of size %lu",
static_cast<
unsigned long>(keymap_size));
354 keymap_area =
static_cast<
char *>(mmap(
nullptr, keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, keymap_fd, 0));
355 if (keymap_area == MAP_FAILED) {
358 qWarning(
"Failed to map shared memory segment");
362 strcpy(keymap_area, keymap_str);
365 mXkbState.reset(xkb_state_new(keymap));
367 qWarning(
"Failed to create XKB state");
370void QWaylandKeyboardPrivate::createXKBKeymap()
375 QWaylandKeymap *keymap = seat->keymap();
376 QByteArray rules = keymap->rules().toLocal8Bit();
377 QByteArray model = keymap->model().toLocal8Bit();
378 QByteArray layout = keymap->layout().toLocal8Bit();
379 QByteArray variant = keymap->variant().toLocal8Bit();
380 QByteArray options = keymap->options().toLocal8Bit();
382 if (!layout.isEmpty() && !layout.contains(
"us")) {
385 layout.append(
",us");
389 struct xkb_rule_names rule_names = {
397 QXkbCommon::ScopedXKBKeymap xkbKeymap(xkb_keymap_new_from_names(xkbContext(), &rule_names,
398 XKB_KEYMAP_COMPILE_NO_FLAGS));
400 scanCodesByQtKey.clear();
401 createXKBState(xkbKeymap.get());
403 qWarning(
"Failed to load the '%s' XKB keymap.", qPrintable(keymap->layout()));
408void QWaylandKeyboardPrivate::sendRepeatInfo()
410 const auto resMap = resourceMap();
411 for (Resource *resource : resMap) {
412 if (resource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
413 send_repeat_info(resource->handle, repeatRate, repeatDelay);
418
419
420
421
422
423
424
425
428
429
430QWaylandKeyboard::QWaylandKeyboard(QWaylandSeat *seat, QObject *parent)
431 : QWaylandObject(*
new QWaylandKeyboardPrivate(seat), parent)
433 Q_D(QWaylandKeyboard);
434 connect(&d->focusDestroyListener, &QWaylandDestroyListener::fired,
this, &QWaylandKeyboard::focusDestroyed);
435 auto keymap = seat->keymap();
436 connect(keymap, &QWaylandKeymap::layoutChanged,
this, &QWaylandKeyboard::updateKeymap);
437 connect(keymap, &QWaylandKeymap::variantChanged,
this, &QWaylandKeyboard::updateKeymap);
438 connect(keymap, &QWaylandKeymap::optionsChanged,
this, &QWaylandKeyboard::updateKeymap);
439 connect(keymap, &QWaylandKeymap::rulesChanged,
this, &QWaylandKeyboard::updateKeymap);
440 connect(keymap, &QWaylandKeymap::modelChanged,
this, &QWaylandKeyboard::updateKeymap);
441#if QT_CONFIG(xkbcommon)
442 d->createXKBKeymap();
447
448
449QWaylandSeat *QWaylandKeyboard::seat()
const
451 Q_D(
const QWaylandKeyboard);
456
457
458QWaylandCompositor *QWaylandKeyboard::compositor()
const
460 Q_D(
const QWaylandKeyboard);
461 return d->seat->compositor();
465
466
467void QWaylandKeyboard::focusDestroyed(
void *data)
470 Q_D(QWaylandKeyboard);
471 d->focusDestroyListener.reset();
474 d->focusResource =
nullptr;
477void QWaylandKeyboard::updateKeymap()
479 Q_D(QWaylandKeyboard);
480 d->pendingKeymap =
true;
481 d->maybeUpdateKeymap();
485
486
487QWaylandClient *QWaylandKeyboard::focusClient()
const
489 Q_D(
const QWaylandKeyboard);
490 if (!d->focusResource)
492 return QWaylandClient::fromWlClient(compositor(), d->focusResource->client());
496
497
498void QWaylandKeyboard::sendKeyModifiers(QWaylandClient *client, uint32_t serial)
500 Q_D(QWaylandKeyboard);
501 QtWaylandServer::wl_keyboard::Resource *resource = d->resourceMap().value(client->client());
503 d->send_modifiers(resource->handle, serial, d->modsDepressed, d->modsLatched, d->modsLocked, d->group);
507
508
509void QWaylandKeyboard::sendKeyPressEvent(uint code)
511 Q_D(QWaylandKeyboard);
512 d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_PRESSED);
516
517
518void QWaylandKeyboard::sendKeyReleaseEvent(uint code)
520 Q_D(QWaylandKeyboard);
521 d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED);
524void QWaylandKeyboardPrivate::checkAndRepairModifierState(QKeyEvent *ke)
526#if QT_CONFIG(xkbcommon)
527 if (ke->modifiers() != currentModifierState) {
528 if (focusResource && ke->key() != Qt::Key_Shift
529 && ke->key() != Qt::Key_Control && ke->key() != Qt::Key_Alt
530 && ke->key() != Qt::Key_AltGr) {
537 if (shiftIndex == 0 && controlIndex == 0)
538 maybeUpdateXkbScanCodeTable();
540 if (ke->modifiers() & Qt::ShiftModifier)
541 mods |= 1 << shiftIndex;
542 if (ke->modifiers() & Qt::ControlModifier)
543 mods |= 1 << controlIndex;
544 if (ke->modifiers() & Qt::AltModifier)
545 mods |= 1 << altIndex;
546 if ((ke->modifiers() & Qt::GroupSwitchModifier) && mod5Index != XKB_MOD_INVALID)
547 mods |= 1 << mod5Index;
548 qCDebug(qLcWaylandCompositor) <<
"Keyboard modifier state mismatch detected for event" << ke <<
"state:" << currentModifierState <<
"repaired:" << Qt::hex << mods;
550 send_modifiers(focusResource->handle, compositor()->nextSerial(), mods,
551 0, modsLocked, group);
552 currentModifierState = ke->modifiers();
561
562
563
564
565
568
569
570quint32 QWaylandKeyboard::repeatRate()
const
572 Q_D(
const QWaylandKeyboard);
573 return d->repeatRate;
577
578
579void QWaylandKeyboard::setRepeatRate(quint32 rate)
581 Q_D(QWaylandKeyboard);
583 if (d->repeatRate == rate)
588 d->repeatRate = rate;
589 Q_EMIT repeatRateChanged(rate);
593
594
595
596
597
600
601
602quint32 QWaylandKeyboard::repeatDelay()
const
604 Q_D(
const QWaylandKeyboard);
605 return d->repeatDelay;
609
610
611void QWaylandKeyboard::setRepeatDelay(quint32 delay)
613 Q_D(QWaylandKeyboard);
615 if (d->repeatDelay == delay)
620 d->repeatDelay = delay;
621 Q_EMIT repeatDelayChanged(delay);
625
626
627QWaylandSurface *QWaylandKeyboard::focus()
const
629 Q_D(
const QWaylandKeyboard);
634
635
636void QWaylandKeyboard::setFocus(QWaylandSurface *surface)
638 Q_D(QWaylandKeyboard);
643
644
645void QWaylandKeyboard::addClient(QWaylandClient *client, uint32_t id, uint32_t version)
647 Q_D(QWaylandKeyboard);
648 d->add(client->client(), id, qMin<uint32_t>(QtWaylandServer::wl_keyboard::interfaceVersion(), version));
651uint QWaylandKeyboard::keyToScanCode(
int qtKey)
const
654#if QT_CONFIG(xkbcommon)
655 Q_D(
const QWaylandKeyboard);
656 const_cast<QWaylandKeyboardPrivate *>(d)->maybeUpdateXkbScanCodeTable();
657 scanCode = d->scanCodesByQtKey.value({d->group, qtKey}, 0);
666#include "moc_qwaylandkeyboard.cpp"