File indexing completed on 2024-04-14 03:56:52

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.h"
0008 #include <QTest>
0009 #include <private/qtx11extras_p.h>
0010 
0011 #include <X11/keysym.h>
0012 #include <xcb/xcb_keysyms.h>
0013 
0014 class KKeyServerTest : public QObject
0015 {
0016     Q_OBJECT
0017 private Q_SLOTS:
0018 
0019     void initTestCase()
0020     {
0021         m_keySymbols = xcb_key_symbols_alloc(QX11Info::connection());
0022 
0023         // This makes me wonder why we have KKeyServer::modXShift :-)
0024         QCOMPARE(XCB_MOD_MASK_SHIFT, xcb_mod_mask_t(KKeyServer::modXShift()));
0025     }
0026 
0027     void cleanupTestCase()
0028     {
0029         if (m_keySymbols) {
0030             xcb_key_symbols_free(m_keySymbols);
0031         }
0032     }
0033 
0034     void keyQtToSymX_data()
0035     {
0036         QTest::addColumn<int>("keyQt");
0037         QTest::addColumn<uint>("modX");
0038         QTest::addColumn<uint>("additionalState"); // set to XCB_MOD_MASK_SHIFT if shift would indeed be pressed for this shortcut
0039         QTest::addColumn<int>("keySymX");
0040 
0041         const uint numLock = KKeyServer::modXNumLock();
0042 
0043         // clang-format off
0044         // Before adding any testcase below, check what `kcmshell5 keys` records, to make sure it matches
0045         QTest::newRow("a") << int(Qt::Key_A) << uint(0) << numLock << XK_A;
0046         QTest::newRow("CTRL_F1") << QKeyCombination(Qt::ControlModifier|Qt::Key_F1).toCombined() << KKeyServer::modXCtrl() << numLock << XK_F1;
0047         QTest::newRow("CTRL_1") << QKeyCombination(Qt::ControlModifier|Qt::Key_1).toCombined() << KKeyServer::modXCtrl() << numLock << XK_1;
0048         QTest::newRow("CTRL_keypad_1") << QKeyCombination(Qt::ControlModifier|Qt::KeypadModifier|Qt::Key_1).toCombined() << KKeyServer::modXCtrl() << numLock << XK_KP_1;
0049         QTest::newRow("CTRL_keypad_slash") << QKeyCombination(Qt::ControlModifier|Qt::KeypadModifier|Qt::Key_Slash).toCombined() << KKeyServer::modXCtrl() << numLock << XK_KP_Divide;
0050         QTest::newRow("CTRL_SHIFT_keypad_end") << QKeyCombination(Qt::ControlModifier|Qt::ShiftModifier|Qt::KeypadModifier|Qt::Key_End).toCombined() << (KKeyServer::modXCtrl()|KKeyServer::modXShift()) << numLock << XK_KP_End;
0051         QTest::newRow("CTRL_keypad_end_no_numlock") << QKeyCombination(Qt::ControlModifier|Qt::KeypadModifier|Qt::Key_End).toCombined() << (KKeyServer::modXCtrl()) << uint(0) << XK_KP_End;
0052         QTest::newRow("CTRL_ampersand") << QKeyCombination(Qt::ControlModifier|Qt::Key_Ampersand).toCombined() << KKeyServer::modXCtrl() << uint(XCB_MOD_MASK_SHIFT|numLock) << XK_ampersand;
0053         QTest::newRow("ALT_SHIFT_right") << QKeyCombination(Qt::AltModifier|Qt::ShiftModifier|Qt::Key_Right).toCombined() << (KKeyServer::modXAlt() | KKeyServer::modXShift()) << numLock << XK_Right;
0054         QTest::newRow("CTRL_SHIFT_right") << QKeyCombination(Qt::ControlModifier|Qt::ShiftModifier|Qt::Key_Right).toCombined() << (KKeyServer::modXCtrl() | KKeyServer::modXShift()) << numLock << XK_Right;
0055         QTest::newRow("META_SHIFT_print") << QKeyCombination(Qt::MetaModifier|Qt::ShiftModifier|Qt::Key_Print).toCombined() << (KKeyServer::modXMeta() | KKeyServer::modXShift()) << numLock << XK_Print;
0056         QTest::newRow("ALT_Tab") << QKeyCombination(Qt::AltModifier|Qt::Key_Tab).toCombined() << (KKeyServer::modXAlt()) << numLock << XK_Tab;
0057         QTest::newRow("ALT_Shift_Tab") << QKeyCombination(Qt::AltModifier|Qt::ShiftModifier|Qt::Key_Tab).toCombined() << (KKeyServer::modXAlt() | KKeyServer::modXShift()) << numLock << XK_Tab;
0058         // clang-format on
0059     }
0060 
0061     void keyQtToSymX()
0062     {
0063         QFETCH(int, keyQt);
0064         QFETCH(uint, modX);
0065         QFETCH(int, keySymX);
0066         int sym;
0067         QVERIFY(KKeyServer::keyQtToSymX(keyQt, &sym));
0068         QCOMPARE(QString::number(sym, 16), QString::number(keySymX, 16));
0069         uint mod;
0070         QVERIFY(KKeyServer::keyQtToModX(keyQt, &mod));
0071         QCOMPARE(mod, modX);
0072     }
0073 
0074     void symXToKeyQt_data()
0075     {
0076         keyQtToSymX_data();
0077     }
0078 
0079     void symXToKeyQt()
0080     {
0081         QFETCH(int, keyQt);
0082         QFETCH(uint, modX);
0083         QFETCH(int, keySymX);
0084         int keyCodeQt;
0085 
0086         // qDebug() << "modX=" << modX << "keySymX=0x" << QString::number(keySymX, 16) << "keyQt=0x" << QString::number(keyQt, 16);
0087 
0088         QVERIFY(KKeyServer::symXModXToKeyQt(keySymX, modX, &keyCodeQt));
0089         QCOMPARE(keyCodeQt, keyQt);
0090     }
0091 
0092     void keyQtToSymXsCalculatorKey()
0093     {
0094         // Should return both XF86XK_Calculator and XF86XK_Calculater
0095         QList<int> keyCodes = KKeyServer::keyQtToSymXs(Qt::Key_Calculator);
0096         QVERIFY(keyCodes.size() == 2);
0097         QVERIFY(keyCodes[0] != keyCodes[1]);
0098         int keyCodeQt;
0099 
0100         QVERIFY(KKeyServer::symXModXToKeyQt(keyCodes[0], 0, &keyCodeQt));
0101         QCOMPARE(keyCodeQt, int(Qt::Key_Calculator));
0102         QVERIFY(KKeyServer::symXModXToKeyQt(keyCodes[1], 0, &keyCodeQt));
0103         QCOMPARE(keyCodeQt, int(Qt::Key_Calculator));
0104     }
0105 
0106     void keyQtToSymXs_data()
0107     {
0108         keyQtToSymX_data();
0109     }
0110 
0111     void keyQtToSymXs()
0112     {
0113         QFETCH(int, keyQt);
0114         QFETCH(uint, modX);
0115         QFETCH(int, keySymX);
0116         QList<int> syms = KKeyServer::keyQtToSymXs(keyQt);
0117         QVERIFY(syms.size() > 0);
0118         QCOMPARE(QString::number(syms[0], 16), QString::number(keySymX, 16));
0119         uint mod;
0120         QVERIFY(KKeyServer::keyQtToModX(keyQt, &mod));
0121         QCOMPARE(mod, modX);
0122     }
0123 
0124     void decodeXcbEvent_data()
0125     {
0126         keyQtToSymX_data();
0127     }
0128 
0129     void decodeXcbEvent()
0130     {
0131         QFETCH(int, keyQt);
0132         QFETCH(uint, modX);
0133         QFETCH(uint, additionalState);
0134         QFETCH(int, keySymX);
0135 
0136         xcb_keycode_t *keyCodes = xcb_key_symbols_get_keycode(m_keySymbols, keySymX);
0137         QVERIFY(keyCodes);
0138         const xcb_keycode_t keyCodeX = keyCodes[0];
0139         QVERIFY(keyCodeX != XCB_NO_SYMBOL);
0140         free(keyCodes);
0141 
0142         xcb_key_press_event_t event{XCB_KEY_PRESS,
0143                                     keyCodeX,
0144                                     0,
0145                                     0 /*time*/,
0146                                     0 /*root*/,
0147                                     0 /*event*/,
0148                                     0 /*child*/,
0149                                     0 /*root_x*/,
0150                                     0 /*root_y*/,
0151                                     0 /*event_x*/,
0152                                     0 /*event_y*/,
0153                                     uint16_t(modX | additionalState),
0154                                     0 /*same_screen*/,
0155                                     0 /*pad0*/};
0156 
0157         int decodedKeyQt;
0158         const bool ok = KKeyServer::xcbKeyPressEventToQt(&event, &decodedKeyQt);
0159         QVERIFY(ok);
0160         if (decodedKeyQt != keyQt) {
0161             qDebug() << "given modX=" << modX << "keySymX=0x" << QString::number(keySymX, 16) << "I expected keyQt=0x" << QString::number(keyQt, 16)
0162                      << QKeySequence(keyQt).toString() << "got" << QString::number(decodedKeyQt, 16) << QKeySequence(decodedKeyQt).toString();
0163         }
0164         QCOMPARE(decodedKeyQt, keyQt);
0165     }
0166 
0167 private:
0168     xcb_key_symbols_t *m_keySymbols;
0169 };
0170 
0171 QTEST_MAIN(KKeyServerTest)
0172 
0173 #include "kkeyserver_x11_unittest.moc"