Commit 729a9d4d authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

Implement input method v1 keyboard grabs

The protocol is rather ambiguous regarding what events should be sent.
So, we send only hardware key events.

Another corner case is that the client has no way to indicate what
version of wl_keyboard it supports. In order to avoid crashing clients,
the grab_keyboard request returns wl_keyboard objects of v1.
parent 89f73408
Pipeline #56004 passed with stage
in 8 minutes and 9 seconds
......@@ -178,7 +178,7 @@ void TestInputMethodInterface::initTestCase()
m_seat = new SeatInterface(&m_display, this);
m_serverCompositor = new CompositorInterface(&m_display, this);
m_inputMethodIface = new InputMethodV1Interface(&m_display, this);
m_inputMethodIface = new InputMethodV1Interface(&m_display, m_seat, this);
m_inputPanelIface = new InputPanelV1Interface(&m_display, this);
auto outputIface = new OutputInterface(&m_display, this);
outputIface->create();
......
......@@ -5,8 +5,10 @@
*/
#include "inputmethod_v1_interface.h"
#include "inputmethod_v1_interface_p.h"
#include "seat_interface.h"
#include "display.h"
#include "logging.h"
#include "surface_interface.h"
#include "output_interface.h"
#include "surfacerole_p.h"
......@@ -24,9 +26,11 @@ static int s_version = 1;
class InputMethodContextV1InterfacePrivate : public QtWaylandServer::zwp_input_method_context_v1
{
public:
InputMethodContextV1InterfacePrivate(InputMethodContextV1Interface *q)
InputMethodContextV1InterfacePrivate(InputMethodContextV1Interface *q,
InputMethodV1Interface *inputMethod)
: zwp_input_method_context_v1()
, q(q)
, inputMethod(inputMethod)
{
}
......@@ -80,9 +84,31 @@ public:
{
Q_EMIT q->keysym(serial, time, sym, state == WL_KEYBOARD_KEY_STATE_PRESSED, toQtModifiers(modifiers));
}
void zwp_input_method_context_v1_grab_keyboard(Resource *, uint32_t keyboard) override
void zwp_input_method_context_v1_grab_keyboard(Resource *resource, uint32_t keyboard) override
{
Q_EMIT q->grabKeyboard(keyboard);
if (keyboardGrab) {
qCWarning(KWAYLAND_SERVER) << "Input method already has keyboard grab";
return;
}
SeatInterface *seat = inputMethod->seat();
if (!seat->hasKeyboard()) {
qCWarning(KWAYLAND_SERVER) << "wl_keyboard capability is missing, but im tried to grab keyboard";
return;
}
// The client has no way to indicate what version of wl_keyboard it prefers. So,
// create a wl_keyboard of v1 to prevent crashing the input method.
wl_resource *keyboardResource = wl_resource_create(resource->client(), &wl_keyboard_interface,
1, keyboard);
if (!keyboardResource) {
wl_resource_post_no_memory(resource->handle);
return;
}
InputMethodKeyboardV1 *dummyKeyboard = new InputMethodKeyboardV1(keyboardResource);
keyboardGrab = new InputMethodKeyboardGrabV1(seat, dummyKeyboard, q);
keyboardGrab->setActive(true);
}
void zwp_input_method_context_v1_key(Resource *, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) override
{
......@@ -133,12 +159,14 @@ public:
private:
InputMethodContextV1Interface *const q;
InputMethodV1Interface *inputMethod;
QVector<Qt::KeyboardModifiers> mods;
QPointer<InputMethodKeyboardGrabV1> keyboardGrab;
};
InputMethodContextV1Interface::InputMethodContextV1Interface(InputMethodV1Interface *parent)
: QObject(parent)
, d(new InputMethodContextV1InterfacePrivate(this))
, d(new InputMethodContextV1InterfacePrivate(this, parent))
{
}
......@@ -352,10 +380,11 @@ SurfaceInterface *InputPanelSurfaceV1Interface::surface() const
class InputMethodV1InterfacePrivate : public QtWaylandServer::zwp_input_method_v1
{
public:
InputMethodV1InterfacePrivate(Display *d, InputMethodV1Interface *q)
InputMethodV1InterfacePrivate(Display *d, SeatInterface *seat, InputMethodV1Interface *q)
: zwp_input_method_v1(*d, s_version)
, q(q)
, m_display(d)
, m_seat(seat)
{
}
......@@ -372,11 +401,12 @@ public:
InputMethodContextV1Interface *m_context = nullptr;
InputMethodV1Interface *const q;
Display *const m_display;
SeatInterface *const m_seat;
};
InputMethodV1Interface::InputMethodV1Interface(Display *d, QObject *parent)
InputMethodV1Interface::InputMethodV1Interface(Display *d, SeatInterface *seat, QObject *parent)
: QObject(parent)
, d(new InputMethodV1InterfacePrivate(d, this))
, d(new InputMethodV1InterfacePrivate(d, seat, this))
{
}
......@@ -412,9 +442,53 @@ void InputMethodV1Interface::sendDeactivate()
d->m_context = nullptr;
}
SeatInterface *InputMethodV1Interface::seat() const
{
return d->m_seat;
}
InputMethodContextV1Interface *InputMethodV1Interface::context() const
{
return d->m_context;
}
InputMethodKeyboardV1::InputMethodKeyboardV1(::wl_resource *resource)
: QtWaylandServer::wl_keyboard(resource)
{
}
InputMethodKeyboardGrabV1::InputMethodKeyboardGrabV1(SeatInterface *seat,
InputMethodKeyboardV1 *keyboard,
QObject *parent)
: QObject(parent)
, KeyboardGrab(seat)
, m_keyboard(keyboard)
{
}
void InputMethodKeyboardGrabV1::cancel()
{
delete this;
}
void InputMethodKeyboardGrabV1::handleFocus(SurfaceInterface *surface, quint32 serial)
{
Q_UNUSED(surface)
Q_UNUSED(serial)
}
void InputMethodKeyboardGrabV1::handleKey(quint32 keyCode, KeyboardKeyState state)
{
const quint32 serial = seat()->display()->nextSerial();
m_keyboard->send_key(serial, seat()->timestamp(), keyCode, quint32(state));
}
void InputMethodKeyboardGrabV1::handleModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group)
{
Q_UNUSED(depressed)
Q_UNUSED(latched)
Q_UNUSED(locked)
Q_UNUSED(group)
}
}
......@@ -20,6 +20,7 @@ class SurfaceInterface;
class Display;
class InputPanelSurfaceV1Interface;
class InputMethodContextV1Interface;
class SeatInterface;
class InputMethodV1InterfacePrivate;
class InputMethodContextV1InterfacePrivate;
......@@ -37,7 +38,7 @@ class KWAYLANDSERVER_EXPORT InputMethodV1Interface : public QObject
{
Q_OBJECT
public:
InputMethodV1Interface(Display *d, QObject *parent);
InputMethodV1Interface(Display *d, SeatInterface *seat, QObject *parent);
~InputMethodV1Interface() override;
/**
......@@ -51,6 +52,7 @@ public:
*/
void sendDeactivate();
SeatInterface *seat() const;
InputMethodContextV1Interface *context() const;
private:
......@@ -81,7 +83,6 @@ Q_SIGNALS:
void deleteSurroundingText(qint32 index, quint32 length);
void cursorPosition(qint32 index, qint32 anchor);
void keysym(quint32 serial, quint32 time, quint32 sym, bool pressed, Qt::KeyboardModifiers modifiers);
void grabKeyboard(quint32 keyboard);
void key(quint32 serial, quint32 time, quint32 key, bool pressed);
void modifiers(quint32 serial, quint32 mods_depressed, quint32 mods_latched, quint32 mods_locked, quint32 group);
void language(quint32 serial, const QString &language);
......
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include "keyboardgrab.h"
// auto-generated
#include "qwayland-server-wayland.h"
namespace KWaylandServer
{
class InputMethodKeyboardV1 : public QtWaylandServer::wl_keyboard
{
public:
explicit InputMethodKeyboardV1(::wl_resource *resource);
};
class InputMethodKeyboardGrabV1 : public QObject, public KeyboardGrab
{
Q_OBJECT
public:
InputMethodKeyboardGrabV1(SeatInterface *seat, InputMethodKeyboardV1 *keyboard, QObject *parent);
void cancel() override;
void handleFocus(SurfaceInterface *surface, quint32 serial) override;
void handleKey(quint32 keyCode, KeyboardKeyState state) override;
void handleModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group) override;
private:
QScopedPointer<InputMethodKeyboardV1> m_keyboard;
};
} // namespace KWaylandServer
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment