File indexing completed on 2024-11-10 04:56:02
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2018 Martin Flöser <mgraesslin@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "kwin_wayland_test.h" 0010 0011 #include "input.h" 0012 #include "keyboard_input.h" 0013 #include "pointer_input.h" 0014 #include "screenedge.h" 0015 #include "wayland_server.h" 0016 #include "workspace.h" 0017 0018 #include <KConfigGroup> 0019 #include <KGlobalAccel> 0020 0021 #include <QAction> 0022 #include <QDBusConnection> 0023 0024 #include <linux/input.h> 0025 0026 using namespace KWin; 0027 0028 static const QString s_socketName = QStringLiteral("wayland_test_kwin_no_global_shortcuts-0"); 0029 static const QString s_serviceName = QStringLiteral("org.kde.KWin.Test.ModifierOnlyShortcut"); 0030 static const QString s_path = QStringLiteral("/Test"); 0031 0032 Q_DECLARE_METATYPE(KWin::ElectricBorder) 0033 0034 /** 0035 * This test verifies the NoGlobalShortcuts initialization flag 0036 */ 0037 class NoGlobalShortcutsTest : public QObject 0038 { 0039 Q_OBJECT 0040 private Q_SLOTS: 0041 void initTestCase(); 0042 void init(); 0043 void cleanup(); 0044 0045 void testTrigger_data(); 0046 void testTrigger(); 0047 void testKGlobalAccel(); 0048 void testPointerShortcut(); 0049 void testAxisShortcut_data(); 0050 void testAxisShortcut(); 0051 void testScreenEdge(); 0052 }; 0053 0054 class Target : public QObject 0055 { 0056 Q_OBJECT 0057 Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.Test.ModifierOnlyShortcut") 0058 0059 public: 0060 Target(); 0061 ~Target() override; 0062 0063 public Q_SLOTS: 0064 Q_SCRIPTABLE void shortcut(); 0065 0066 Q_SIGNALS: 0067 void shortcutTriggered(); 0068 }; 0069 0070 Target::Target() 0071 : QObject() 0072 { 0073 QDBusConnection::sessionBus().registerService(s_serviceName); 0074 QDBusConnection::sessionBus().registerObject(s_path, s_serviceName, this, QDBusConnection::ExportScriptableSlots); 0075 } 0076 0077 Target::~Target() 0078 { 0079 QDBusConnection::sessionBus().unregisterObject(s_path); 0080 QDBusConnection::sessionBus().unregisterService(s_serviceName); 0081 } 0082 0083 void Target::shortcut() 0084 { 0085 Q_EMIT shortcutTriggered(); 0086 } 0087 0088 void NoGlobalShortcutsTest::initTestCase() 0089 { 0090 qRegisterMetaType<KWin::ElectricBorder>("ElectricBorder"); 0091 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); 0092 QVERIFY(waylandServer()->init(s_socketName, KWin::WaylandServer::InitializationFlag::NoGlobalShortcuts)); 0093 Test::setOutputConfig({ 0094 QRect(0, 0, 1280, 1024), 0095 QRect(1280, 0, 1280, 1024), 0096 }); 0097 0098 kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig)); 0099 qputenv("KWIN_XKB_DEFAULT_KEYMAP", "1"); 0100 qputenv("XKB_DEFAULT_RULES", "evdev"); 0101 0102 kwinApp()->start(); 0103 QVERIFY(applicationStartedSpy.wait()); 0104 } 0105 0106 void NoGlobalShortcutsTest::init() 0107 { 0108 workspace()->setActiveOutput(QPoint(640, 512)); 0109 KWin::input()->pointer()->warp(QPoint(640, 512)); 0110 } 0111 0112 void NoGlobalShortcutsTest::cleanup() 0113 { 0114 } 0115 0116 void NoGlobalShortcutsTest::testTrigger_data() 0117 { 0118 QTest::addColumn<QStringList>("metaConfig"); 0119 QTest::addColumn<QStringList>("altConfig"); 0120 QTest::addColumn<QStringList>("controlConfig"); 0121 QTest::addColumn<QStringList>("shiftConfig"); 0122 QTest::addColumn<int>("modifier"); 0123 QTest::addColumn<QList<int>>("nonTriggeringMods"); 0124 0125 const QStringList trigger = QStringList{s_serviceName, s_path, s_serviceName, QStringLiteral("shortcut")}; 0126 const QStringList e = QStringList(); 0127 0128 QTest::newRow("leftMeta") << trigger << e << e << e << KEY_LEFTMETA << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; 0129 QTest::newRow("rightMeta") << trigger << e << e << e << KEY_RIGHTMETA << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; 0130 QTest::newRow("leftAlt") << e << trigger << e << e << KEY_LEFTALT << QList<int>{KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; 0131 QTest::newRow("rightAlt") << e << trigger << e << e << KEY_RIGHTALT << QList<int>{KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; 0132 QTest::newRow("leftControl") << e << e << trigger << e << KEY_LEFTCTRL << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; 0133 QTest::newRow("rightControl") << e << e << trigger << e << KEY_RIGHTCTRL << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_LEFTSHIFT, KEY_RIGHTSHIFT}; 0134 QTest::newRow("leftShift") << e << e << e << trigger << KEY_LEFTSHIFT << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, KEY_RIGHTMETA}; 0135 QTest::newRow("rightShift") << e << e << e << trigger << KEY_RIGHTSHIFT << QList<int>{KEY_LEFTALT, KEY_RIGHTALT, KEY_LEFTCTRL, KEY_RIGHTCTRL, KEY_LEFTMETA, KEY_RIGHTMETA}; 0136 } 0137 0138 void NoGlobalShortcutsTest::testTrigger() 0139 { 0140 // test based on ModifierOnlyShortcutTest::testTrigger 0141 Target target; 0142 QSignalSpy triggeredSpy(&target, &Target::shortcutTriggered); 0143 0144 KConfigGroup group = kwinApp()->config()->group(QStringLiteral("ModifierOnlyShortcuts")); 0145 QFETCH(QStringList, metaConfig); 0146 QFETCH(QStringList, altConfig); 0147 QFETCH(QStringList, shiftConfig); 0148 QFETCH(QStringList, controlConfig); 0149 group.writeEntry("Meta", metaConfig); 0150 group.writeEntry("Alt", altConfig); 0151 group.writeEntry("Shift", shiftConfig); 0152 group.writeEntry("Control", controlConfig); 0153 group.sync(); 0154 workspace()->slotReconfigure(); 0155 0156 // configured shortcut should trigger 0157 quint32 timestamp = 1; 0158 QFETCH(int, modifier); 0159 Test::keyboardKeyPressed(modifier, timestamp++); 0160 Test::keyboardKeyReleased(modifier, timestamp++); 0161 QCOMPARE(triggeredSpy.count(), 0); 0162 0163 // the other shortcuts should not trigger 0164 QFETCH(QList<int>, nonTriggeringMods); 0165 for (auto it = nonTriggeringMods.constBegin(), end = nonTriggeringMods.constEnd(); it != end; it++) { 0166 Test::keyboardKeyPressed(*it, timestamp++); 0167 Test::keyboardKeyReleased(*it, timestamp++); 0168 QCOMPARE(triggeredSpy.count(), 0); 0169 } 0170 } 0171 0172 void NoGlobalShortcutsTest::testKGlobalAccel() 0173 { 0174 std::unique_ptr<QAction> action(new QAction(nullptr)); 0175 action->setProperty("componentName", QStringLiteral("kwin")); 0176 action->setObjectName(QStringLiteral("globalshortcuts-test-meta-shift-w")); 0177 QSignalSpy triggeredSpy(action.get(), &QAction::triggered); 0178 KGlobalAccel::self()->setShortcut(action.get(), QList<QKeySequence>{Qt::META | Qt::SHIFT | Qt::Key_W}, KGlobalAccel::NoAutoloading); 0179 0180 // press meta+shift+w 0181 quint32 timestamp = 0; 0182 Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++); 0183 QCOMPARE(input()->keyboardModifiers(), Qt::MetaModifier); 0184 Test::keyboardKeyPressed(KEY_LEFTSHIFT, timestamp++); 0185 QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier | Qt::MetaModifier); 0186 Test::keyboardKeyPressed(KEY_W, timestamp++); 0187 Test::keyboardKeyReleased(KEY_W, timestamp++); 0188 0189 // release meta+shift 0190 Test::keyboardKeyReleased(KEY_LEFTSHIFT, timestamp++); 0191 Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++); 0192 0193 QVERIFY(!triggeredSpy.wait(100)); 0194 QCOMPARE(triggeredSpy.count(), 0); 0195 } 0196 0197 void NoGlobalShortcutsTest::testPointerShortcut() 0198 { 0199 // based on LockScreenTest::testPointerShortcut 0200 std::unique_ptr<QAction> action(new QAction(nullptr)); 0201 QSignalSpy actionSpy(action.get(), &QAction::triggered); 0202 input()->registerPointerShortcut(Qt::MetaModifier, Qt::LeftButton, action.get()); 0203 0204 // try to trigger the shortcut 0205 quint32 timestamp = 1; 0206 Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++); 0207 Test::pointerButtonPressed(BTN_LEFT, timestamp++); 0208 QCoreApplication::instance()->processEvents(); 0209 QCOMPARE(actionSpy.count(), 0); 0210 Test::pointerButtonReleased(BTN_LEFT, timestamp++); 0211 Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++); 0212 QCoreApplication::instance()->processEvents(); 0213 QCOMPARE(actionSpy.count(), 0); 0214 } 0215 0216 void NoGlobalShortcutsTest::testAxisShortcut_data() 0217 { 0218 QTest::addColumn<Qt::Orientation>("direction"); 0219 QTest::addColumn<int>("sign"); 0220 0221 QTest::newRow("up") << Qt::Vertical << 1; 0222 QTest::newRow("down") << Qt::Vertical << -1; 0223 QTest::newRow("left") << Qt::Horizontal << 1; 0224 QTest::newRow("right") << Qt::Horizontal << -1; 0225 } 0226 0227 void NoGlobalShortcutsTest::testAxisShortcut() 0228 { 0229 // based on LockScreenTest::testAxisShortcut 0230 std::unique_ptr<QAction> action(new QAction(nullptr)); 0231 QSignalSpy actionSpy(action.get(), &QAction::triggered); 0232 QFETCH(Qt::Orientation, direction); 0233 QFETCH(int, sign); 0234 PointerAxisDirection axisDirection = PointerAxisUp; 0235 if (direction == Qt::Vertical) { 0236 axisDirection = sign > 0 ? PointerAxisUp : PointerAxisDown; 0237 } else { 0238 axisDirection = sign > 0 ? PointerAxisLeft : PointerAxisRight; 0239 } 0240 input()->registerAxisShortcut(Qt::MetaModifier, axisDirection, action.get()); 0241 0242 // try to trigger the shortcut 0243 quint32 timestamp = 1; 0244 Test::keyboardKeyPressed(KEY_LEFTMETA, timestamp++); 0245 if (direction == Qt::Vertical) { 0246 Test::pointerAxisVertical(sign * 5.0, timestamp++); 0247 } else { 0248 Test::pointerAxisHorizontal(sign * 5.0, timestamp++); 0249 } 0250 QCoreApplication::instance()->processEvents(); 0251 QCOMPARE(actionSpy.count(), 0); 0252 Test::keyboardKeyReleased(KEY_LEFTMETA, timestamp++); 0253 QCoreApplication::instance()->processEvents(); 0254 QCOMPARE(actionSpy.count(), 0); 0255 } 0256 0257 void NoGlobalShortcutsTest::testScreenEdge() 0258 { 0259 // based on LockScreenTest::testScreenEdge 0260 QSignalSpy screenEdgeSpy(workspace()->screenEdges(), &ScreenEdges::approaching); 0261 QCOMPARE(screenEdgeSpy.count(), 0); 0262 0263 quint32 timestamp = 1; 0264 Test::pointerMotion({5, 5}, timestamp++); 0265 QCOMPARE(screenEdgeSpy.count(), 0); 0266 } 0267 0268 WAYLANDTEST_MAIN(NoGlobalShortcutsTest) 0269 #include "no_global_shortcuts_test.moc"