diff options
-rw-r--r-- | src/client/qwaylandinputdevice.cpp | 127 | ||||
-rw-r--r-- | src/client/qwaylandinputdevice_p.h | 26 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandkeyboard.cpp | 40 | ||||
-rw-r--r-- | src/compositor/compositor_api/qwaylandkeyboard_p.h | 2 |
4 files changed, 100 insertions, 95 deletions
diff --git a/src/client/qwaylandinputdevice.cpp b/src/client/qwaylandinputdevice.cpp index 572ce1e50..166be1934 100644 --- a/src/client/qwaylandinputdevice.cpp +++ b/src/client/qwaylandinputdevice.cpp @@ -77,7 +77,20 @@ namespace QtWaylandClient { QWaylandInputDevice::Keyboard::Keyboard(QWaylandInputDevice *p) : mParent(p) { - connect(&mRepeatTimer, SIGNAL(timeout()), this, SLOT(repeatKey())); + mRepeatTimer.callOnTimeout([&]() { + if (!focusWindow()) { + // We destroyed the keyboard focus surface, but the server didn't get the message yet... + // or the server didn't send an enter event first. + return; + } + mRepeatTimer.setInterval(mRepeatRate); + handleKey(mRepeatKey.time, QEvent::KeyRelease, mRepeatKey.key, mRepeatKey.modifiers, + mRepeatKey.code, mRepeatKey.nativeVirtualKey, mRepeatKey.nativeModifiers, + mRepeatKey.text, true); + handleKey(mRepeatKey.time, QEvent::KeyPress, mRepeatKey.key, mRepeatKey.modifiers, + mRepeatKey.code, mRepeatKey.nativeVirtualKey, mRepeatKey.nativeModifiers, + mRepeatKey.text, true); + }); } #if QT_CONFIG(xkbcommon) @@ -728,8 +741,10 @@ void QWaylandInputDevice::Pointer::pointer_axis(uint32_t time, uint32_t axis, in void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, uint32_t size) { + mKeymapFormat = format; #if QT_CONFIG(xkbcommon) if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + qCWarning(lcQpaWayland) << "unknown keymap format:" << format; close(fd); return; } @@ -751,7 +766,6 @@ void QWaylandInputDevice::Keyboard::keyboard_keymap(uint32_t format, int32_t fd, else mXkbState.reset(nullptr); #else - Q_UNUSED(format); Q_UNUSED(fd); Q_UNUSED(size); #endif @@ -798,29 +812,34 @@ void QWaylandInputDevice::Keyboard::keyboard_leave(uint32_t time, struct wl_surf handleFocusLost(); } -void QWaylandInputDevice::Keyboard::sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, - Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, - quint32 nativeVirtualKey, quint32 nativeModifiers, - const QString& text, bool autorep, ushort count) +void QWaylandInputDevice::Keyboard::handleKey(ulong timestamp, QEvent::Type type, int key, + Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, + quint32 nativeVirtualKey, quint32 nativeModifiers, + const QString &text, bool autorepeat, ushort count) { QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext(); bool filtered = false; if (inputContext && !mParent->mQDisplay->usingInputContextFromCompositor()) { QKeyEvent event(type, key, modifiers, nativeScanCode, nativeVirtualKey, - nativeModifiers, text, autorep, count); + nativeModifiers, text, autorepeat, count); event.setTimestamp(timestamp); filtered = inputContext->filterEvent(&event); } if (!filtered) { - QWindowSystemInterface::handleExtendedKeyEvent(tlw, timestamp, type, key, modifiers, - nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count); + QWindowSystemInterface::handleExtendedKeyEvent(focusWindow()->window(), timestamp, type, key, modifiers, + nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorepeat, count); } } void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { + if (mKeymapFormat != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 && mKeymapFormat != WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) { + qCWarning(lcQpaWayland) << Q_FUNC_INFO << "unknown keymap format:" << mKeymapFormat; + return; + } + auto *window = focusWindow(); if (!window) { // We destroyed the keyboard focus surface, but the server didn't get the message yet... @@ -828,76 +847,53 @@ void QWaylandInputDevice::Keyboard::keyboard_key(uint32_t serial, uint32_t time, return; } - uint32_t code = key + 8; - bool isDown = state != WL_KEYBOARD_KEY_STATE_RELEASED; - QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease; - QString text; - int qtkey = key + 8; // qt-compositor substracts 8 for some reason mParent->mSerial = serial; + const bool isDown = state != WL_KEYBOARD_KEY_STATE_RELEASED; if (isDown) mParent->mQDisplay->setLastInputDevice(mParent, serial, window); + if (mKeymapFormat == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { #if QT_CONFIG(xkbcommon) - if ((!mXkbKeymap || !mXkbState) && !createDefaultKeymap()) - return; - - xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState.get(), code); - - Qt::KeyboardModifiers modifiers = mParent->modifiers(); + if ((!mXkbKeymap || !mXkbState) && !createDefaultKeymap()) + return; - std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, modifiers); + auto code = key + 8; // map to wl_keyboard::keymap_format::keymap_format_xkb_v1 - sendKey(window->window(), time, type, qtkey, modifiers, code, sym, mNativeModifiers, text); -#else - // Generic fallback for single hard keys: Assume 'key' is a Qt key code. - sendKey(window->window(), time, type, qtkey, Qt::NoModifier, code, 0, 0); -#endif + xkb_keysym_t sym = xkb_state_key_get_one_sym(mXkbState.get(), code); - if (state == WL_KEYBOARD_KEY_STATE_PRESSED -#if QT_CONFIG(xkbcommon) - && xkb_keymap_key_repeats(mXkbKeymap.get(), code) -#endif - ) { - mRepeatKey = qtkey; - mRepeatCode = code; - mRepeatTime = time; - mRepeatText = text; -#if QT_CONFIG(xkbcommon) - mRepeatSym = sym; -#endif - mRepeatTimer.setInterval(mRepeatDelay); - mRepeatTimer.start(); - } else if (mRepeatCode == code) { - mRepeatTimer.stop(); - } -} + Qt::KeyboardModifiers modifiers = mParent->modifiers(); -void QWaylandInputDevice::Keyboard::repeatKey() -{ - auto *window = focusWindow(); - if (!window) { - // We destroyed the keyboard focus surface, but the server didn't get the message yet... - // or the server didn't send an enter event first. - return; - } + int qtkey = 0; + QString text; + std::tie(qtkey, text) = QWaylandXkb::keysymToQtKey(sym, modifiers); - mRepeatTimer.setInterval(mRepeatRate); - sendKey(window->window(), mRepeatTime, QEvent::KeyRelease, mRepeatKey, modifiers(), mRepeatCode, -#if QT_CONFIG(xkbcommon) - mRepeatSym, mNativeModifiers, -#else - 0, 0, -#endif - mRepeatText, true); + QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease; + handleKey(time, type, qtkey, modifiers, code, sym, mNativeModifiers, text); - sendKey(window->window(), mRepeatTime, QEvent::KeyPress, mRepeatKey, modifiers(), mRepeatCode, -#if QT_CONFIG(xkbcommon) - mRepeatSym, mNativeModifiers, + if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(mXkbKeymap.get(), code)) { + mRepeatKey.key = qtkey; + mRepeatKey.code = code; + mRepeatKey.time = time; + mRepeatKey.text = text; + mRepeatKey.modifiers = modifiers; + mRepeatKey.nativeModifiers = mNativeModifiers; + mRepeatKey.nativeVirtualKey = sym; + mRepeatTimer.setInterval(mRepeatDelay); + mRepeatTimer.start(); + } else if (mRepeatKey.code == code) { + mRepeatTimer.stop(); + } #else - 0, 0, + Q_UNUSED(time); + Q_UNUSED(key); + qCWarning(lcQpaWayland, "xkbcommon not available on this build, not performing key mapping"); + return; #endif - mRepeatText, true); + } else if (mKeymapFormat == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) { + // raw scan code + return; + } } void QWaylandInputDevice::Keyboard::handleFocusDestroyed() @@ -935,7 +931,6 @@ void QWaylandInputDevice::Keyboard::keyboard_modifiers(uint32_t serial, 0, 0, group); mNativeModifiers = mods_depressed | mods_latched | mods_locked; #else - Q_UNUSED(serial); Q_UNUSED(mods_depressed); Q_UNUSED(mods_latched); Q_UNUSED(mods_locked); diff --git a/src/client/qwaylandinputdevice_p.h b/src/client/qwaylandinputdevice_p.h index 98e60286e..2dc3ddc27 100644 --- a/src/client/qwaylandinputdevice_p.h +++ b/src/client/qwaylandinputdevice_p.h @@ -211,18 +211,25 @@ public: uint32_t mNativeModifiers = 0; - int mRepeatKey; - uint32_t mRepeatCode; - uint32_t mRepeatTime; + struct repeatKey { + int key; + uint32_t code; + uint32_t time; + QString text; + Qt::KeyboardModifiers modifiers; + uint32_t nativeVirtualKey; + uint32_t nativeModifiers; + } mRepeatKey; + + QTimer mRepeatTimer; int mRepeatRate = 25; int mRepeatDelay = 400; - QString mRepeatText; - QTimer mRepeatTimer; + + uint32_t mKeymapFormat = WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1; Qt::KeyboardModifiers modifiers() const; private slots: - void repeatKey(); void handleFocusDestroyed(); void handleFocusLost(); @@ -230,12 +237,11 @@ private: #if QT_CONFIG(xkbcommon) bool createDefaultKeymap(); #endif - void sendKey(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, - quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, - const QString& text = QString(), bool autorep = false, ushort count = 1); + void handleKey(ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, + quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, + const QString &text, bool autorepeat = false, ushort count = 1); #if QT_CONFIG(xkbcommon) - xkb_keysym_t mRepeatSym = XKB_KEY_NoSymbol; QXkbCommon::ScopedXKBKeymap mXkbKeymap; QXkbCommon::ScopedXKBState mXkbState; #endif diff --git a/src/compositor/compositor_api/qwaylandkeyboard.cpp b/src/compositor/compositor_api/qwaylandkeyboard.cpp index e84eed64a..f66fe3263 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard.cpp +++ b/src/compositor/compositor_api/qwaylandkeyboard.cpp @@ -143,7 +143,7 @@ void QWaylandKeyboardPrivate::keyboard_bind_resource(wl_keyboard::Resource *reso #endif { int null_fd = open("/dev/null", O_RDONLY); - send_keymap(resource->handle, 0 /* WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP */, + send_keymap(resource->handle, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP, null_fd, 0); close(null_fd); } @@ -163,11 +163,8 @@ void QWaylandKeyboardPrivate::keyboard_release(wl_keyboard::Resource *resource) void QWaylandKeyboardPrivate::keyEvent(uint code, uint32_t state) { -#if QT_CONFIG(xkbcommon) - uint key = toWaylandXkbV1Key(code); -#else - uint key = code; -#endif + uint key = toWaylandKey(code); + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { keys << key; } else { @@ -179,11 +176,7 @@ void QWaylandKeyboardPrivate::sendKeyEvent(uint code, uint32_t state) { uint32_t time = compositor()->currentTimeMsecs(); uint32_t serial = compositor()->nextSerial(); -#if QT_CONFIG(xkbcommon) - uint key = toWaylandXkbV1Key(code); -#else - uint key = code; -#endif + uint key = toWaylandKey(code); if (focusResource) send_key(focusResource->handle, serial, time, key, state); } @@ -284,6 +277,24 @@ void QWaylandKeyboardPrivate::maybeUpdateKeymap() #endif } +uint QWaylandKeyboardPrivate::toWaylandKey(const uint nativeScanCode) +{ +#if QT_CONFIG(xkbcommon) + // In all current XKB keymaps there's a constant offset of 8 (for historical + // reasons) from hardware/evdev scancodes to XKB keycodes. On X11, we pass + // XKB keycodes (as sent by X server) via QKeyEvent::nativeScanCode. eglfs+evdev + // adds 8 for consistency, see qtbase/05c07c7636012ebb4131ca099ca4ea093af76410. + // eglfs+libinput also adds 8, for the same reason. Wayland protocol uses + // hardware/evdev scancodes, thus we need to minus 8 before sending the event + // out. + const uint offset = 8; + Q_ASSERT(nativeScanCode >= offset); + return nativeScanCode - offset; +#else + return nativeScanCode; +#endif +} + #if QT_CONFIG(xkbcommon) static int createAnonymousFile(size_t size) { @@ -348,13 +359,6 @@ void QWaylandKeyboardPrivate::createXKBState(xkb_keymap *keymap) qWarning("Failed to create XKB state"); } -uint QWaylandKeyboardPrivate::toWaylandXkbV1Key(const uint nativeScanCode) -{ - const uint offset = 8; - Q_ASSERT(nativeScanCode >= offset); - return nativeScanCode - offset; -} - void QWaylandKeyboardPrivate::createXKBKeymap() { if (!xkbContext()) diff --git a/src/compositor/compositor_api/qwaylandkeyboard_p.h b/src/compositor/compositor_api/qwaylandkeyboard_p.h index c4d29c2d6..fb3f5fe34 100644 --- a/src/compositor/compositor_api/qwaylandkeyboard_p.h +++ b/src/compositor/compositor_api/qwaylandkeyboard_p.h @@ -115,7 +115,7 @@ private: void createXKBKeymap(); void createXKBState(xkb_keymap *keymap); #endif - static uint toWaylandXkbV1Key(const uint nativeScanCode); + static uint toWaylandKey(const uint nativeScanCode); void sendRepeatInfo(); |