inputmethod: Allow input methods to grab the keyboard

This allows different input methods to get information about what's
beign typed from the actual hardware. This is especially useful for
non-latin script languages.
This commit is contained in:
Aleix Pol 2021-06-01 18:15:47 +02:00
parent c5ea99cbe5
commit 454425b43f
4 changed files with 51 additions and 4 deletions

View file

@ -33,6 +33,7 @@
#include <QDBusPendingCall>
#include <QDBusMessage>
#include <QMenu>
#include <QKeyEvent>
#include <linux/input-event-codes.h>
#include <xkbcommon/xkbcommon-keysyms.h>
@ -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);
});
}
}

View file

@ -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();

View file

@ -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<char> 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)

View file

@ -98,6 +98,7 @@ public:
void forwardModifiers();
void setSeat(KWaylandServer::SeatInterface *seat);
QByteArray keymapContents() const;
Q_SIGNALS:
void ledsChanged(const LEDs &leds);