File indexing completed on 2024-04-21 15:05:27

0001 /*  This file is part of the KDE libraries
0002     SPDX-FileCopyrightText: 2017 David Faure <faure@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "kkeyserver_x11.h"
0008 #include <QTest>
0009 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0010 #include <private/qtx11extras_p.h>
0011 #else
0012 #include <QX11Info>
0013 #endif
0014 
0015 #include <X11/keysym.h>
0016 #include <xcb/xcb_keysyms.h>
0017 
0018 class KKeyServerTest : public QObject
0019 {
0020     Q_OBJECT
0021 private Q_SLOTS:
0022 
0023     void initTestCase()
0024     {
0025         m_keySymbols = xcb_key_symbols_alloc(QX11Info::connection());
0026 
0027         // This makes me wonder why we have KKeyServer::modXShift :-)
0028         QCOMPARE(XCB_MOD_MASK_SHIFT, xcb_mod_mask_t(KKeyServer::modXShift()));
0029     }
0030 
0031     void cleanupTestCase()
0032     {
0033         if (m_keySymbols) {
0034             xcb_key_symbols_free(m_keySymbols);
0035         }
0036     }
0037 
0038     void keyQtToSymX_data()
0039     {
0040         QTest::addColumn<int>("keyQt");
0041         QTest::addColumn<uint>("modX");
0042         QTest::addColumn<uint>("additionalState"); // set to XCB_MOD_MASK_SHIFT if shift would indeed be pressed for this shortcut
0043         QTest::addColumn<int>("keySymX");
0044 
0045         const uint numLock = KKeyServer::modXNumLock();
0046 
0047         // clang-format off
0048         // Before adding any testcase below, check what `kcmshell5 keys` records, to make sure it matches
0049         QTest::newRow("a") << int(Qt::Key_A) << uint(0) << numLock << XK_A;
0050         QTest::newRow("CTRL_F1") << int(Qt::ControlModifier|Qt::Key_F1) << KKeyServer::modXCtrl() << numLock << XK_F1;
0051         QTest::newRow("CTRL_1") << int(Qt::ControlModifier|Qt::Key_1) << KKeyServer::modXCtrl() << numLock << XK_1;
0052         QTest::newRow("CTRL_keypad_1") << int(Qt::ControlModifier|Qt::KeypadModifier|Qt::Key_1) << KKeyServer::modXCtrl() << numLock << XK_KP_1;
0053         QTest::newRow("CTRL_keypad_slash") << int(Qt::ControlModifier|Qt::KeypadModifier|Qt::Key_Slash) << KKeyServer::modXCtrl() << numLock << XK_KP_Divide;
0054         QTest::newRow("CTRL_SHIFT_keypad_end") << int(Qt::ControlModifier|Qt::ShiftModifier|Qt::KeypadModifier|Qt::Key_End) << (KKeyServer::modXCtrl()|KKeyServer::modXShift()) << numLock << XK_KP_End;
0055         QTest::newRow("CTRL_keypad_end_no_numlock") << int(Qt::ControlModifier|Qt::KeypadModifier|Qt::Key_End) << (KKeyServer::modXCtrl()) << uint(0) << XK_KP_End;
0056         QTest::newRow("CTRL_ampersand") << int(Qt::ControlModifier|Qt::Key_Ampersand) << KKeyServer::modXCtrl() << uint(XCB_MOD_MASK_SHIFT|numLock) << XK_ampersand;
0057         QTest::newRow("ALT_SHIFT_right") << int(Qt::AltModifier|Qt::ShiftModifier|Qt::Key_Right) << (KKeyServer::modXAlt() | KKeyServer::modXShift()) << numLock << XK_Right;
0058         QTest::newRow("CTRL_SHIFT_right") << int(Qt::ControlModifier|Qt::ShiftModifier|Qt::Key_Right) << (KKeyServer::modXCtrl() | KKeyServer::modXShift()) << numLock << XK_Right;
0059         QTest::newRow("META_SHIFT_print") << int(Qt::MetaModifier|Qt::ShiftModifier|Qt::Key_Print) << (KKeyServer::modXMeta() | KKeyServer::modXShift()) << numLock << XK_Print;
0060         QTest::newRow("ALT_Tab") << int(Qt::AltModifier|Qt::Key_Tab) << (KKeyServer::modXAlt()) << numLock << XK_Tab;
0061         QTest::newRow("ALT_Shift_Tab") << int(Qt::AltModifier|Qt::ShiftModifier|Qt::Key_Tab) << (KKeyServer::modXAlt() | KKeyServer::modXShift()) << numLock << XK_Tab;
0062         // clang-format on
0063     }
0064 
0065     void keyQtToSymX()
0066     {
0067         QFETCH(int, keyQt);
0068         QFETCH(uint, modX);
0069         QFETCH(int, keySymX);
0070         int sym;
0071         QVERIFY(KKeyServer::keyQtToSymX(keyQt, &sym));
0072         QCOMPARE(QString::number(sym, 16), QString::number(keySymX, 16));
0073         uint mod;
0074         QVERIFY(KKeyServer::keyQtToModX(keyQt, &mod));
0075         QCOMPARE(mod, modX);
0076     }
0077 
0078     void symXToKeyQt_data()
0079     {
0080         keyQtToSymX_data();
0081     }
0082 
0083     void symXToKeyQt()
0084     {
0085         QFETCH(int, keyQt);
0086         QFETCH(uint, modX);
0087         QFETCH(int, keySymX);
0088         int keyCodeQt;
0089 
0090         // qDebug() << "modX=" << modX << "keySymX=0x" << QString::number(keySymX, 16) << "keyQt=0x" << QString::number(keyQt, 16);
0091 
0092         QVERIFY(KKeyServer::symXModXToKeyQt(keySymX, modX, &keyCodeQt));
0093         QCOMPARE(keyCodeQt, keyQt);
0094     }
0095 
0096     void decodeXcbEvent_data()
0097     {
0098         keyQtToSymX_data();
0099     }
0100 
0101     void decodeXcbEvent()
0102     {
0103         QFETCH(int, keyQt);
0104         QFETCH(uint, modX);
0105         QFETCH(uint, additionalState);
0106         QFETCH(int, keySymX);
0107 
0108         xcb_keycode_t *keyCodes = xcb_key_symbols_get_keycode(m_keySymbols, keySymX);
0109         QVERIFY(keyCodes);
0110         const xcb_keycode_t keyCodeX = keyCodes[0];
0111         QVERIFY(keyCodeX != XCB_NO_SYMBOL);
0112         free(keyCodes);
0113 
0114         xcb_key_press_event_t event{XCB_KEY_PRESS,
0115                                     keyCodeX,
0116                                     0,
0117                                     0 /*time*/,
0118                                     0 /*root*/,
0119                                     0 /*event*/,
0120                                     0 /*child*/,
0121                                     0 /*root_x*/,
0122                                     0 /*root_y*/,
0123                                     0 /*event_x*/,
0124                                     0 /*event_y*/,
0125                                     uint16_t(modX | additionalState),
0126                                     0 /*same_screen*/,
0127                                     0 /*pad0*/};
0128 
0129         int decodedKeyQt;
0130         const bool ok = KKeyServer::xcbKeyPressEventToQt(&event, &decodedKeyQt);
0131         QVERIFY(ok);
0132         if (decodedKeyQt != keyQt) {
0133             qDebug() << "given modX=" << modX << "keySymX=0x" << QString::number(keySymX, 16) << "I expected keyQt=0x" << QString::number(keyQt, 16)
0134                      << QKeySequence(keyQt).toString() << "got" << QString::number(decodedKeyQt, 16) << QKeySequence(decodedKeyQt).toString();
0135         }
0136         QCOMPARE(decodedKeyQt, keyQt);
0137     }
0138 
0139 private:
0140     xcb_key_symbols_t *m_keySymbols;
0141 };
0142 
0143 QTEST_MAIN(KKeyServerTest)
0144 
0145 #include "kkeyserver_x11_unittest.moc"