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>
34#if QT_CONFIG(xkbcommon)
37 munmap(keymap_area, keymap_size);
46 return keyboard->d_func();
51 if (!keyboardResource || !focus)
55 if (focusResource == keyboardResource)
59 if (wl_resource_get_client(focus->
resource()) == keyboardResource->client()) {
61 focusResource = keyboardResource;
68 send_modifiers(keyboardResource->handle, serial, modsDepressed, modsLatched, modsLocked,
group);
76 if (focus != surface) {
79 send_leave(focusResource->handle, serial, focus->
resource());
81 focusDestroyListener.
reset();
86 Resource *resource = surface ? resourceMap().value(surface->
waylandClient()) : 0;
88 if (resource && (focus != surface || focusResource != resource))
91 focusResource = resource;
93 Q_EMIT q_func()->focusChanged(focus);
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,
120 if (focusResource == resource)
121 focusResource =
nullptr;
126 wl_resource_destroy(resource->handle);
133 if (
state == WL_KEYBOARD_KEY_STATE_PRESSED) {
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);
160 const xkb_keysym_t *syms =
nullptr;
161 xkb_keymap_key_get_syms_by_level(keymap,
keycode,
layout, 0, &syms);
165 Qt::KeyboardModifiers mods = {};
170 }, &scanCodesByQtKey);
178void QWaylandKeyboardPrivate::resetKeyboardState()
184 uint32_t
code = fromWaylandKey(keys.
first());
185 keyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED);
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);
220 if (xkb_state_mod_index_is_active(xkbState(), shiftIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
222 if (xkb_state_mod_index_is_active(xkbState(), controlIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
224 if (xkb_state_mod_index_is_active(xkbState(), altIndex, XKB_STATE_MODS_EFFECTIVE) == 1)
226 currentModifierState = currentState;
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,
273#define QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET 8
275uint QWaylandKeyboardPrivate::fromWaylandKey(
const uint key)
277#if QT_CONFIG(xkbcommon)
285uint QWaylandKeyboardPrivate::toWaylandKey(
const uint nativeScanCode)
287#if QT_CONFIG(xkbcommon)
290 return nativeScanCode -
offset;
292 return nativeScanCode;
296#if QT_CONFIG(xkbcommon)
297static int createAnonymousFile(
size_t size)
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));
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()
379 struct xkb_rule_names rule_names = {
388 XKB_KEYMAP_COMPILE_NO_FLAGS));
390 scanCodesByQtKey.clear();
391 createXKBState(xkbKeymap.get());
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);
431#if QT_CONFIG(xkbcommon)
432 d->createXKBKeymap();
451 return d->seat->compositor();
457void QWaylandKeyboard::focusDestroyed(
void *
data)
461 d->focusDestroyListener.reset();
464 d->focusResource =
nullptr;
467void QWaylandKeyboard::updateKeymap()
470 d->pendingKeymap =
true;
471 d->maybeUpdateKeymap();
480 if (!
d->focusResource)
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);
502 d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_PRESSED);
511 d->sendKeyEvent(code, WL_KEYBOARD_KEY_STATE_RELEASED);
516#if QT_CONFIG(xkbcommon)
517 if (ke->modifiers() != currentModifierState) {
526 if (shiftIndex == 0 && controlIndex == 0)
527 maybeUpdateXkbScanCodeTable();
530 mods |= 1 << shiftIndex;
532 mods |= 1 << controlIndex;
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();
552 return d->repeatRate;
562 if (
d->repeatRate ==
rate)
567 d->repeatRate =
rate;
577 return d->repeatDelay;
587 if (
d->repeatDelay == delay)
592 d->repeatDelay = delay;
620 d->add(client->
client(),
id, qMin<uint32_t>(QtWaylandServer::wl_keyboard::interfaceVersion(), version));
626#if QT_CONFIG(xkbcommon)
629 scanCode =
d->scanCodesByQtKey.value({
d->group,
qtKey}, 0);
638#include "moc_qwaylandkeyboard.cpp"
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
The QKeyEvent class describes a key event.
bool isEmpty() const override
\reimp
qsizetype size() const noexcept
bool isEmpty() const noexcept
qsizetype removeAll(const AT &t)
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
static QString writableLocation(StandardLocation type)
\macro QT_RESTRICTED_CAST_FROM_ASCII
QByteArray toLocal8Bit() const &
const void * constData() const
\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 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)
~QWaylandKeyboardPrivate() override
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)
\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)
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
#define qCDebug(category,...)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLsizei const GLchar *const * path
static QString qtKey(CFStringRef cfkey)
#define qPrintable(string)
#define QStringLiteral(str)
#define QTWAYLANDKEYBOARD_XKB_HISTORICAL_OFFSET
#define XKB_MOD_NAME_SHIFT
#define XKB_MOD_NAME_CTRL
QSqlQueryModel * model
[16]
file open(QIODevice::ReadOnly)