abc6dae6df
This adds autotests for binding to tablet pad and tool buttons, which was previously untested. Of note is that we don't explicitly test mouse buttons, which is already tested in the other functions.
242 lines
9.7 KiB
C++
242 lines
9.7 KiB
C++
/*
|
|
KWin - the KDE window manager
|
|
This file is part of the KDE project.
|
|
|
|
SPDX-FileCopyrightText: 2024 Aleix Pol Gonzalez <aleixpol@kde.org>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
#include "kwin_wayland_test.h"
|
|
|
|
#include "pointer_input.h"
|
|
#include "wayland_server.h"
|
|
#include "workspace.h"
|
|
|
|
#include <KWayland/Client/keyboard.h>
|
|
#include <KWayland/Client/pointer.h>
|
|
#include <KWayland/Client/seat.h>
|
|
#include <linux/input-event-codes.h>
|
|
|
|
using namespace KWin;
|
|
|
|
static const QString s_socketName = QStringLiteral("wayland_test_kwin_buttonrebind-0");
|
|
|
|
class TestButtonRebind : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private Q_SLOTS:
|
|
void init();
|
|
void cleanup();
|
|
void initTestCase();
|
|
|
|
void testKey_data();
|
|
void testKey();
|
|
|
|
void testMouse_data();
|
|
void testMouse();
|
|
|
|
void testDisabled();
|
|
|
|
// NOTE: Mouse buttons are not tested because those are used in the other tests
|
|
void testBindingTabletPad();
|
|
void testBindingTabletTool();
|
|
|
|
private:
|
|
quint32 timestamp = 1;
|
|
};
|
|
|
|
void TestButtonRebind::init()
|
|
{
|
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat));
|
|
QVERIFY(Test::waitForWaylandPointer());
|
|
}
|
|
|
|
void TestButtonRebind::cleanup()
|
|
{
|
|
Test::destroyWaylandConnection();
|
|
QVERIFY(QFile::remove(QStandardPaths::locate(QStandardPaths::ConfigLocation, QStringLiteral("kcminputrc"))));
|
|
}
|
|
|
|
void TestButtonRebind::initTestCase()
|
|
{
|
|
qRegisterMetaType<KWin::Window *>();
|
|
QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
|
|
QVERIFY(waylandServer()->init(s_socketName));
|
|
Test::setOutputConfig({
|
|
QRect(0, 0, 1280, 1024),
|
|
QRect(1280, 0, 1280, 1024),
|
|
});
|
|
kwinApp()->start();
|
|
QVERIFY(applicationStartedSpy.wait());
|
|
}
|
|
|
|
void TestButtonRebind::testKey_data()
|
|
{
|
|
QTest::addColumn<QKeySequence>("boundKeys");
|
|
QTest::addColumn<QList<quint32>>("expectedKeys");
|
|
|
|
QTest::newRow("single key") << QKeySequence(Qt::Key_A) << QList<quint32>{KEY_A};
|
|
QTest::newRow("single modifier") << QKeySequence(Qt::Key_Control) << QList<quint32>{KEY_LEFTCTRL};
|
|
QTest::newRow("single modifier plus key") << QKeySequence(Qt::ControlModifier | Qt::Key_N) << QList<quint32>{KEY_LEFTCTRL, KEY_N};
|
|
QTest::newRow("multiple modifiers plus key") << QKeySequence(Qt::ControlModifier | Qt::MetaModifier | Qt::Key_Y) << QList<quint32>{KEY_LEFTCTRL, KEY_LEFTMETA, KEY_Y};
|
|
QTest::newRow("delete") << QKeySequence(Qt::Key_Delete) << QList<quint32>{KEY_DELETE};
|
|
QTest::newRow("keypad delete") << QKeySequence(Qt::KeypadModifier | Qt::Key_Delete) << QList<quint32>{KEY_KPDOT};
|
|
QTest::newRow("keypad enter") << QKeySequence(Qt::KeypadModifier | Qt::Key_Enter) << QList<quint32>{KEY_KPENTER};
|
|
}
|
|
|
|
void TestButtonRebind::testKey()
|
|
{
|
|
KConfigGroup buttonGroup = KSharedConfig::openConfig(QStringLiteral("kcminputrc"))->group(QStringLiteral("ButtonRebinds")).group(QStringLiteral("Mouse"));
|
|
QFETCH(QKeySequence, boundKeys);
|
|
buttonGroup.writeEntry("ExtraButton7", QStringList{"Key", boundKeys.toString(QKeySequence::PortableText)}, KConfig::Notify);
|
|
buttonGroup.sync();
|
|
|
|
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
|
|
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
|
|
Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
|
|
|
|
std::unique_ptr<KWayland::Client::Keyboard> keyboard(Test::waylandSeat()->createKeyboard());
|
|
QSignalSpy enteredSpy(keyboard.get(), &KWayland::Client::Keyboard::entered);
|
|
QSignalSpy keyChangedSpy(keyboard.get(), &KWayland::Client::Keyboard::keyChanged);
|
|
QVERIFY(enteredSpy.wait());
|
|
|
|
// 0x119 is Qt::ExtraButton7
|
|
Test::pointerButtonPressed(0x119, timestamp++);
|
|
|
|
QVERIFY(keyChangedSpy.wait());
|
|
QFETCH(QList<quint32>, expectedKeys);
|
|
QCOMPARE(keyChangedSpy.count(), expectedKeys.count());
|
|
for (int i = 0; i < keyChangedSpy.count(); i++) {
|
|
QCOMPARE(keyChangedSpy.at(i).at(0).value<quint32>(), expectedKeys.at(i));
|
|
QCOMPARE(keyChangedSpy.at(i).at(1).value<KWayland::Client::Keyboard::KeyState>(), KWayland::Client::Keyboard::KeyState::Pressed);
|
|
}
|
|
Test::pointerButtonReleased(0x119, timestamp++);
|
|
}
|
|
|
|
void TestButtonRebind::testMouse_data()
|
|
{
|
|
QTest::addColumn<int>("mouseButton");
|
|
|
|
QTest::newRow("left button") << BTN_LEFT;
|
|
QTest::newRow("middle button") << BTN_MIDDLE;
|
|
QTest::newRow("right button") << BTN_RIGHT;
|
|
}
|
|
|
|
void TestButtonRebind::testMouse()
|
|
{
|
|
KConfigGroup buttonGroup = KSharedConfig::openConfig(QStringLiteral("kcminputrc"))->group(QStringLiteral("ButtonRebinds")).group(QStringLiteral("Mouse"));
|
|
QFETCH(int, mouseButton);
|
|
buttonGroup.writeEntry("ExtraButton7", QStringList{"MouseButton", QString::number(mouseButton)}, KConfig::Notify);
|
|
buttonGroup.sync();
|
|
|
|
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
|
|
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
|
|
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
|
|
|
|
std::unique_ptr<KWayland::Client::Pointer> pointer(Test::waylandSeat()->createPointer());
|
|
QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
|
|
QSignalSpy buttonChangedSpy(pointer.get(), &KWayland::Client::Pointer::buttonStateChanged);
|
|
|
|
const QRectF startGeometry = window->frameGeometry();
|
|
input()->pointer()->warp(startGeometry.center());
|
|
|
|
QVERIFY(enteredSpy.wait());
|
|
|
|
// 0x119 is Qt::ExtraButton7
|
|
Test::pointerButtonPressed(0x119, timestamp++);
|
|
|
|
QVERIFY(buttonChangedSpy.wait());
|
|
|
|
QCOMPARE(buttonChangedSpy.count(), 1);
|
|
QCOMPARE(buttonChangedSpy.at(0).at(2).value<qint32>(), mouseButton);
|
|
|
|
Test::pointerButtonReleased(0x119, timestamp++);
|
|
}
|
|
|
|
void TestButtonRebind::testDisabled()
|
|
{
|
|
KConfigGroup buttonGroup = KSharedConfig::openConfig(QStringLiteral("kcminputrc"))->group(QStringLiteral("ButtonRebinds")).group(QStringLiteral("Mouse"));
|
|
buttonGroup.writeEntry("ExtraButton7", QStringList{"Disabled"}, KConfig::Notify);
|
|
buttonGroup.sync();
|
|
|
|
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
|
|
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
|
|
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
|
|
|
|
std::unique_ptr<KWayland::Client::Pointer> pointer(Test::waylandSeat()->createPointer());
|
|
QSignalSpy enteredSpy(pointer.get(), &KWayland::Client::Pointer::entered);
|
|
QSignalSpy buttonChangedSpy(pointer.get(), &KWayland::Client::Pointer::buttonStateChanged);
|
|
|
|
const QRectF startGeometry = window->frameGeometry();
|
|
input()->pointer()->warp(startGeometry.center());
|
|
|
|
QVERIFY(enteredSpy.wait());
|
|
|
|
// 0x119 is Qt::ExtraButton7
|
|
Test::pointerButtonPressed(0x119, timestamp++);
|
|
|
|
// Qt::ExtraButton7 should not have been emitted if this button is disabled
|
|
QVERIFY(!buttonChangedSpy.wait(std::chrono::milliseconds(100)));
|
|
QCOMPARE(buttonChangedSpy.count(), 0);
|
|
|
|
Test::pointerButtonReleased(0x119, timestamp++);
|
|
}
|
|
|
|
void TestButtonRebind::testBindingTabletPad()
|
|
{
|
|
const QKeySequence sequence(Qt::Key_A);
|
|
|
|
KConfigGroup buttonGroup = KSharedConfig::openConfig(QStringLiteral("kcminputrc"))->group(QStringLiteral("ButtonRebinds")).group(QStringLiteral("Tablet")).group(QStringLiteral("Virtual Tablet Pad 1"));
|
|
buttonGroup.writeEntry("1", QStringList{"Key", sequence.toString(QKeySequence::PortableText)}, KConfig::Notify);
|
|
buttonGroup.sync();
|
|
|
|
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
|
|
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
|
|
Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
|
|
|
|
std::unique_ptr<KWayland::Client::Keyboard> keyboard(Test::waylandSeat()->createKeyboard());
|
|
QSignalSpy enteredSpy(keyboard.get(), &KWayland::Client::Keyboard::entered);
|
|
QSignalSpy keyChangedSpy(keyboard.get(), &KWayland::Client::Keyboard::keyChanged);
|
|
QVERIFY(enteredSpy.wait());
|
|
|
|
Test::tabletPadButtonPressed(1, timestamp++);
|
|
|
|
QVERIFY(keyChangedSpy.wait());
|
|
QCOMPARE(keyChangedSpy.count(), 1);
|
|
QCOMPARE(keyChangedSpy.at(0).at(0), KEY_A);
|
|
|
|
Test::tabletPadButtonReleased(1, timestamp++);
|
|
}
|
|
|
|
void TestButtonRebind::testBindingTabletTool()
|
|
{
|
|
const QKeySequence sequence(Qt::Key_A);
|
|
|
|
KConfigGroup buttonGroup = KSharedConfig::openConfig(QStringLiteral("kcminputrc"))->group(QStringLiteral("ButtonRebinds")).group(QStringLiteral("TabletTool")).group(QStringLiteral("Virtual Tablet Tool 1"));
|
|
buttonGroup.writeEntry(QString::number(BTN_STYLUS), QStringList{"Key", sequence.toString(QKeySequence::PortableText)}, KConfig::Notify);
|
|
buttonGroup.sync();
|
|
|
|
std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface();
|
|
std::unique_ptr<Test::XdgToplevel> shellSurface = Test::createXdgToplevelSurface(surface.get());
|
|
auto window = Test::renderAndWaitForShown(surface.get(), QSize(100, 50), Qt::blue);
|
|
|
|
std::unique_ptr<KWayland::Client::Keyboard> keyboard(Test::waylandSeat()->createKeyboard());
|
|
QSignalSpy enteredSpy(keyboard.get(), &KWayland::Client::Keyboard::entered);
|
|
QSignalSpy keyChangedSpy(keyboard.get(), &KWayland::Client::Keyboard::keyChanged);
|
|
QVERIFY(enteredSpy.wait());
|
|
|
|
const QRectF startGeometry = window->frameGeometry();
|
|
Test::tabletToolEvent(InputRedirection::Tip, startGeometry.center(), 1.0, 0, 0, 0, true, false, timestamp++);
|
|
|
|
Test::tabletToolButtonPressed(BTN_STYLUS, timestamp++);
|
|
|
|
QVERIFY(keyChangedSpy.wait());
|
|
QCOMPARE(keyChangedSpy.count(), 1);
|
|
QCOMPARE(keyChangedSpy.at(0).at(0), KEY_A);
|
|
|
|
Test::tabletToolButtonReleased(BTN_STYLUS, timestamp++);
|
|
}
|
|
|
|
WAYLANDTEST_MAIN(TestButtonRebind)
|
|
#include "buttonrebind_test.moc"
|