Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwaylandkeyboard.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// Copyright (C) 2017 Klarälvdalens Datakonsult AB (KDAB).
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
6#include "qwaylandkeyboard.h"
8#include <QtWaylandCompositor/QWaylandKeymap>
9#include <QtWaylandCompositor/QWaylandCompositor>
10#include <QtWaylandCompositor/QWaylandSeat>
11#include <QtWaylandCompositor/QWaylandClient>
12
13#include <QtCore/QFile>
14#include <QtCore/QStandardPaths>
15
16#include <QKeyEvent>
17#include <fcntl.h>
18#include <unistd.h>
19#if QT_CONFIG(xkbcommon)
20#include <sys/mman.h>
21#include <sys/types.h>
22#include <xkbcommon/xkbcommon-names.h>
23#endif
24
26
31
33{
34#if QT_CONFIG(xkbcommon)
35 if (xkbContext()) {
36 if (keymap_area)
37 munmap(keymap_area, keymap_size);
38 if (keymap_fd >= 0)
39 close(keymap_fd);
40 }
41#endif
42}
43
45{
46 return keyboard->d_func();
47}
48
49void QWaylandKeyboardPrivate::checkFocusResource(Resource *keyboardResource)
50{
51 if (!keyboardResource || !focus)
52 return;
53
54 // this is already the current resource, do no send enter twice
55 if (focusResource == keyboardResource)
56 return;
57
58 // check if new wl_keyboard resource is from the client owning the focus surface
59 if (wl_resource_get_client(focus->resource()) == keyboardResource->client()) {
60 sendEnter(focus, keyboardResource);
61 focusResource = keyboardResource;
62 }
63}
64
65void QWaylandKeyboardPrivate::sendEnter(QWaylandSurface *surface, Resource *keyboardResource)
66{
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)));
70}
71
73{
74 if (surface && surface->isCursorSurface())
75 surface = nullptr;
76 if (focus != surface) {
77 if (focusResource) {
78 uint32_t serial = compositor()->nextSerial();
79 send_leave(focusResource->handle, serial, focus->resource());
80 }
81 focusDestroyListener.reset();
82 if (surface)
83 focusDestroyListener.listenForDestruction(surface->resource());
84 }
85
86 Resource *resource = surface ? resourceMap().value(surface->waylandClient()) : 0;
87
88 if (resource && (focus != surface || focusResource != resource))
89 sendEnter(surface, resource);
90
91 focusResource = resource;
92 focus = surface;
93 Q_EMIT q_func()->focusChanged(focus);
94}
95
96
97void QWaylandKeyboardPrivate::keyboard_bind_resource(wl_keyboard::Resource *resource)
98{
99 // Send repeat information
100 if (resource->version() >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION)
101 send_repeat_info(resource->handle, repeatRate, repeatDelay);
102
103#if QT_CONFIG(xkbcommon)
104 if (xkbContext()) {
105 send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
106 keymap_fd, keymap_size);
107 } else
108#endif
109 {
110 int null_fd = open("/dev/null", O_RDONLY);
111 send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP,
112 null_fd, 0);
113 close(null_fd);
114 }
115 checkFocusResource(resource);
116}
117
118void QWaylandKeyboardPrivate::keyboard_destroy_resource(wl_keyboard::Resource *resource)
119{
120 if (focusResource == resource)
121 focusResource = nullptr;
122}
123
124void QWaylandKeyboardPrivate::keyboard_release(wl_keyboard::Resource *resource)
125{
126 wl_resource_destroy(resource->handle);
127}
128
130{
131 uint key = toWaylandKey(code);
132
133 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
134 keys << key;
135 } else {
136 keys.removeAll(key);
137 }
138}
139
141{
142 uint32_t time = compositor()->currentTimeMsecs();
143 uint32_t serial = compositor()->nextSerial();
144 uint key = toWaylandKey(code);
145 if (focusResource)
146 send_key(focusResource->handle, serial, time, key, state);
147}
148
149#if QT_CONFIG(xkbcommon)
150void QWaylandKeyboardPrivate::maybeUpdateXkbScanCodeTable()
151{
152 if (!scanCodesByQtKey.isEmpty() || !xkbState())
153 return;
154
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);
162 if (!syms)
163 continue;
164
165 Qt::KeyboardModifiers mods = {};
166 int qtKey = QXkbCommon::keysymToQtKey(syms[0], mods, nullptr, 0, false, false);
167 if (qtKey != 0)
168 scanCodesByQtKey->insert({layout, qtKey}, keycode);
169 }
170 }, &scanCodesByQtKey);
171
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);
175 }
176}
177
178void QWaylandKeyboardPrivate::resetKeyboardState()
179{
180 if (!xkbContext())
181 return;
182
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);
187 }
188}
189#endif
190
192{
193#if QT_CONFIG(xkbcommon)
194 if (!xkbContext())
195 return;
196
197 xkb_state_update_key(xkbState(), code, state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP);
198
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);
203
204 if (this->modsDepressed == modsDepressed
205 && this->modsLatched == modsLatched
206 && this->modsLocked == modsLocked
207 && this->group == group)
208 return;
209
210 this->modsDepressed = modsDepressed;
211 this->modsLatched = modsLatched;
212 this->modsLocked = modsLocked;
213 this->group = group;
214
215 if (focusResource) {
216 send_modifiers(focusResource->handle, compositor()->nextSerial(), modsDepressed,
217 modsLatched, modsLocked, group);
218
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;
227 }
228#else
229 Q_UNUSED(code);
231#endif
232}
233
234// If there is no key currently pressed, update the keymap right away.
235// Otherwise, delay the update when keys are released
236// see http://lists.freedesktop.org/archives/wayland-devel/2013-October/011395.html
238{
239 // There must be no keys pressed when changing the keymap,
240 // see http://lists.freedesktop.org/archives/wayland-devel/2013-October/011395.html
241 if (!pendingKeymap || !keys.isEmpty())
242 return;
243
244 pendingKeymap = false;
245#if QT_CONFIG(xkbcommon)
246 if (!xkbContext())
247 return;
248
249 createXKBKeymap();
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);
253 }
254
255 xkb_state_update_mask(xkbState(), 0, modsLatched, modsLocked, 0, 0, 0);
256 if (focusResource)
257 send_modifiers(focusResource->handle,
258 compositor()->nextSerial(),
259 modsDepressed,
260 modsLatched,
261 modsLocked,
262 group);
263#endif
264}
265
266// In all current XKB keymaps there's a constant offset of 8 (for historical
267// reasons) from hardware/evdev scancodes to XKB keycodes. On X11, we pass
268// XKB keycodes (as sent by X server) via QKeyEvent::nativeScanCode. eglfs+evdev
269// adds 8 for consistency, see qtbase/05c07c7636012ebb4131ca099ca4ea093af76410.
270// eglfs+libinput also adds 8, for the same reason. Wayland protocol uses
271// hardware/evdev scancodes, thus we need to subtract 8 before sending the event
272// out and add it when mapping back.
273#define QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET 8
274
275uint QWaylandKeyboardPrivate::fromWaylandKey(const uint key)
276{
277#if QT_CONFIG(xkbcommon)
279 return key + offset;
280#else
281 return key;
282#endif
283}
284
285uint QWaylandKeyboardPrivate::toWaylandKey(const uint nativeScanCode)
286{
287#if QT_CONFIG(xkbcommon)
289 Q_ASSERT(nativeScanCode >= offset);
290 return nativeScanCode - offset;
291#else
292 return nativeScanCode;
293#endif
294}
295
296#if QT_CONFIG(xkbcommon)
297static int createAnonymousFile(size_t size)
298{
300 if (path.isEmpty())
301 return -1;
302
303 QByteArray name = QFile::encodeName(path + QStringLiteral("/qtwayland-XXXXXX"));
304
305 int fd = mkstemp(name.data());
306 if (fd < 0)
307 return -1;
308
309 long flags = fcntl(fd, F_GETFD);
310 if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
311 close(fd);
312 fd = -1;
313 }
314 unlink(name.constData());
315
316 if (fd < 0)
317 return -1;
318
319 if (ftruncate(fd, size) < 0) {
320 close(fd);
321 return -1;
322 }
323
324 return fd;
325}
326
327void QWaylandKeyboardPrivate::createXKBState(xkb_keymap *keymap)
328{
329 char *keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
330 if (!keymap_str) {
331 qWarning("Failed to compile global XKB keymap");
332 return;
333 }
334
335 keymap_size = strlen(keymap_str) + 1;
336 if (keymap_fd >= 0)
337 close(keymap_fd);
338 keymap_fd = createAnonymousFile(keymap_size);
339 if (keymap_fd < 0) {
340 qWarning("Failed to create anonymous file of size %lu", static_cast<unsigned long>(keymap_size));
341 return;
342 }
343
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) {
346 close(keymap_fd);
347 keymap_fd = -1;
348 qWarning("Failed to map shared memory segment");
349 return;
350 }
351
352 strcpy(keymap_area, keymap_str);
353 free(keymap_str);
354
355 mXkbState.reset(xkb_state_new(keymap));
356 if (!mXkbState)
357 qWarning("Failed to create XKB state");
358}
359
360void QWaylandKeyboardPrivate::createXKBKeymap()
361{
362 if (!xkbContext())
363 return;
364
365 QWaylandKeymap *keymap = seat->keymap();
366 QByteArray rules = keymap->rules().toLocal8Bit();
367 QByteArray model = keymap->model().toLocal8Bit();
368 QByteArray layout = keymap->layout().toLocal8Bit();
370 QByteArray options = keymap->options().toLocal8Bit();
371
372 if (!layout.isEmpty() && !layout.contains("us")) {
373 // This is needed for shortucts like "ctrl+c" to function even when
374 // user has selected only non-latin keyboard layouts, e.g. 'ru'.
375 layout.append(",us");
376 variant.append(",");
377 }
378
379 struct xkb_rule_names rule_names = {
380 rules.constData(),
381 model.constData(),
382 layout.constData(),
384 options.constData()
385 };
386
387 QXkbCommon::ScopedXKBKeymap xkbKeymap(xkb_keymap_new_from_names(xkbContext(), &rule_names,
388 XKB_KEYMAP_COMPILE_NO_FLAGS));
389 if (xkbKeymap) {
390 scanCodesByQtKey.clear();
391 createXKBState(xkbKeymap.get());
392 } else {
393 qWarning("Failed to load the '%s' XKB keymap.", qPrintable(keymap->layout()));
394 }
395}
396#endif // QT_CONFIG(xkbcommon)
397
398void QWaylandKeyboardPrivate::sendRepeatInfo()
399{
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);
404 }
405}
406
421 : QWaylandObject(* new QWaylandKeyboardPrivate(seat), parent)
422{
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();
433#endif
434}
435
440{
441 Q_D(const QWaylandKeyboard);
442 return d->seat;
443}
444
449{
450 Q_D(const QWaylandKeyboard);
451 return d->seat->compositor();
452}
453
457void QWaylandKeyboard::focusDestroyed(void *data)
458{
459 Q_UNUSED(data);
460 Q_D(QWaylandKeyboard);
461 d->focusDestroyListener.reset();
462
463 d->focus = nullptr;
464 d->focusResource = nullptr;
465}
466
467void QWaylandKeyboard::updateKeymap()
468{
469 Q_D(QWaylandKeyboard);
470 d->pendingKeymap = true;
471 d->maybeUpdateKeymap();
472}
473
478{
479 Q_D(const QWaylandKeyboard);
480 if (!d->focusResource)
481 return nullptr;
482 return QWaylandClient::fromWlClient(compositor(), d->focusResource->client());
483}
484
489{
490 Q_D(QWaylandKeyboard);
491 QtWaylandServer::wl_keyboard::Resource *resource = d->resourceMap().value(client->client());
492 if (resource)
493 d->send_modifiers(resource->handle, serial, d->modsDepressed, d->modsLatched, d->modsLocked, d->group);
494}
495
500{
501 Q_D(QWaylandKeyboard);
502 d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_PRESSED);
503}
504
509{
510 Q_D(QWaylandKeyboard);
511 d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED);
512}
513
515{
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) {
520 // Only repair the state for non-modifier keys
521 // ### slightly awkward because the standard modifier handling
522 // is done by QtWayland::WindowSystemEventHandler after the
523 // key event is delivered
524 uint32_t mods = 0;
525
526 if (shiftIndex == 0 && controlIndex == 0)
527 maybeUpdateXkbScanCodeTable();
528
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,
537 0, 0, group);
538 currentModifierState = ke->modifiers();
539 }
540 }
541#else
542 Q_UNUSED(ke);
543#endif
544}
545
550{
551 Q_D(const QWaylandKeyboard);
552 return d->repeatRate;
553}
554
559{
560 Q_D(QWaylandKeyboard);
561
562 if (d->repeatRate == rate)
563 return;
564
565 d->sendRepeatInfo();
566
567 d->repeatRate = rate;
569}
570
575{
576 Q_D(const QWaylandKeyboard);
577 return d->repeatDelay;
578}
579
584{
585 Q_D(QWaylandKeyboard);
586
587 if (d->repeatDelay == delay)
588 return;
589
590 d->sendRepeatInfo();
591
592 d->repeatDelay = delay;
594}
595
600{
601 Q_D(const QWaylandKeyboard);
602 return d->focus;
603}
604
609{
610 Q_D(QWaylandKeyboard);
611 d->focused(surface);
612}
613
617void QWaylandKeyboard::addClient(QWaylandClient *client, uint32_t id, uint32_t version)
618{
619 Q_D(QWaylandKeyboard);
620 d->add(client->client(), id, qMin<uint32_t>(QtWaylandServer::wl_keyboard::interfaceVersion(), version));
621}
622
624{
625 uint scanCode = 0;
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);
630#else
632#endif
633 return scanCode;
634}
635
637
638#include "moc_qwaylandkeyboard.cpp"
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
Definition qbytearray.h:409
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
Definition qfile.h:158
The QKeyEvent class describes a key event.
Definition qevent.h:424
bool isEmpty() const override
\reimp
Definition qlayout.cpp:422
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
T & first()
Definition qlist.h:645
qsizetype removeAll(const AT &t)
Definition qlist.h:592
pointer data()
Definition qlist.h:431
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static QString writableLocation(StandardLocation type)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QByteArray toLocal8Bit() const &
Definition qstring.h:638
const void * constData() const
Definition qvariant.h:451
\qmltype WaylandClient \instantiates QWaylandClient \inqmlmodule QtWayland.Compositor
static QWaylandClient * fromWlClient(QWaylandCompositor *compositor, wl_client *wlClient)
Returns the QWaylandClient corresponding to the Wayland client wlClient and compositor.
wl_client * client() const
Returns the Wayland client of this QWaylandClient.
\qmltype WaylandCompositor \instantiates QWaylandCompositor \inqmlmodule QtWayland....
void fired(void *data)
void listenForDestruction(struct wl_resource *resource)
void checkAndRepairModifierState(QKeyEvent *ke)
void updateModifierState(uint code, uint32_t state)
void keyEvent(uint code, uint32_t state)
void keyboard_release(Resource *resource) override
void checkFocusResource(Resource *resource)
QWaylandCompositor * compositor() const
void sendKeyEvent(uint code, uint32_t state)
void keyboard_destroy_resource(Resource *resource) override
void keyboard_bind_resource(Resource *resource) override
QWaylandKeyboardPrivate(QWaylandSeat *seat)
void focused(QWaylandSurface *surface)
static QWaylandKeyboardPrivate * get(QWaylandKeyboard *keyboard)
void sendEnter(QWaylandSurface *surface, Resource *resource)
\inmodule QtWaylandCompositor
uint keyToScanCode(int qtKey) const
void repeatDelayChanged(quint32 repeatDelay)
virtual void sendKeyReleaseEvent(uint code)
Sends a key release event with the key code to the current keyboard focus.
virtual void setFocus(QWaylandSurface *surface)
Sets the current focus to surface.
QWaylandKeyboard(QWaylandSeat *seat, QObject *parent=nullptr)
Constructs a QWaylandKeyboard for the given seat and with the given parent.
QWaylandCompositor * compositor() const
Returns the compositor for this QWaylandKeyboard.
QWaylandClient * focusClient() const
Returns the client that currently has keyboard focus.
virtual void sendKeyPressEvent(uint code)
Sends a key press event with the key code to the current keyboard focus.
QWaylandSurface * focus() const
Returns the currently focused surface.
void setRepeatDelay(quint32 delay)
Sets the repeat delay to delay.
virtual void addClient(QWaylandClient *client, uint32_t id, uint32_t version)
virtual void sendKeyModifiers(QWaylandClient *client, uint32_t serial)
Sends the current key modifiers to client with the given serial.
void setRepeatRate(quint32 rate)
Sets the repeat rate to rate.
QWaylandSeat * seat() const
Returns the seat for this QWaylandKeyboard.
void repeatRateChanged(quint32 repeatRate)
void variantChanged()
void optionsChanged()
void rulesChanged()
void layoutChanged()
void modelChanged()
\inmodule QtWaylandCompositor
\qmltype WaylandSeat \instantiates QWaylandSeat \inqmlmodule QtWayland.Compositor
QWaylandKeymap * keymap
Returns the keymap object for this QWaylandSeat.
\qmltype WaylandSurface \instantiates QWaylandSurface \inqmlmodule QtWayland.Compositor
struct wl_resource * resource() const
Returns the Wayland resource corresponding to this QWaylandSurface.
::wl_client * waylandClient() const
Holds the wl_client using this QWaylandSurface.
bool isCursorSurface() const
std::unique_ptr< struct xkb_keymap, XKBKeymapDeleter > ScopedXKBKeymap
static int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers)
else opt state
[0]
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
@ Key_Shift
Definition qnamespace.h:683
@ Key_Control
Definition qnamespace.h:684
@ Key_Alt
Definition qnamespace.h:686
@ ShiftModifier
@ ControlModifier
@ NoModifier
@ AltModifier
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLboolean GLuint group
GLbitfield flags
GLenum GLuint GLintptr offset
GLuint64 GLenum GLint fd
GLuint name
GLuint res
GLuint GLenum * rate
GLsizei const GLchar *const * path
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define MAP_FAILED
static QString qtKey(CFStringRef cfkey)
#define qPrintable(string)
Definition qstring.h:1531
#define QStringLiteral(str)
#define Q_EMIT
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
unsigned int uint
Definition qtypes.h:34
int keycode
Definition qvnc.cpp:140
#define QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET
#define XKB_MOD_NAME_ALT
#define XKB_MOD_NAME_SHIFT
#define XKB_MOD_NAME_CTRL
QSqlQueryModel * model
[16]
file open(QIODevice::ReadOnly)
QVBoxLayout * layout
QVariant variant
[1]