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>
27QWaylandKeyboardPrivate::QWaylandKeyboardPrivate(QWaylandSeat *seat)
32QWaylandKeyboardPrivate::~QWaylandKeyboardPrivate()
34#if QT_CONFIG(xkbcommon)
37 munmap(keymap_area, keymap_size);
44QWaylandKeyboardPrivate *QWaylandKeyboardPrivate::get(QWaylandKeyboard *keyboard)
46 return keyboard->d_func();
49void QWaylandKeyboardPrivate::checkFocusResource(Resource *keyboardResource)
51 if (!keyboardResource || !focus)
55 if (focusResource == keyboardResource)
59 if (wl_resource_get_client(focus->resource()) == keyboardResource->client()) {
60 sendEnter(focus, keyboardResource);
61 focusResource = keyboardResource;
65void QWaylandKeyboardPrivate::sendEnter(QWaylandSurface *surface, Resource *keyboardResource)
67 uint32_t serial = compositor()->nextSerial();
68 send_modifiers(keyboardResource->handle, serial, modsDepressed, modsLatched, modsLocked, group);
69 send_enter(keyboardResource->handle, serial, surface->resource(), QByteArray::fromRawData((
char *)keys.data(), keys.size() *
sizeof(uint32_t)));
72void QWaylandKeyboardPrivate::focused(QWaylandSurface *surface)
74 if (surface && surface->isCursorSurface())
76 if (focus != surface) {
78 uint32_t serial = compositor()->nextSerial();
79 send_leave(focusResource->handle, serial, focus->resource());
81 focusDestroyListener.reset();
83 focusDestroyListener.listenForDestruction(surface->resource());
86 Resource *resource = surface ? resourceMap().value(surface->waylandClient()) : 0;
88 if (resource && (focus != surface || focusResource != resource))
89 sendEnter(surface, resource);
91 focusResource = resource;
93 Q_EMIT q_func()->focusChanged(focus);
97void QWaylandKeyboardPrivate::keyboard_bind_resource(wl_keyboard::Resource *resource)
100 if (resource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
101 send_repeat_info(resource->handle, repeatRate, repeatDelay);
103#if QT_CONFIG(xkbcommon)
105 send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
106 keymap_fd, keymap_size);
110 int null_fd = open(
"/dev/null", O_RDONLY);
111 send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP,
115 checkFocusResource(resource);
118void QWaylandKeyboardPrivate::keyboard_destroy_resource(wl_keyboard::Resource *resource)
120 if (focusResource == resource)
121 focusResource =
nullptr;
124void QWaylandKeyboardPrivate::keyboard_release(wl_keyboard::Resource *resource)
126 wl_resource_destroy(resource->handle);
129void QWaylandKeyboardPrivate::keyEvent(uint code, uint32_t state)
131 uint key = toWaylandKey(code);
133 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
140void QWaylandKeyboardPrivate::sendKeyEvent(uint code, uint32_t state)
142 uint32_t time = compositor()->currentTimeMsecs();
143 uint32_t serial = compositor()->nextSerial();
144 uint key = toWaylandKey(code);
146 send_key(focusResource->handle, serial, time, key, state);
149#if QT_CONFIG(xkbcommon)
150void QWaylandKeyboardPrivate::maybeUpdateXkbScanCodeTable()
152 if (!scanCodesByQtKey.isEmpty() || !xkbState())
155 if (xkb_keymap *keymap = xkb_state_get_keymap(xkbState())) {
156 xkb_keymap_key_for_each(keymap, [](xkb_keymap *keymap, xkb_keycode_t keycode,
void *d){
157 auto *scanCodesByQtKey =
static_cast<QMap<ScanCodeKey, uint>*>(d);
158 uint numLayouts = xkb_keymap_num_layouts_for_key(keymap, keycode);
159 for (uint layout = 0; layout < numLayouts; ++layout) {
160 const xkb_keysym_t *syms =
nullptr;
161 xkb_keymap_key_get_syms_by_level(keymap, keycode, layout, 0, &syms);
165 Qt::KeyboardModifiers mods = {};
166 int qtKey = QXkbCommon::keysymToQtKey(syms[0], mods,
nullptr, 0,
false,
false);
168 scanCodesByQtKey->insert({layout, qtKey}, keycode);
170 }, &scanCodesByQtKey);
172 shiftIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
173 controlIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
174 altIndex = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT);
178void QWaylandKeyboardPrivate::resetKeyboardState()
183 while (!keys.isEmpty()) {
184 uint32_t code = fromWaylandKey(keys.first());
185 keyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED);
186 updateModifierState(code, WL_KEYBOARD_KEY_STATE_RELEASED);
191void QWaylandKeyboardPrivate::updateModifierState(uint code, uint32_t state)
193#if QT_CONFIG(xkbcommon)
197 xkb_state_update_key(xkbState(), code, state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP);
199 uint32_t modsDepressed = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_DEPRESSED);
200 uint32_t modsLatched = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_LATCHED);
201 uint32_t modsLocked = xkb_state_serialize_mods(xkbState(), XKB_STATE_MODS_LOCKED);
202 uint32_t group = xkb_state_serialize_layout(xkbState(), XKB_STATE_LAYOUT_EFFECTIVE);
204 if (
this->modsDepressed == modsDepressed
205 &&
this->modsLatched == modsLatched
206 &&
this->modsLocked == modsLocked
207 &&
this->group == group)
210 this->modsDepressed = modsDepressed;
211 this->modsLatched = modsLatched;
212 this->modsLocked = modsLocked;
216 send_modifiers(focusResource->handle, compositor()->nextSerial(), modsDepressed,
217 modsLatched, modsLocked, group);
219 Qt::KeyboardModifiers currentState = Qt::NoModifier;
220 if (xkb_state_mod_index_is_active(xkbState(), shiftIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
221 currentState |= Qt::ShiftModifier;
222 if (xkb_state_mod_index_is_active(xkbState(), controlIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
223 currentState |= Qt::ControlModifier;
224 if (xkb_state_mod_index_is_active(xkbState(), altIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
225 currentState |= Qt::AltModifier;
226 currentModifierState = currentState;
237void QWaylandKeyboardPrivate::maybeUpdateKeymap()
241 if (!pendingKeymap || !keys.isEmpty())
244 pendingKeymap =
false;
245#if QT_CONFIG(xkbcommon)
250 const auto resMap = resourceMap();
251 for (Resource *res : resMap) {
252 send_keymap(res->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymap_fd, keymap_size);
255 xkb_state_update_mask(xkbState(), 0, modsLatched, modsLocked, 0, 0, 0);
257 send_modifiers(focusResource->handle,
258 compositor()->nextSerial(),
273#define QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET 8
275uint QWaylandKeyboardPrivate::fromWaylandKey(
const uint key)
277#if QT_CONFIG(xkbcommon)
278 const uint offset = QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET;
285uint QWaylandKeyboardPrivate::toWaylandKey(
const uint nativeScanCode)
287#if QT_CONFIG(xkbcommon)
288 const uint offset = QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET;
289 Q_ASSERT(nativeScanCode >= offset);
290 return nativeScanCode - offset;
292 return nativeScanCode;
296#if QT_CONFIG(xkbcommon)
297static int createAnonymousFile(size_t size)
299 QString path = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
303 QByteArray name = QFile::encodeName(path + QStringLiteral(
"/qtwayland-XXXXXX"));
305 int fd = mkstemp(name.data());
309 long flags = fcntl(fd, F_GETFD);
310 if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
314 unlink(name.constData());
319 if (ftruncate(fd, size) < 0) {
327void QWaylandKeyboardPrivate::createXKBState(xkb_keymap *keymap)
329 char *keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
331 qWarning(
"Failed to compile global XKB keymap");
335 keymap_size = strlen(keymap_str) + 1;
338 keymap_fd = createAnonymousFile(keymap_size);
340 qWarning(
"Failed to create anonymous file of size %lu",
static_cast<
unsigned long>(keymap_size));
344 keymap_area =
static_cast<
char *>(mmap(
nullptr, keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, keymap_fd, 0));
345 if (keymap_area == MAP_FAILED) {
348 qWarning(
"Failed to map shared memory segment");
352 strcpy(keymap_area, keymap_str);
355 mXkbState.reset(xkb_state_new(keymap));
357 qWarning(
"Failed to create XKB state");
360void QWaylandKeyboardPrivate::createXKBKeymap()
365 QWaylandKeymap *keymap = seat->keymap();
366 QByteArray rules = keymap->rules().toLocal8Bit();
367 QByteArray model = keymap->model().toLocal8Bit();
368 QByteArray layout = keymap->layout().toLocal8Bit();
369 QByteArray variant = keymap->variant().toLocal8Bit();
370 QByteArray options = keymap->options().toLocal8Bit();
372 if (!layout.isEmpty() && !layout.contains(
"us")) {
375 layout.append(
",us");
379 struct xkb_rule_names rule_names = {
387 QXkbCommon::ScopedXKBKeymap xkbKeymap(xkb_keymap_new_from_names(xkbContext(), &rule_names,
388 XKB_KEYMAP_COMPILE_NO_FLAGS));
390 scanCodesByQtKey.clear();
391 createXKBState(xkbKeymap.get());
393 qWarning(
"Failed to load the '%s' XKB keymap.", qPrintable(keymap->layout()));
398void QWaylandKeyboardPrivate::sendRepeatInfo()
400 const auto resMap = resourceMap();
401 for (Resource *resource : resMap) {
402 if (resource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
403 send_repeat_info(resource->handle, repeatRate, repeatDelay);
408
409
410
411
412
413
414
415
418
419
420QWaylandKeyboard::QWaylandKeyboard(QWaylandSeat *seat, QObject *parent)
421 : QWaylandObject(*
new QWaylandKeyboardPrivate(seat), parent)
423 Q_D(QWaylandKeyboard);
424 connect(&d->focusDestroyListener, &QWaylandDestroyListener::fired,
this, &QWaylandKeyboard::focusDestroyed);
425 auto keymap = seat->keymap();
426 connect(keymap, &QWaylandKeymap::layoutChanged,
this, &QWaylandKeyboard::updateKeymap);
427 connect(keymap, &QWaylandKeymap::variantChanged,
this, &QWaylandKeyboard::updateKeymap);
428 connect(keymap, &QWaylandKeymap::optionsChanged,
this, &QWaylandKeyboard::updateKeymap);
429 connect(keymap, &QWaylandKeymap::rulesChanged,
this, &QWaylandKeyboard::updateKeymap);
430 connect(keymap, &QWaylandKeymap::modelChanged,
this, &QWaylandKeyboard::updateKeymap);
431#if QT_CONFIG(xkbcommon)
432 d->createXKBKeymap();
437
438
439QWaylandSeat *QWaylandKeyboard::seat()
const
441 Q_D(
const QWaylandKeyboard);
446
447
448QWaylandCompositor *QWaylandKeyboard::compositor()
const
450 Q_D(
const QWaylandKeyboard);
451 return d->seat->compositor();
455
456
457void QWaylandKeyboard::focusDestroyed(
void *data)
460 Q_D(QWaylandKeyboard);
461 d->focusDestroyListener.reset();
464 d->focusResource =
nullptr;
467void QWaylandKeyboard::updateKeymap()
469 Q_D(QWaylandKeyboard);
470 d->pendingKeymap =
true;
471 d->maybeUpdateKeymap();
475
476
477QWaylandClient *QWaylandKeyboard::focusClient()
const
479 Q_D(
const QWaylandKeyboard);
480 if (!d->focusResource)
482 return QWaylandClient::fromWlClient(compositor(), d->focusResource->client());
486
487
488void QWaylandKeyboard::sendKeyModifiers(QWaylandClient *client, uint32_t serial)
490 Q_D(QWaylandKeyboard);
491 QtWaylandServer::wl_keyboard::Resource *resource = d->resourceMap().value(client->client());
493 d->send_modifiers(resource->handle, serial, d->modsDepressed, d->modsLatched, d->modsLocked, d->group);
497
498
499void QWaylandKeyboard::sendKeyPressEvent(uint code)
501 Q_D(QWaylandKeyboard);
502 d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_PRESSED);
506
507
508void QWaylandKeyboard::sendKeyReleaseEvent(uint code)
510 Q_D(QWaylandKeyboard);
511 d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED);
514void QWaylandKeyboardPrivate::checkAndRepairModifierState(QKeyEvent *ke)
516#if QT_CONFIG(xkbcommon)
517 if (ke->modifiers() != currentModifierState) {
518 if (focusResource && ke->key() != Qt::Key_Shift
519 && ke->key() != Qt::Key_Control && ke->key() != Qt::Key_Alt) {
526 if (shiftIndex == 0 && controlIndex == 0)
527 maybeUpdateXkbScanCodeTable();
529 if (ke->modifiers() & Qt::ShiftModifier)
530 mods |= 1 << shiftIndex;
531 if (ke->modifiers() & Qt::ControlModifier)
532 mods |= 1 << controlIndex;
533 if (ke->modifiers() & Qt::AltModifier)
534 mods |= 1 << altIndex;
535 qCDebug(qLcWaylandCompositor) <<
"Keyboard modifier state mismatch detected for event" << ke <<
"state:" << currentModifierState <<
"repaired:" << Qt::hex << mods;
536 send_modifiers(focusResource->handle, compositor()->nextSerial(), mods,
538 currentModifierState = ke->modifiers();
547
548
549quint32 QWaylandKeyboard::repeatRate()
const
551 Q_D(
const QWaylandKeyboard);
552 return d->repeatRate;
556
557
558void QWaylandKeyboard::setRepeatRate(quint32 rate)
560 Q_D(QWaylandKeyboard);
562 if (d->repeatRate == rate)
567 d->repeatRate = rate;
568 Q_EMIT repeatRateChanged(rate);
572
573
574quint32 QWaylandKeyboard::repeatDelay()
const
576 Q_D(
const QWaylandKeyboard);
577 return d->repeatDelay;
581
582
583void QWaylandKeyboard::setRepeatDelay(quint32 delay)
585 Q_D(QWaylandKeyboard);
587 if (d->repeatDelay == delay)
592 d->repeatDelay = delay;
593 Q_EMIT repeatDelayChanged(delay);
597
598
599QWaylandSurface *QWaylandKeyboard::focus()
const
601 Q_D(
const QWaylandKeyboard);
606
607
608void QWaylandKeyboard::setFocus(QWaylandSurface *surface)
610 Q_D(QWaylandKeyboard);
615
616
617void QWaylandKeyboard::addClient(QWaylandClient *client, uint32_t id, uint32_t version)
619 Q_D(QWaylandKeyboard);
620 d->add(client->client(), id, qMin<uint32_t>(QtWaylandServer::wl_keyboard::interfaceVersion(), version));
623uint QWaylandKeyboard::keyToScanCode(
int qtKey)
const
626#if QT_CONFIG(xkbcommon)
627 Q_D(
const QWaylandKeyboard);
628 const_cast<QWaylandKeyboardPrivate *>(d)->maybeUpdateXkbScanCodeTable();
629 scanCode = d->scanCodesByQtKey.value({d->group, qtKey}, 0);
638#include "moc_qwaylandkeyboard.cpp"