Commit 48326670 authored by Martin Flöser's avatar Martin Flöser
Browse files

Implement repeat info on wl_keyboard protocol

* Raises wl_seat supported version to 4 in both server and client
* Raises wl_keyboard supported version to 4 in wl_keyboard
* wl_pointer and wl_touch are still on version 3
* Raises minimum Wayland version to 1.6
parent 7207c4ed
......@@ -28,7 +28,7 @@ ecm_setup_version(${KF5_VERSION} VARIABLE_PREFIX KWAYLAND
set(REQUIRED_QT_VERSION 5.4.0)
find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Gui)
find_package(Wayland 1.3 COMPONENTS Client Server)
find_package(Wayland 1.6 COMPONENTS Client Server)
set_package_properties(Wayland PROPERTIES
TYPE REQUIRED
)
......
......@@ -642,12 +642,32 @@ void TestWaylandSeat::testKeyboard()
QVERIFY(!m_seatInterface->focusedKeyboard());
Keyboard *keyboard = m_seat->createKeyboard(m_seat);
QSignalSpy repeatInfoSpy(keyboard, &Keyboard::keyRepeatChanged);
QVERIFY(repeatInfoSpy.isValid());
const Keyboard &ckeyboard = *keyboard;
QVERIFY(keyboard->isValid());
QCOMPARE(keyboard->isKeyRepeatEnabled(), false);
QCOMPARE(keyboard->keyRepeatDelay(), 0);
QCOMPARE(keyboard->keyRepeatRate(), 0);
wl_display_flush(m_connection->display());
QTest::qWait(100);
QVERIFY(m_seatInterface->focusedKeyboard());
// we should get the repeat info announced
QCOMPARE(repeatInfoSpy.count(), 1);
QCOMPARE(keyboard->isKeyRepeatEnabled(), false);
QCOMPARE(keyboard->keyRepeatDelay(), 0);
QCOMPARE(keyboard->keyRepeatRate(), 0);
// let's change repeat in server
m_seatInterface->setKeyRepeatInfo(25, 660);
m_seatInterface->focusedKeyboard()->client()->flush();
QVERIFY(repeatInfoSpy.wait());
QCOMPARE(repeatInfoSpy.count(), 2);
QCOMPARE(keyboard->isKeyRepeatEnabled(), true);
QCOMPARE(keyboard->keyRepeatRate(), 25);
QCOMPARE(keyboard->keyRepeatDelay(), 660);
m_seatInterface->setTimestamp(1);
m_seatInterface->keyPressed(KEY_K);
m_seatInterface->setTimestamp(2);
......@@ -745,6 +765,20 @@ void TestWaylandSeat::testKeyboard()
QTest::qWait(100);
QVERIFY(!m_seatInterface->focusedKeyboardSurface());
QVERIFY(!m_seatInterface->focusedKeyboard());
// create a second Keyboard to verify that repeat info is announced properly
Keyboard *keyboard2 = m_seat->createKeyboard(m_seat);
QSignalSpy repeatInfoSpy2(keyboard2, &Keyboard::keyRepeatChanged);
QVERIFY(repeatInfoSpy2.isValid());
QVERIFY(keyboard2->isValid());
QCOMPARE(keyboard2->isKeyRepeatEnabled(), false);
QCOMPARE(keyboard2->keyRepeatDelay(), 0);
QCOMPARE(keyboard2->keyRepeatRate(), 0);
wl_display_flush(m_connection->display());
QVERIFY(repeatInfoSpy2.wait());
QCOMPARE(keyboard2->isKeyRepeatEnabled(), true);
QCOMPARE(keyboard2->keyRepeatRate(), 25);
QCOMPARE(keyboard2->keyRepeatDelay(), 660);
}
void TestWaylandSeat::testCast()
......
......@@ -36,6 +36,7 @@ private Q_SLOTS:
void testPointerButton();
void testPointerPos();
void testDestroyThroughTerminate();
void testRepeatInfo();
};
static const QString s_socketName = QStringLiteral("kwin-wayland-server-seat-test-0");
......@@ -179,5 +180,22 @@ void TestWaylandServerSeat::testDestroyThroughTerminate()
QVERIFY(!destroyedSpy.isEmpty());
}
void TestWaylandServerSeat::testRepeatInfo()
{
Display display;
display.setSocketName(s_socketName);
display.start();
SeatInterface *seat = display.createSeat();
QCOMPARE(seat->keyRepeatRate(), 0);
QCOMPARE(seat->keyRepeatDelay(), 0);
seat->setKeyRepeatInfo(25, 660);
QCOMPARE(seat->keyRepeatRate(), 25);
QCOMPARE(seat->keyRepeatDelay(), 660);
// setting negative values should result in 0
seat->setKeyRepeatInfo(-25, -660);
QCOMPARE(seat->keyRepeatRate(), 0);
QCOMPARE(seat->keyRepeatDelay(), 0);
}
QTEST_GUILESS_MAIN(TestWaylandServerSeat)
#include "test_seat.moc"
......@@ -36,6 +36,11 @@ public:
WaylandPointer<wl_keyboard, wl_keyboard_destroy> keyboard;
Surface *enteredSurface = nullptr;
struct {
qint32 charactersPerSecond = 0;
qint32 delay = 0;
} repeatInfo;
private:
void enter(uint32_t serial, wl_surface *surface, wl_array *keys);
void leave(uint32_t serial);
......@@ -45,6 +50,7 @@ private:
static void keyCallback(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
static void modifiersCallback(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t modsDepressed,
uint32_t modsLatched, uint32_t modsLocked, uint32_t group);
static void repeatInfoCallback(void *data, wl_keyboard *keyboard, int32_t charactersPerSecond, int32_t delay);
Keyboard *q;
static const wl_keyboard_listener s_listener;
};
......@@ -67,7 +73,8 @@ const wl_keyboard_listener Keyboard::Private::s_listener = {
enterCallback,
leaveCallback,
keyCallback,
modifiersCallback
modifiersCallback,
repeatInfoCallback
};
Keyboard::Keyboard(QObject *parent)
......@@ -158,6 +165,15 @@ void Keyboard::Private::modifiersCallback(void *data, wl_keyboard *keyboard, uin
emit k->q->modifiersChanged(modsDepressed, modsLatched, modsLocked, group);
}
void Keyboard::Private::repeatInfoCallback(void *data, wl_keyboard *keyboard, int32_t charactersPerSecond, int32_t delay)
{
auto k = reinterpret_cast<Keyboard::Private*>(data);
Q_ASSERT(k->keyboard == keyboard);
k->repeatInfo.charactersPerSecond = qMax(charactersPerSecond, 0);
k->repeatInfo.delay = qMax(delay, 0);
emit k->q->keyRepeatChanged();
}
Surface *Keyboard::enteredSurface()
{
return d->enteredSurface;
......@@ -173,6 +189,21 @@ bool Keyboard::isValid() const
return d->keyboard.isValid();
}
bool Keyboard::isKeyRepeatEnabled() const
{
return d->repeatInfo.charactersPerSecond > 0;
}
qint32 Keyboard::keyRepeatDelay() const
{
return d->repeatInfo.delay;
}
qint32 Keyboard::keyRepeatRate() const
{
return d->repeatInfo.charactersPerSecond;
}
Keyboard::operator wl_keyboard*()
{
return d->keyboard;
......
......@@ -97,6 +97,31 @@ public:
**/
Surface *enteredSurface();
/**
* @returns Whether key repeat is enabled on this keyboard
* @see keyRepeatRate
* @see keyRepeatDelay
* @see keyRepeatChanged
* @since 5.5
**/
bool isKeyRepeatEnabled() const;
/**
* @returns the key repeat rate in characters per second.
* @see isKeyRepeatEnabled
* @see keyRepeatDelay
* @see keyRepeatChanged
* @since 5.5
**/
qint32 keyRepeatRate() const;
/**
* @returns the delay in millisecond for key repeat after a press.
* @see isKeyRepeatEnabled
* @see keyRepeatRate
* @see keyRepeatChanged
* @since 5.5
**/
qint32 keyRepeatDelay() const;
operator wl_keyboard*();
operator wl_keyboard*() const;
......@@ -138,6 +163,14 @@ Q_SIGNALS:
* and it should update its local state.
**/
void modifiersChanged(quint32 depressed, quint32 latched, quint32 locked, quint32 group);
/**
* Emitted whenever information on key repeat changed.
* @see isKeyRepeatEnabled
* @see keyRepeatRate
* @see keyRepeatDelay
* @since 5.5
**/
void keyRepeatChanged();
private:
class Private;
......
......@@ -102,7 +102,7 @@ static const QMap<Registry::Interface, SuppertedInterfaceData> s_interfaces = {
&Registry::shmRemoved
}},
{Registry::Interface::Seat, {
3,
4,
QByteArrayLiteral("wl_seat"),
&wl_seat_interface,
&Registry::seatAnnounced,
......
......@@ -169,6 +169,16 @@ void KeyboardInterface::updateModifiers(quint32 depressed, quint32 latched, quin
d->sendModifiers(depressed, latched, locked, group, serial);
}
void KeyboardInterface::repeatInfo(qint32 charactersPerSecond, qint32 delay)
{
Q_D();
if (wl_resource_get_version(d->resource) < 4) {
// only supported since version 4
return;
}
wl_keyboard_send_repeat_info(d->resource, charactersPerSecond, delay);
}
SurfaceInterface *KeyboardInterface::focusedSurface() const
{
Q_D();
......
......@@ -46,6 +46,7 @@ private:
void updateModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group, quint32 serial);
void keyPressed(quint32 key, quint32 serial);
void keyReleased(quint32 key, quint32 serial);
void repeatInfo(qint32 charactersPerSecond, qint32 delay);
friend class SeatInterface;
explicit KeyboardInterface(SeatInterface *parent, wl_resource *parentResource);
......
......@@ -38,7 +38,10 @@ namespace KWayland
namespace Server
{
static const quint32 s_version = 3;
static const quint32 s_version = 4;
static const qint32 s_pointerVersion = 3;
static const qint32 s_touchVersion = 3;
static const qint32 s_keyboardVersion = 4;
SeatInterface::Private::Private(SeatInterface *q, Display *display)
: Global::Private(display, &wl_seat_interface, s_version)
......@@ -303,7 +306,7 @@ void SeatInterface::Private::getPointer(wl_client *client, wl_resource *resource
{
// TODO: only create if seat has pointer?
PointerInterface *pointer = new PointerInterface(q, resource);
pointer->create(display->getConnection(client), wl_resource_get_version(resource), id);
pointer->create(display->getConnection(client), qMin(wl_resource_get_version(resource), s_pointerVersion), id);
if (!pointer->resource()) {
wl_resource_post_no_memory(resource);
delete pointer;
......@@ -337,12 +340,13 @@ void SeatInterface::Private::getKeyboard(wl_client *client, wl_resource *resourc
{
// TODO: only create if seat has keyboard?
KeyboardInterface *keyboard = new KeyboardInterface(q, resource);
keyboard->create(display->getConnection(client), wl_resource_get_version(resource), id);
keyboard->create(display->getConnection(client), qMin(wl_resource_get_version(resource), s_keyboardVersion) , id);
if (!keyboard->resource()) {
wl_resource_post_no_memory(resource);
delete keyboard;
return;
}
keyboard->repeatInfo(keys.keyRepeat.charactersPerSecond, keys.keyRepeat.delay);
if (keys.keymap.xkbcommonCompatible) {
keyboard->setKeymap(keys.keymap.fd, keys.keymap.size);
}
......@@ -374,7 +378,7 @@ void SeatInterface::Private::getTouch(wl_client *client, wl_resource *resource,
{
// TODO: only create if seat has touch?
TouchInterface *touch = new TouchInterface(q, resource);
touch->create(display->getConnection(client), wl_resource_get_version(resource), id);
touch->create(display->getConnection(client), qMin(wl_resource_get_version(resource), s_touchVersion), id);
if (!touch->resource()) {
wl_resource_post_no_memory(resource);
delete touch;
......@@ -718,6 +722,28 @@ void SeatInterface::updateKeyboardModifiers(quint32 depressed, quint32 latched,
}
}
void SeatInterface::setKeyRepeatInfo(qint32 charactersPerSecond, qint32 delay)
{
Q_D();
d->keys.keyRepeat.charactersPerSecond = qMax(charactersPerSecond, 0);
d->keys.keyRepeat.delay = qMax(delay, 0);
for (auto it = d->keyboards.constBegin(); it != d->keyboards.constEnd(); ++it) {
(*it)->repeatInfo(d->keys.keyRepeat.charactersPerSecond, d->keys.keyRepeat.delay);
}
}
qint32 SeatInterface::keyRepeatDelay() const
{
Q_D();
return d->keys.keyRepeat.delay;
}
qint32 SeatInterface::keyRepeatRate() const
{
Q_D();
return d->keys.keyRepeat.charactersPerSecond;
}
bool SeatInterface::isKeymapXkbCompatible() const
{
Q_D();
......
......@@ -89,6 +89,19 @@ public:
void keyPressed(quint32 key);
void keyReleased(quint32 key);
void updateKeyboardModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group);
/**
* Sets the key repeat information to be forwarded to all bound keyboards.
*
* To disable key repeat set a @p charactersPerSecond of @c 0.
*
* Requires wl_seat version 4.
*
* @param charactersPerSecond The characters per second rate, value of @c 0 disables key repeating
* @param delay The delay on key press before starting repeating keys
*
* @since 5.5
***/
void setKeyRepeatInfo(qint32 charactersPerSecond, qint32 delay);
quint32 depressedModifiers() const;
quint32 latchedModifiers() const;
quint32 lockedModifiers() const;
......@@ -98,6 +111,20 @@ public:
quint32 keymapSize() const;
bool isKeymapXkbCompatible() const;
QVector<quint32> pressedKeys() const;
/**
* @returns The key repeat in character per second
* @since 5.5
* @see setKeyRepeatInfo
* @see keyRepeatDelay
**/
qint32 keyRepeatRate() const;
/**
* @returns The delay on key press before starting repeating keys
* @since 5.5
* @see keyRepeatRate
* @see setKeyRepeatInfo
**/
qint32 keyRepeatDelay() const;
void setFocusedKeyboardSurface(SurfaceInterface *surface);
SurfaceInterface *focusedKeyboardSurface() const;
......
......@@ -112,6 +112,10 @@ public:
};
Focus focus;
quint32 lastStateSerial = 0;
struct {
qint32 charactersPerSecond = 0;
qint32 delay = 0;
} keyRepeat;
};
Keyboard keys;
void updateKey(quint32 key, Keyboard::State state);
......
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