diff --git a/src/inputmethod.cpp b/src/inputmethod.cpp index c22007bcad..89b6584554 100644 --- a/src/inputmethod.cpp +++ b/src/inputmethod.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -472,6 +473,7 @@ void InputMethod::adoptInputMethodContext() connect(inputContext, &KWaylandServer::InputMethodContextV1Interface::cursorPosition, this, &InputMethod::setCursorPosition, Qt::UniqueConnection); connect(inputContext, &KWaylandServer::InputMethodContextV1Interface::preeditString, this, &InputMethod::setPreeditString, Qt::UniqueConnection); connect(inputContext, &KWaylandServer::InputMethodContextV1Interface::preeditCursor, this, &InputMethod::setPreeditCursor, Qt::UniqueConnection); + connect(inputContext, &KWaylandServer::InputMethodContextV1Interface::keyboardGrabRequested, this, &InputMethod::installKeyboardGrab, Qt::UniqueConnection); } void InputMethod::updateSni() @@ -628,5 +630,34 @@ bool InputMethod::isActive() const return waylandServer()->inputMethod()->context(); } +class InputKeyboardFilter : public InputEventFilter { +public: + InputKeyboardFilter(KWaylandServer::InputMethodGrabV1 *grab) + : m_keyboardGrab(grab) + { + } + + bool keyEvent(QKeyEvent *event) override { + if (event->isAutoRepeat()) { + return true; + } + auto newState = event->type() == QEvent::KeyPress ? KWaylandServer::KeyboardKeyState::Pressed : KWaylandServer::KeyboardKeyState::Released; + m_keyboardGrab->sendKey(waylandServer()->display()->nextSerial(), event->timestamp(), event->nativeScanCode(), newState); + return true; + } + InputMethodGrabV1 *const m_keyboardGrab; +}; + +void InputMethod::installKeyboardGrab(KWaylandServer::InputMethodGrabV1 *keyboardGrab) +{ + auto xkb = input()->keyboard()->xkb(); + auto filter = new InputKeyboardFilter(keyboardGrab); + keyboardGrab->sendKeymap(xkb->keymapContents()); + input()->prependInputEventFilter(filter); + connect(keyboardGrab, &QObject::destroyed, input(), [filter] { + input()->uninstallInputEventFilter(filter); + }); +} + } diff --git a/src/inputmethod.h b/src/inputmethod.h index 45a94317ed..ecc12e19ed 100644 --- a/src/inputmethod.h +++ b/src/inputmethod.h @@ -21,6 +21,11 @@ class KStatusNotifierItem; class QProcess; +namespace KWaylandServer +{ +class InputMethodGrabV1; +} + namespace KWin { @@ -81,6 +86,7 @@ private: void startInputMethod(); void stopInputMethod(); void setTrackedClient(AbstractClient *trackedClient); + void installKeyboardGrab(KWaylandServer::InputMethodGrabV1 *keyboardGrab); struct { QString text = QString(); diff --git a/src/xkb.cpp b/src/xkb.cpp index ef8006f39a..2d5adfd746 100644 --- a/src/xkb.cpp +++ b/src/xkb.cpp @@ -284,19 +284,28 @@ void Xkb::updateKeymap(xkb_keymap *keymap) void Xkb::createKeymapFile() { - if (!m_seat || !m_seat->keyboard()) { + const auto currentKeymap = keymapContents(); + if (currentKeymap.isEmpty()) { return; } + m_seat->keyboard()->setKeymap(currentKeymap); +} + +QByteArray Xkb::keymapContents() const +{ + if (!m_seat || !m_seat->keyboard()) { + return {}; + } // TODO: uninstall keymap on server? if (!m_keymap) { - return; + return {}; } ScopedCPointer keymapString(xkb_keymap_get_as_string(m_keymap, XKB_KEYMAP_FORMAT_TEXT_V1)); if (keymapString.isNull()) { - return; + return {}; } - m_seat->keyboard()->setKeymap(keymapString.data()); + return keymapString.data(); } void Xkb::updateModifiers(uint32_t modsDepressed, uint32_t modsLatched, uint32_t modsLocked, uint32_t group) diff --git a/src/xkb.h b/src/xkb.h index f82545bebe..e610d37ae6 100644 --- a/src/xkb.h +++ b/src/xkb.h @@ -98,6 +98,7 @@ public: void forwardModifiers(); void setSeat(KWaylandServer::SeatInterface *seat); + QByteArray keymapContents() const; Q_SIGNALS: void ledsChanged(const LEDs &leds);