File indexing completed on 2024-11-10 04:56:06

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
0006     SPDX-FileCopyrightText: 2023 Nicolas Fella <nicolas.fella@gmx.de>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 #include "kwin_wayland_test.h"
0011 
0012 #include "keyboard_input.h"
0013 #include "pluginmanager.h"
0014 #include "pointer_input.h"
0015 #include "wayland_server.h"
0016 #include "window.h"
0017 #include "workspace.h"
0018 
0019 #include <KWayland/Client/keyboard.h>
0020 #include <KWayland/Client/seat.h>
0021 
0022 #include <linux/input.h>
0023 
0024 namespace KWin
0025 {
0026 
0027 static const QString s_socketName = QStringLiteral("wayland_test_kwin_sticky_keys-0");
0028 
0029 class StickyKeysTest : public QObject
0030 {
0031     Q_OBJECT
0032 private Q_SLOTS:
0033     void initTestCase();
0034     void init();
0035     void cleanup();
0036     void testStick();
0037     void testLock();
0038 };
0039 
0040 void StickyKeysTest::initTestCase()
0041 {
0042     KConfig kaccessConfig("kaccessrc");
0043     kaccessConfig.group(QStringLiteral("Keyboard")).writeEntry("StickyKeys", true);
0044     kaccessConfig.sync();
0045 
0046     qRegisterMetaType<KWin::Window *>();
0047     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0048     QVERIFY(waylandServer()->init(s_socketName));
0049     Test::setOutputConfig({
0050         QRect(0, 0, 1280, 1024),
0051         QRect(1280, 0, 1280, 1024),
0052     });
0053 
0054     qputenv("XKB_DEFAULT_RULES", "evdev");
0055 
0056     kwinApp()->start();
0057     QVERIFY(applicationStartedSpy.wait());
0058 }
0059 
0060 void StickyKeysTest::init()
0061 {
0062     QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat));
0063     QVERIFY(Test::waitForWaylandKeyboard());
0064 }
0065 
0066 void StickyKeysTest::cleanup()
0067 {
0068     Test::destroyWaylandConnection();
0069 }
0070 
0071 void StickyKeysTest::testStick()
0072 {
0073     std::unique_ptr<KWayland::Client::Keyboard> keyboard(Test::waylandSeat()->createKeyboard());
0074 
0075     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0076     QVERIFY(surface != nullptr);
0077     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0078     QVERIFY(shellSurface != nullptr);
0079     Window *waylandWindow = Test::renderAndWaitForShown(surface.get(), QSize(10, 10), Qt::blue);
0080     QVERIFY(waylandWindow);
0081 
0082     QSignalSpy modifierSpy(keyboard.get(), &KWayland::Client::Keyboard::modifiersChanged);
0083     QVERIFY(modifierSpy.wait());
0084     modifierSpy.clear();
0085 
0086     quint32 timestamp = 0;
0087 
0088     // press Ctrl to latch it
0089     Test::keyboardKeyPressed(KEY_LEFTCTRL, ++timestamp);
0090     QVERIFY(modifierSpy.wait());
0091     // arguments are: quint32 depressed, quint32 latched, quint32 locked, quint32 group
0092     QCOMPARE(modifierSpy.first()[0], 4); // verify that Ctrl is depressed
0093     QCOMPARE(modifierSpy.first()[1], 4); // verify that Ctrl is latched
0094 
0095     modifierSpy.clear();
0096     // release Ctrl, the modified should still be latched
0097     Test::keyboardKeyReleased(KEY_LEFTCTRL, ++timestamp);
0098     QVERIFY(modifierSpy.wait());
0099     QCOMPARE(modifierSpy.first()[0], 0); // verify that Ctrl is not depressed
0100     QCOMPARE(modifierSpy.first()[1], 4); // verify that Ctrl is still latched
0101 
0102     // press and release a letter, this unlatches the modifier
0103     modifierSpy.clear();
0104     Test::keyboardKeyPressed(KEY_A, ++timestamp);
0105     QVERIFY(modifierSpy.wait());
0106     QCOMPARE(modifierSpy.first()[0], 0); // verify that Ctrl is not depressed
0107     QCOMPARE(modifierSpy.first()[1], 0); // verify that Ctrl is not latched any more
0108 
0109     Test::keyboardKeyReleased(KEY_A, ++timestamp);
0110 }
0111 
0112 void StickyKeysTest::testLock()
0113 {
0114     KConfig kaccessConfig("kaccessrc");
0115     kaccessConfig.group(QStringLiteral("Keyboard")).writeEntry("StickyKeysLatch", true);
0116     kaccessConfig.sync();
0117 
0118     // reload the plugin to pick up the new config
0119     kwinApp()->pluginManager()->unloadPlugin("StickyKeysPlugin");
0120     kwinApp()->pluginManager()->loadPlugin("StickyKeysPlugin");
0121 
0122     QVERIFY(Test::waylandSeat()->hasKeyboard());
0123     std::unique_ptr<KWayland::Client::Keyboard> keyboard(Test::waylandSeat()->createKeyboard());
0124 
0125     std::unique_ptr<KWayland::Client::Surface> surface(Test::createSurface());
0126     QVERIFY(surface != nullptr);
0127     std::unique_ptr<Test::XdgToplevel> shellSurface(Test::createXdgToplevelSurface(surface.get()));
0128     QVERIFY(shellSurface != nullptr);
0129     Window *waylandWindow = Test::renderAndWaitForShown(surface.get(), QSize(10, 10), Qt::blue);
0130     QVERIFY(waylandWindow);
0131     waylandWindow->move(QPoint(0, 0));
0132 
0133     QSignalSpy modifierSpy(keyboard.get(), &KWayland::Client::Keyboard::modifiersChanged);
0134     QVERIFY(modifierSpy.wait());
0135     modifierSpy.clear();
0136 
0137     quint32 timestamp = 0;
0138 
0139     // press Ctrl to latch it
0140     Test::keyboardKeyPressed(KEY_LEFTCTRL, ++timestamp);
0141     QVERIFY(modifierSpy.wait());
0142     // arguments are: quint32 depressed, quint32 latched, quint32 locked, quint32 group
0143     QCOMPARE(modifierSpy.first()[0], 4); // verify that Ctrl is depressed
0144     QCOMPARE(modifierSpy.first()[1], 4); // verify that Ctrl is latched
0145 
0146     modifierSpy.clear();
0147     // release Ctrl, the modified should still be latched
0148     Test::keyboardKeyReleased(KEY_LEFTCTRL, ++timestamp);
0149     QVERIFY(modifierSpy.wait());
0150     QCOMPARE(modifierSpy.first()[0], 0); // verify that Ctrl is not depressed
0151     QCOMPARE(modifierSpy.first()[1], 4); // verify that Ctrl is still latched
0152 
0153     // press Ctrl again to lock it
0154     modifierSpy.clear();
0155     Test::keyboardKeyPressed(KEY_LEFTCTRL, ++timestamp);
0156     QVERIFY(modifierSpy.wait());
0157     QCOMPARE(modifierSpy.first()[0], 4); // verify that Ctrl is depressed
0158     // TODO should it be latched?
0159     QCOMPARE(modifierSpy.first()[2], 4); // verify that Ctrl is locked
0160 
0161     // press and release a letter, this does not unlock the modifier
0162     modifierSpy.clear();
0163     Test::keyboardKeyPressed(KEY_A, ++timestamp);
0164     QVERIFY(!modifierSpy.wait(10));
0165 
0166     Test::keyboardKeyReleased(KEY_A, ++timestamp);
0167     QVERIFY(!modifierSpy.wait(10));
0168 
0169     // press Ctrl again to unlock it
0170     Test::keyboardKeyPressed(KEY_LEFTCTRL, ++timestamp);
0171     QVERIFY(modifierSpy.wait());
0172     QCOMPARE(modifierSpy.first()[0], 4); // verify that Ctrl is depressed
0173     QCOMPARE(modifierSpy.first()[2], 0); // verify that Ctrl is locked
0174 
0175     Test::keyboardKeyReleased(KEY_LEFTCTRL, ++timestamp);
0176 }
0177 }
0178 
0179 WAYLANDTEST_MAIN(KWin::StickyKeysTest)
0180 #include "sticky_keys_test.moc"