8#include <QtWaylandCompositor/QWaylandKeymap>
9#include <QtWaylandCompositor/QWaylandCompositor>
10#include <QtWaylandCompositor/QWaylandSeat>
11#include <QtWaylandCompositor/QWaylandClient>
13#include <QtCore/QFile>
14#include <QtCore/QStandardPaths>
19#if QT_CONFIG(xkbcommon)
22#include <xkbcommon/xkbcommon-names.h>
25#ifndef XKB_MOD_NAME_MOD5
26#define XKB_MOD_NAME_MOD5 "Mod5"
32QWaylandKeyboardPrivate::QWaylandKeyboardPrivate(QWaylandSeat *seat)
37QWaylandKeyboardPrivate::~QWaylandKeyboardPrivate()
39#if QT_CONFIG(xkbcommon)
42 munmap(keymap_area, keymap_size);
49QWaylandKeyboardPrivate *QWaylandKeyboardPrivate::get(QWaylandKeyboard *keyboard)
51 return keyboard->d_func();
54void QWaylandKeyboardPrivate::checkFocusResource(Resource *keyboardResource)
56 if (!keyboardResource || !focus)
60 if (focusResource == keyboardResource)
64 if (wl_resource_get_client(focus->resource()) == keyboardResource->client()) {
65 sendEnter(focus, keyboardResource);
66 focusResource = keyboardResource;
70void QWaylandKeyboardPrivate::sendEnter(QWaylandSurface *surface, Resource *keyboardResource)
72 uint32_t serial = compositor()->nextSerial();
73 send_modifiers(keyboardResource->handle, serial, modsDepressed, modsLatched, modsLocked, group);
74 send_enter(keyboardResource->handle, serial, surface->resource(), QByteArray::fromRawData((
char *)keys.data(), keys.size() *
sizeof(uint32_t)));
77void QWaylandKeyboardPrivate::focused(QWaylandSurface *surface)
79 if (surface && surface->isCursorSurface())
81 if (focus != surface) {
83 uint32_t serial = compositor()->nextSerial();
84 send_leave(focusResource->handle, serial, focus->resource());
86 focusDestroyListener.reset();
88 focusDestroyListener.listenForDestruction(surface->resource());
91 Resource *resource = surface ? resourceMap().value(surface->waylandClient()) : 0;
93 if (resource && (focus != surface || focusResource != resource))
94 sendEnter(surface, resource);
96 focusResource = resource;
98 Q_EMIT q_func()->focusChanged(focus);
102void QWaylandKeyboardPrivate::keyboard_bind_resource(wl_keyboard::Resource *resource)
105 if (resource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
106 send_repeat_info(resource->handle, repeatRate, repeatDelay);
108#if QT_CONFIG(xkbcommon)
110 send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
111 keymap_fd, keymap_size);
115 int null_fd = open(
"/dev/null", O_RDONLY);
116 send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP,
120 checkFocusResource(resource);
123void QWaylandKeyboardPrivate::keyboard_destroy_resource(wl_keyboard::Resource *resource)
125 if (focusResource == resource)
126 focusResource =
nullptr;
129void QWaylandKeyboardPrivate::keyboard_release(wl_keyboard::Resource *resource)
131 wl_resource_destroy(resource->handle);
134void QWaylandKeyboardPrivate::keyEvent(uint code, uint32_t state)
136 uint key = toWaylandKey(code);
138 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
145void QWaylandKeyboardPrivate::sendKeyEvent(uint code, uint32_t state)
147 uint32_t time = compositor()->currentTimeMsecs();
148 uint32_t serial = compositor()->nextSerial();
149 uint key = toWaylandKey(code);
151 send_key(focusResource->handle, serial, time, key, state);
154#if QT_CONFIG(xkbcommon)
155void QWaylandKeyboardPrivate::maybeUpdateXkbScanCodeTable()
157 if (!scanCodesByQtKey.isEmpty() || !xkbState())
160 if (xkb_keymap *keymap = xkb_state_get_keymap(xkbState())) {
161 xkb_keymap_key_for_each(keymap, [](xkb_keymap *keymap, xkb_keycode_t keycode,
void *d){
162 auto *scanCodesByQtKey =
static_cast<QMap<ScanCodeKey, uint>*>(d);
163 uint numLayouts = xkb_keymap_num_layouts_for_key(keymap, keycode);
164 for (uint layout = 0; layout < numLayouts; ++layout) {
165 const xkb_keysym_t *syms =
nullptr;
166 xkb_keymap_key_get_syms_by_level(keymap, keycode, layout, 0, &syms);
170 Qt::KeyboardModifiers mods = {};
171 int qtKey = QXkbCommon::keysymToQtKey(syms[0], mods,
nullptr, 0,
false,
false);
173 scanCodesByQtKey->insert({layout, qtKey}, keycode);
175 }, &scanCodesByQtKey);
177 shiftIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
178 controlIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
179 altIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT);
180 mod5Index = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD5);
184void QWaylandKeyboardPrivate::resetKeyboardState()
189 while (!keys.isEmpty()) {
190 uint32_t code = fromWaylandKey(keys.first());
191 keyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED);
192 updateModifierState(code, WL_KEYBOARD_KEY_STATE_RELEASED);
197void QWaylandKeyboardPrivate::updateModifierState(uint code, uint32_t state)
199#if QT_CONFIG(xkbcommon)
203 xkb_state_update_key(xkbState(), code, state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP);
205 uint32_t modsDepressed = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_DEPRESSED);
206 uint32_t modsLatched = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_LATCHED);
207 uint32_t modsLocked = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_LOCKED);
208 uint32_t group = xkb_state_serialize_layout(xkbState(), XKB_STATE_LAYOUT_EFFECTIVE);
210 if (
this->modsDepressed == modsDepressed
211 &&
this->modsLatched == modsLatched
212 &&
this->modsLocked == modsLocked
213 &&
this->group == group)
216 this->modsDepressed = modsDepressed;
217 this->modsLatched = modsLatched;
218 this->modsLocked = modsLocked;
222 send_modifiers(focusResource->handle, compositor()->nextSerial(), modsDepressed,
223 modsLatched, modsLocked, group);
225 Qt::KeyboardModifiers currentState = Qt::NoModifier;
226 if (xkb_state_mod_index_is_active(xkbState(), shiftIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
227 currentState |= Qt::ShiftModifier;
228 if (xkb_state_mod_index_is_active(xkbState(), controlIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
229 currentState |= Qt::ControlModifier;
230 if (xkb_state_mod_index_is_active(xkbState(), altIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
231 currentState |= Qt::AltModifier;
232 if (mod5Index != XKB_MOD_INVALID
233 && xkb_state_mod_index_is_active(xkbState(), mod5Index, XKB_STATE_MODS_EFFECTIVE) == 1)
234 currentState |= Qt::GroupSwitchModifier;
235 currentModifierState = currentState;
246void QWaylandKeyboardPrivate::maybeUpdateKeymap()
250 if (!pendingKeymap || !keys.isEmpty())
253 pendingKeymap =
false;
254#if QT_CONFIG(xkbcommon)
259 const auto resMap = resourceMap();
260 for (Resource *res : resMap) {
261 send_keymap(res->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymap_fd, keymap_size);
264 xkb_state_update_mask(xkbState(), 0, modsLatched, modsLocked, 0, 0, 0);
266 send_modifiers(focusResource->handle,
267 compositor()->nextSerial(),
282#define QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET 8
284uint QWaylandKeyboardPrivate::fromWaylandKey(
const uint key)
286#if QT_CONFIG(xkbcommon)
287 const uint offset = QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET;
294uint QWaylandKeyboardPrivate::toWaylandKey(
const uint nativeScanCode)
296#if QT_CONFIG(xkbcommon)
297 const uint offset = QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET;
298 Q_ASSERT(nativeScanCode >= offset);
299 return nativeScanCode - offset;
301 return nativeScanCode;
305#if QT_CONFIG(xkbcommon)
306static int createAnonymousFile(size_t size)
308 QString path = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
312 QByteArray name = QFile::encodeName(path + QStringLiteral(
"/qtwayland-XXXXXX"));
314 int fd = mkstemp(name.data());
318 long flags = fcntl(fd, F_GETFD);
319 if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
323 unlink(name.constData());
328 if (ftruncate(fd, size) < 0) {
336void QWaylandKeyboardPrivate::createXKBState(xkb_keymap *keymap)
338 char *keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
340 qWarning(
"Failed to compile global XKB keymap");
344 keymap_size = strlen(keymap_str) + 1;
347 keymap_fd = createAnonymousFile(keymap_size);
349 qWarning(
"Failed to create anonymous file of size %lu",
static_cast<
unsigned long>(keymap_size));
353 keymap_area =
static_cast<
char *>(mmap(
nullptr, keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, keymap_fd, 0));
354 if (keymap_area == MAP_FAILED) {
357 qWarning(
"Failed to map shared memory segment");
361 strcpy(keymap_area, keymap_str);
364 mXkbState.reset(xkb_state_new(keymap));
366 qWarning(
"Failed to create XKB state");
369void QWaylandKeyboardPrivate::createXKBKeymap()
374 QWaylandKeymap *keymap = seat->keymap();
375 QByteArray rules = keymap->rules().toLocal8Bit();
376 QByteArray model = keymap->model().toLocal8Bit();
377 QByteArray layout = keymap->layout().toLocal8Bit();
378 QByteArray variant = keymap->variant().toLocal8Bit();
379 QByteArray options = keymap->options().toLocal8Bit();
381 if (!layout.isEmpty() && !layout.contains(
"us")) {
384 layout.append(
",us");
388 struct xkb_rule_names rule_names = {
396 QXkbCommon::ScopedXKBKeymap xkbKeymap(xkb_keymap_new_from_names(xkbContext(), &rule_names,
397 XKB_KEYMAP_COMPILE_NO_FLAGS));
399 scanCodesByQtKey.clear();
400 createXKBState(xkbKeymap.get());
402 qWarning(
"Failed to load the '%s' XKB keymap.", qPrintable(keymap->layout()));
407void QWaylandKeyboardPrivate::sendRepeatInfo()
409 const auto resMap = resourceMap();
410 for (Resource *resource : resMap) {
411 if (resource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
412 send_repeat_info(resource->handle, repeatRate, repeatDelay);
417
418
419
420
421
422
423
424
427
428
429QWaylandKeyboard::QWaylandKeyboard(QWaylandSeat *seat, QObject *parent)
430 : QWaylandObject(*
new QWaylandKeyboardPrivate(seat), parent)
432 Q_D(QWaylandKeyboard);
433 connect(&d->focusDestroyListener, &QWaylandDestroyListener::fired,
this, &QWaylandKeyboard::focusDestroyed);
434 auto keymap = seat->keymap();
435 connect(keymap, &QWaylandKeymap::layoutChanged,
this, &QWaylandKeyboard::updateKeymap);
436 connect(keymap, &QWaylandKeymap::variantChanged,
this, &QWaylandKeyboard::updateKeymap);
437 connect(keymap, &QWaylandKeymap::optionsChanged,
this, &QWaylandKeyboard::updateKeymap);
438 connect(keymap, &QWaylandKeymap::rulesChanged,
this, &QWaylandKeyboard::updateKeymap);
439 connect(keymap, &QWaylandKeymap::modelChanged,
this, &QWaylandKeyboard::updateKeymap);
440#if QT_CONFIG(xkbcommon)
441 d->createXKBKeymap();
446
447
448QWaylandSeat *QWaylandKeyboard::seat()
const
450 Q_D(
const QWaylandKeyboard);
455
456
457QWaylandCompositor *QWaylandKeyboard::compositor()
const
459 Q_D(
const QWaylandKeyboard);
460 return d->seat->compositor();
464
465
466void QWaylandKeyboard::focusDestroyed(
void *data)
469 Q_D(QWaylandKeyboard);
470 d->focusDestroyListener.reset();
473 d->focusResource =
nullptr;
476void QWaylandKeyboard::updateKeymap()
478 Q_D(QWaylandKeyboard);
479 d->pendingKeymap =
true;
480 d->maybeUpdateKeymap();
484
485
486QWaylandClient *QWaylandKeyboard::focusClient()
const
488 Q_D(
const QWaylandKeyboard);
489 if (!d->focusResource)
491 return QWaylandClient::fromWlClient(compositor(), d->focusResource->client());
495
496
497void QWaylandKeyboard::sendKeyModifiers(QWaylandClient *client, uint32_t serial)
499 Q_D(QWaylandKeyboard);
500 QtWaylandServer::wl_keyboard::Resource *resource = d->resourceMap().value(client->client());
502 d->send_modifiers(resource->handle, serial, d->modsDepressed, d->modsLatched, d->modsLocked, d->group);
506
507
508void QWaylandKeyboard::sendKeyPressEvent(uint code)
510 Q_D(QWaylandKeyboard);
511 d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_PRESSED);
515
516
517void QWaylandKeyboard::sendKeyReleaseEvent(uint code)
519 Q_D(QWaylandKeyboard);
520 d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED);
523void QWaylandKeyboardPrivate::checkAndRepairModifierState(QKeyEvent *ke)
525#if QT_CONFIG(xkbcommon)
526 if (ke->modifiers() != currentModifierState) {
527 if (focusResource && ke->key() != Qt::Key_Shift
528 && ke->key() != Qt::Key_Control && ke->key() != Qt::Key_Alt
529 && ke->key() != Qt::Key_AltGr) {
536 if (shiftIndex == 0 && controlIndex == 0)
537 maybeUpdateXkbScanCodeTable();
539 if (ke->modifiers() & Qt::ShiftModifier)
540 mods |= 1 << shiftIndex;
541 if (ke->modifiers() & Qt::ControlModifier)
542 mods |= 1 << controlIndex;
543 if (ke->modifiers() & Qt::AltModifier)
544 mods |= 1 << altIndex;
545 if ((ke->modifiers() & Qt::GroupSwitchModifier) && mod5Index != XKB_MOD_INVALID)
546 mods |= 1 << mod5Index;
547 qCDebug(qLcWaylandCompositor) <<
"Keyboard modifier state mismatch detected for event" << ke <<
"state:" << currentModifierState <<
"repaired:" << Qt::hex << mods;
549 send_modifiers(focusResource->handle, compositor()->nextSerial(), mods,
550 0, modsLocked, group);
551 currentModifierState = ke->modifiers();
560
561
562
563
564
567
568
569quint32 QWaylandKeyboard::repeatRate()
const
571 Q_D(
const QWaylandKeyboard);
572 return d->repeatRate;
576
577
578void QWaylandKeyboard::setRepeatRate(quint32 rate)
580 Q_D(QWaylandKeyboard);
582 if (d->repeatRate == rate)
587 d->repeatRate = rate;
588 Q_EMIT repeatRateChanged(rate);
592
593
594
595
596
599
600
601quint32 QWaylandKeyboard::repeatDelay()
const
603 Q_D(
const QWaylandKeyboard);
604 return d->repeatDelay;
608
609
610void QWaylandKeyboard::setRepeatDelay(quint32 delay)
612 Q_D(QWaylandKeyboard);
614 if (d->repeatDelay == delay)
619 d->repeatDelay = delay;
620 Q_EMIT repeatDelayChanged(delay);
624
625
626QWaylandSurface *QWaylandKeyboard::focus()
const
628 Q_D(
const QWaylandKeyboard);
633
634
635void QWaylandKeyboard::setFocus(QWaylandSurface *surface)
637 Q_D(QWaylandKeyboard);
642
643
644void QWaylandKeyboard::addClient(QWaylandClient *client, uint32_t id, uint32_t version)
646 Q_D(QWaylandKeyboard);
647 d->add(client->client(), id, qMin<uint32_t>(QtWaylandServer::wl_keyboard::interfaceVersion(), version));
650uint QWaylandKeyboard::keyToScanCode(
int qtKey)
const
653#if QT_CONFIG(xkbcommon)
654 Q_D(
const QWaylandKeyboard);
655 const_cast<QWaylandKeyboardPrivate *>(d)->maybeUpdateXkbScanCodeTable();
656 scanCode = d->scanCodesByQtKey.value({d->group, qtKey}, 0);
665#include "moc_qwaylandkeyboard.cpp"