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){
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 = {};
168 scanCodesByQtKey->insert({
layout,
qtKey}, keycode);
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,
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.
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately after the event occurred.
int key() const
Returns the code of the key that was pressed or released.
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)
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent