From 91f47c909237437e93ceb84326ae1eead0c3e3e7 Mon Sep 17 00:00:00 2001 From: Andrey Butirsky Date: Mon, 15 Mar 2021 20:34:41 +0300 Subject: [PATCH] fix global shortcuts for non-Latin symbols Re-use Qt's implementation of handling non-Latin layouts here For full ASCII range support (Alt+`, etc.) Qt needs to be patched still, see QTBUG-90611 BUG: 375518 --- CMakeLists.txt | 2 + autotests/CMakeLists.txt | 1 + .../integration/globalshortcuts_test.cpp | 83 +++++ autotests/test_xkb.cpp | 21 -- src/CMakeLists.txt | 1 + src/input.cpp | 9 +- src/keyboard_input.cpp | 5 +- src/xkb.cpp | 42 +-- src/xkb.h | 9 +- src/xkb_qt_mapping.h | 312 ------------------ 10 files changed, 122 insertions(+), 363 deletions(-) delete mode 100644 src/xkb_qt_mapping.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0969bc1148..d8377a2632 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,6 +189,8 @@ set_package_properties(XKB PROPERTIES PURPOSE "Required for building KWin with Wayland support" ) +find_package(Qt5XkbCommonSupport REQUIRED) + find_package(Libinput 1.9) set_package_properties(Libinput PROPERTIES TYPE REQUIRED PURPOSE "Required for input handling on Wayland.") diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index f859094ff3..f6d7410d2b 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -366,6 +366,7 @@ target_link_libraries(testXkb KF5::WindowSystem XKB::XKB + Qt5::XkbCommonSupportPrivate ) add_test(NAME kwin-testXkb COMMAND testXkb) ecm_mark_as_test(testXkb) diff --git a/autotests/integration/globalshortcuts_test.cpp b/autotests/integration/globalshortcuts_test.cpp index dd9765d508..b5f2405136 100644 --- a/autotests/integration/globalshortcuts_test.cpp +++ b/autotests/integration/globalshortcuts_test.cpp @@ -40,6 +40,8 @@ private Q_SLOTS: void init(); void cleanup(); + void testNonLatinLayout_data(); + void testNonLatinLayout(); void testConsumedShift(); void testRepeatedTrigger(); void testUserActionsMenu(); @@ -62,6 +64,7 @@ void GlobalShortcutsTest::initTestCase() kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig)); qputenv("KWIN_XKB_DEFAULT_KEYMAP", "1"); qputenv("XKB_DEFAULT_RULES", "evdev"); + qputenv("XKB_DEFAULT_LAYOUT", "us,ru"); kwinApp()->start(); QVERIFY(applicationStartedSpy.wait()); @@ -80,6 +83,84 @@ void GlobalShortcutsTest::cleanup() Test::destroyWaylandConnection(); } +Q_DECLARE_METATYPE(Qt::Modifier) + +void GlobalShortcutsTest::testNonLatinLayout_data() +{ + QTest::addColumn("modifierKey"); + QTest::addColumn("qtModifier"); + QTest::addColumn("key"); + QTest::addColumn("qtKey"); + + for (const auto &modifier : + QVector> { + {KEY_LEFTCTRL, Qt::CTRL}, + {KEY_LEFTALT, Qt::ALT}, + {KEY_LEFTSHIFT, Qt::SHIFT}, + {KEY_LEFTMETA, Qt::META}, + } ) + { + for (const auto &key : + QVector> { + + // Tab is example of a key usually the same on different layouts, check it first + {KEY_TAB, Qt::Key_Tab}, + + // Then check a key with a Latin letter. + // The symbol will probably be differ on non-Latin layout. + // On Russian layout, "w" key has a cyrillic letter "ц" + {KEY_W, Qt::Key_W}, + + #if QT_VERSION_MAJOR > 5 // since Qt 5 LTS is frozen + // More common case with any Latin1 symbol keys, including punctuation, should work also. + // "`" key has a "ё" letter on Russian layout + // FIXME: QTBUG-90611 + {KEY_GRAVE, Qt::Key_QuoteLeft}, + #endif + } ) + { + QTest::newRow(QKeySequence(modifier.second + key.second).toString().toLatin1().constData()) + << modifier.first << modifier.second << key.first << key.second; + } + } +} + +void GlobalShortcutsTest::testNonLatinLayout() +{ + // Shortcuts on non-Latin layouts should still work, see BUG 375518 + auto xkb = input()->keyboard()->xkb(); + xkb->switchToLayout(1); + QCOMPARE(xkb->layoutName(), QStringLiteral("Russian")); + + QFETCH(int, modifierKey); + QFETCH(Qt::Modifier, qtModifier); + QFETCH(int, key); + QFETCH(Qt::Key, qtKey); + + const QKeySequence seq(qtModifier + qtKey); + + QScopedPointer action(new QAction(nullptr)); + action->setProperty("componentName", QStringLiteral(KWIN_NAME)); + action->setObjectName("globalshortcuts-test-non-latin-layout"); + + QSignalSpy triggeredSpy(action.data(), &QAction::triggered); + QVERIFY(triggeredSpy.isValid()); + + KGlobalAccel::self()->stealShortcutSystemwide(seq); + KGlobalAccel::self()->setShortcut(action.data(), {seq}, KGlobalAccel::NoAutoloading); + input()->registerShortcut(seq, action.data()); + + quint32 timestamp = 0; + kwinApp()->platform()->keyboardKeyPressed(modifierKey, timestamp++); + QCOMPARE(input()->keyboardModifiers(), qtModifier); + kwinApp()->platform()->keyboardKeyPressed(key, timestamp++); + + kwinApp()->platform()->keyboardKeyReleased(key, timestamp++); + kwinApp()->platform()->keyboardKeyReleased(modifierKey, timestamp++); + + QTRY_COMPARE_WITH_TIMEOUT(triggeredSpy.count(), 1, 100); +} + void GlobalShortcutsTest::testConsumedShift() { // this test verifies that a shortcut with a consumed shift modifier triggers @@ -327,6 +408,8 @@ void GlobalShortcutsTest::testWaylandClientShortcut() void GlobalShortcutsTest::testSetupWindowShortcut() { + // QTBUG-62102 + QScopedPointer surface(Test::createSurface()); QScopedPointer shellSurface(Test::createXdgShellStableSurface(surface.data())); auto client = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue); diff --git a/autotests/test_xkb.cpp b/autotests/test_xkb.cpp index da9c24ca9e..c25ef1971e 100644 --- a/autotests/test_xkb.cpp +++ b/autotests/test_xkb.cpp @@ -19,8 +19,6 @@ class XkbTest : public QObject private Q_SLOTS: void testToQtKey_data(); void testToQtKey(); - void testFromQtKey_data(); - void testFromQtKey(); }; // from kwindowsystem/src/platforms/xcb/kkeyserver.cpp @@ -480,24 +478,5 @@ void XkbTest::testToQtKey() QTEST(xkb.toQtKey(keySym), "qt"); } -void XkbTest::testFromQtKey_data() -{ - QTest::addColumn("qt"); - QTest::addColumn("keySym"); - QTest::addColumn("modifiers"); - for (std::size_t i = 0; i < sizeof(g_rgQtToSymX) / sizeof(TransKey); i++) { - const QByteArray row = QByteArray::number(g_rgQtToSymX[i].keySymX, 16); - QTest::newRow(row.constData()) << g_rgQtToSymX[i].keySymQt << g_rgQtToSymX[i].keySymX << g_rgQtToSymX[i].modifiers; - } -} - -void XkbTest::testFromQtKey() -{ - Xkb xkb; - QFETCH(Qt::Key, qt); - QFETCH(Qt::KeyboardModifiers, modifiers); - QTEST(xkb.fromQtKey(qt, modifiers), "keySym"); -} - QTEST_MAIN(XkbTest) #include "test_xkb.moc" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d55d1ebd4f..c890aac818 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -227,6 +227,7 @@ target_link_libraries(kwin Libinput::Libinput UDev::UDev XKB::XKB + Qt5::XkbCommonSupportPrivate epoxy::epoxy Threads::Threads diff --git a/src/input.cpp b/src/input.cpp index 3304cb634e..36a6292be0 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -990,11 +990,10 @@ class InternalWindowEventFilter : public InputEventFilter { return false; } auto xkb = input()->keyboard()->xkb(); - Qt::Key key = xkb->toQtKey(xkb->toKeysym(event->nativeScanCode())); - if (key == Qt::Key_Super_L || key == Qt::Key_Super_R) { - // workaround for QTBUG-62102 - key = Qt::Key_Meta; - } + Qt::Key key = xkb->toQtKey( xkb->toKeysym(event->nativeScanCode()), + event->nativeScanCode(), + Qt::KeyboardModifiers(), + true /* workaround for QTBUG-62102 */ ); QKeyEvent internalEvent(event->type(), key, event->modifiers(), event->nativeScanCode(), event->nativeVirtualKey(), event->nativeModifiers(), event->text()); diff --git a/src/keyboard_input.cpp b/src/keyboard_input.cpp index 05d1c738dd..3f7d717670 100644 --- a/src/keyboard_input.cpp +++ b/src/keyboard_input.cpp @@ -202,8 +202,9 @@ void KeyboardInputRedirection::processKey(uint32_t key, InputRedirection::Keyboa } const xkb_keysym_t keySym = m_xkb->currentKeysym(); + const Qt::KeyboardModifiers globalShortcutsModifiers = m_xkb->modifiersRelevantForGlobalShortcuts(key); KeyEvent event(type, - m_xkb->toQtKey(keySym), + m_xkb->toQtKey(keySym, key, globalShortcutsModifiers ? Qt::ControlModifier : Qt::KeyboardModifiers()), m_xkb->modifiers(), key, keySym, @@ -211,7 +212,7 @@ void KeyboardInputRedirection::processKey(uint32_t key, InputRedirection::Keyboa autoRepeat, time, device); - event.setModifiersRelevantForGlobalShortcuts(m_xkb->modifiersRelevantForGlobalShortcuts()); + event.setModifiersRelevantForGlobalShortcuts(globalShortcutsModifiers); m_input->processSpies(std::bind(&InputEventSpy::keyEvent, std::placeholders::_1, &event)); if (!m_inited) { diff --git a/src/xkb.cpp b/src/xkb.cpp index e7034a632c..ef8006f39a 100644 --- a/src/xkb.cpp +++ b/src/xkb.cpp @@ -7,7 +7,6 @@ SPDX-License-Identifier: GPL-2.0-or-later */ #include "xkb.h" -#include "xkb_qt_mapping.h" #include "utils.h" // frameworks #include @@ -17,6 +16,7 @@ // Qt #include #include +#include // xkbcommon #include #include @@ -353,7 +353,7 @@ void Xkb::updateModifiers() if (xkb_state_mod_index_is_active(m_state, m_metaModifier, XKB_STATE_MODS_EFFECTIVE) == 1) { mods |= Qt::MetaModifier; } - if (isKeypadKey(m_keysym)) { + if (m_keysym >= XKB_KEY_KP_Space && m_keysym <= XKB_KEY_KP_9) { mods |= Qt::KeypadModifier; } m_modifiers = mods; @@ -427,7 +427,7 @@ void Xkb::updateConsumedModifiers(uint32_t key) m_consumedModifiers = mods; } -Qt::KeyboardModifiers Xkb::modifiersRelevantForGlobalShortcuts() const +Qt::KeyboardModifiers Xkb::modifiersRelevantForGlobalShortcuts(uint32_t scanCode) const { if (!m_state) { return Qt::NoModifier; @@ -452,7 +452,7 @@ Qt::KeyboardModifiers Xkb::modifiersRelevantForGlobalShortcuts() const // in that case the shift should be removed from the consumed modifiers again // otherwise it would not be possible to trigger e.g. Shift+W as a shortcut // see BUG: 370341 - if (QChar(toQtKey(m_keysym)).isLetter()) { + if (QChar(toQtKey(m_keysym, scanCode, Qt::ControlModifier)).isLetter()) { consumedMods = Qt::KeyboardModifiers(); } } @@ -481,24 +481,28 @@ QString Xkb::toString(xkb_keysym_t keysym) return QString::fromUtf8(byteArray.constData()); } -Qt::Key Xkb::toQtKey(xkb_keysym_t keysym) const +Qt::Key Xkb::toQtKey(xkb_keysym_t keySym, + uint32_t scanCode, + Qt::KeyboardModifiers modifiers, + bool superAsMeta) const { - return xkbToQtKey(keysym); -} + // FIXME: passing superAsMeta doesn't have impact due to bug in the Qt function, so handle it below + Qt::Key qtKey = Qt::Key( QXkbCommon::keysymToQtKey(keySym, modifiers, m_state, scanCode + 8, superAsMeta) ); -xkb_keysym_t Xkb::fromQtKey(Qt::Key key, Qt::KeyboardModifiers mods) const -{ - return qtKeyToXkb(key, mods); -} - -xkb_keysym_t Xkb::fromKeyEvent(QKeyEvent *event) const -{ - xkb_keysym_t sym = xkb_keysym_from_name(event->text().toUtf8().constData(), XKB_KEYSYM_NO_FLAGS); - if (sym == XKB_KEY_NoSymbol) { - // mapping from text failed, try mapping through KKeyServer - sym = fromQtKey(Qt::Key(event->key() & ~Qt::KeyboardModifierMask), event->modifiers()); + // FIXME: workarounds for symbols currently wrong/not mappable via keysymToQtKey() + if (superAsMeta && (qtKey == Qt::Key_Super_L || qtKey == Qt::Key_Super_R)) { + // translate Super/Hyper keys to Meta if we're using them as the MetaModifier + qtKey = Qt::Key_Meta; + } else if (qtKey > 0xff && keySym <= 0xff) { + // XKB_KEY_mu, XKB_KEY_ydiaeresis go here + qtKey = Qt::Key(keySym); +#if QT_VERSION_MAJOR < 6 // since Qt 5 LTS is frozen + } else if (keySym == XKB_KEY_Sys_Req) { + // fixed in QTBUG-92087 + qtKey = Qt::Key_SysReq; +#endif } - return sym; + return qtKey; } bool Xkb::shouldKeyRepeat(quint32 key) const diff --git a/src/xkb.h b/src/xkb.h index 8e03e257f9..f82545bebe 100644 --- a/src/xkb.h +++ b/src/xkb.h @@ -54,11 +54,12 @@ public: return m_keysym; } QString toString(xkb_keysym_t keysym); - Qt::Key toQtKey(xkb_keysym_t keysym) const; - xkb_keysym_t fromQtKey(Qt::Key key, Qt::KeyboardModifiers mods) const; - xkb_keysym_t fromKeyEvent(QKeyEvent *event) const; + Qt::Key toQtKey(xkb_keysym_t keysym, + uint32_t scanCode = 0, + Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(), + bool superAsMeta = false) const; Qt::KeyboardModifiers modifiers() const; - Qt::KeyboardModifiers modifiersRelevantForGlobalShortcuts() const; + Qt::KeyboardModifiers modifiersRelevantForGlobalShortcuts(uint32_t scanCode = 0) const; bool shouldKeyRepeat(quint32 key) const; void switchToNextLayout(); diff --git a/src/xkb_qt_mapping.h b/src/xkb_qt_mapping.h deleted file mode 100644 index 48117142bd..0000000000 --- a/src/xkb_qt_mapping.h +++ /dev/null @@ -1,312 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2017 Martin Flöser - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#ifndef KWIN_XKB_QT_MAPPING_H -#define KWIN_XKB_QT_MAPPING_H - -#include - -#include -#include - -namespace KWin -{ - -// based on mapping in kwindowsystem/src/platforms/xcb/kkeyserver.cpp -// adjusted to XKB -static const std::map s_mapping{ - { XKB_KEY_Escape, Qt::Key_Escape }, - { XKB_KEY_Tab, Qt::Key_Tab }, - { XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab }, - { XKB_KEY_BackSpace, Qt::Key_Backspace }, - { XKB_KEY_Return, Qt::Key_Return }, - { XKB_KEY_Insert, Qt::Key_Insert }, - { XKB_KEY_Delete, Qt::Key_Delete }, - { XKB_KEY_Pause, Qt::Key_Pause }, - { XKB_KEY_Print, Qt::Key_Print }, - { XKB_KEY_Sys_Req, Qt::Key_SysReq }, - { XKB_KEY_Home, Qt::Key_Home }, - { XKB_KEY_End, Qt::Key_End }, - { XKB_KEY_Left, Qt::Key_Left }, - { XKB_KEY_Up, Qt::Key_Up }, - { XKB_KEY_Right, Qt::Key_Right }, - { XKB_KEY_Down, Qt::Key_Down }, - { XKB_KEY_Prior, Qt::Key_PageUp }, - { XKB_KEY_Next, Qt::Key_PageDown }, - { XKB_KEY_Caps_Lock, Qt::Key_CapsLock }, - { XKB_KEY_Num_Lock, Qt::Key_NumLock }, - { XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock }, - { XKB_KEY_F1, Qt::Key_F1 }, - { XKB_KEY_F2, Qt::Key_F2 }, - { XKB_KEY_F3, Qt::Key_F3 }, - { XKB_KEY_F4, Qt::Key_F4 }, - { XKB_KEY_F5, Qt::Key_F5 }, - { XKB_KEY_F6, Qt::Key_F6 }, - { XKB_KEY_F7, Qt::Key_F7 }, - { XKB_KEY_F8, Qt::Key_F8 }, - { XKB_KEY_F9, Qt::Key_F9 }, - { XKB_KEY_F10, Qt::Key_F10 }, - { XKB_KEY_F11, Qt::Key_F11 }, - { XKB_KEY_F12, Qt::Key_F12 }, - { XKB_KEY_F13, Qt::Key_F13 }, - { XKB_KEY_F14, Qt::Key_F14 }, - { XKB_KEY_F15, Qt::Key_F15 }, - { XKB_KEY_F16, Qt::Key_F16 }, - { XKB_KEY_F17, Qt::Key_F17 }, - { XKB_KEY_F18, Qt::Key_F18 }, - { XKB_KEY_F19, Qt::Key_F19 }, - { XKB_KEY_F20, Qt::Key_F20 }, - { XKB_KEY_F21, Qt::Key_F21 }, - { XKB_KEY_F22, Qt::Key_F22 }, - { XKB_KEY_F23, Qt::Key_F23 }, - { XKB_KEY_F24, Qt::Key_F24 }, - { XKB_KEY_F25, Qt::Key_F25 }, - { XKB_KEY_F26, Qt::Key_F26 }, - { XKB_KEY_F27, Qt::Key_F27 }, - { XKB_KEY_F28, Qt::Key_F28 }, - { XKB_KEY_F29, Qt::Key_F29 }, - { XKB_KEY_F30, Qt::Key_F30 }, - { XKB_KEY_F31, Qt::Key_F31 }, - { XKB_KEY_F32, Qt::Key_F32 }, - { XKB_KEY_F33, Qt::Key_F33 }, - { XKB_KEY_F34, Qt::Key_F34 }, - { XKB_KEY_F35, Qt::Key_F35 }, - { XKB_KEY_Super_L, Qt::Key_Super_L }, - { XKB_KEY_Super_R, Qt::Key_Super_R }, - { XKB_KEY_Menu, Qt::Key_Menu }, - { XKB_KEY_Hyper_L, Qt::Key_Hyper_L }, - { XKB_KEY_Hyper_R, Qt::Key_Hyper_R }, - { XKB_KEY_Help, Qt::Key_Help }, - { XKB_KEY_KP_Space, Qt::Key_Space }, - { XKB_KEY_KP_Tab, Qt::Key_Tab }, - { XKB_KEY_KP_Enter, Qt::Key_Enter }, - { XKB_KEY_KP_Home, Qt::Key_Home }, - { XKB_KEY_KP_Left, Qt::Key_Left }, - { XKB_KEY_KP_Up, Qt::Key_Up }, - { XKB_KEY_KP_Right, Qt::Key_Right }, - { XKB_KEY_KP_Down, Qt::Key_Down }, - { XKB_KEY_KP_Prior, Qt::Key_PageUp }, - { XKB_KEY_KP_Next, Qt::Key_PageDown }, - { XKB_KEY_KP_End, Qt::Key_End }, - { XKB_KEY_KP_Begin, Qt::Key_Clear }, - { XKB_KEY_KP_Insert, Qt::Key_Insert }, - { XKB_KEY_KP_Delete, Qt::Key_Delete }, - { XKB_KEY_KP_Equal, Qt::Key_Equal }, - { XKB_KEY_KP_Multiply, Qt::Key_Asterisk }, - { XKB_KEY_KP_Add, Qt::Key_Plus }, - { XKB_KEY_KP_Separator, Qt::Key_Comma }, - { XKB_KEY_KP_Subtract, Qt::Key_Minus }, - { XKB_KEY_KP_Decimal, Qt::Key_Period }, - { XKB_KEY_KP_Divide, Qt::Key_Slash }, - { XKB_KEY_XF86Back, Qt::Key_Back }, - { XKB_KEY_XF86Forward, Qt::Key_Forward }, - { XKB_KEY_XF86Stop, Qt::Key_Stop }, - { XKB_KEY_XF86Refresh, Qt::Key_Refresh }, - { XKB_KEY_XF86Favorites, Qt::Key_Favorites }, - { XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia }, - { XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl }, - { XKB_KEY_XF86HomePage, Qt::Key_HomePage }, - { XKB_KEY_XF86Search, Qt::Key_Search }, - { XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown }, - { XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute }, - { XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp }, - { XKB_KEY_XF86AudioPlay, Qt::Key_MediaPlay }, - { XKB_KEY_XF86AudioPause, Qt::Key_MediaPause }, - { XKB_KEY_XF86AudioStop, Qt::Key_MediaStop }, - { XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious }, - { XKB_KEY_XF86AudioNext, Qt::Key_MediaNext }, - { XKB_KEY_XF86AudioRecord, Qt::Key_MediaRecord }, - { XKB_KEY_XF86Mail, Qt::Key_LaunchMail }, - { XKB_KEY_XF86MyComputer, Qt::Key_Launch0 }, - { XKB_KEY_XF86Calculator, Qt::Key_Launch1 }, - { XKB_KEY_XF86Memo, Qt::Key_Memo }, - { XKB_KEY_XF86ToDoList, Qt::Key_ToDoList }, - { XKB_KEY_XF86Calendar, Qt::Key_Calendar }, - { XKB_KEY_XF86PowerDown, Qt::Key_PowerDown }, - { XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust }, - { XKB_KEY_XF86Standby, Qt::Key_Standby }, - { XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp }, - { XKB_KEY_XF86MonBrightnessDown, Qt::Key_MonBrightnessDown }, - { XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff }, - { XKB_KEY_XF86KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp }, - { XKB_KEY_XF86KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown }, - { XKB_KEY_XF86PowerOff, Qt::Key_PowerOff }, - { XKB_KEY_XF86WakeUp, Qt::Key_WakeUp }, - { XKB_KEY_XF86Eject, Qt::Key_Eject }, - { XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver }, - { XKB_KEY_XF86WWW, Qt::Key_WWW }, - { XKB_KEY_XF86Sleep, Qt::Key_Sleep }, - { XKB_KEY_XF86LightBulb, Qt::Key_LightBulb }, - { XKB_KEY_XF86Shop, Qt::Key_Shop }, - { XKB_KEY_XF86History, Qt::Key_History }, - { XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite }, - { XKB_KEY_XF86HotLinks, Qt::Key_HotLinks }, - { XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust }, - { XKB_KEY_XF86Finance, Qt::Key_Finance }, - { XKB_KEY_XF86Community, Qt::Key_Community }, - { XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind }, - { XKB_KEY_XF86BackForward, Qt::Key_BackForward }, - { XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft }, - { XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight }, - { XKB_KEY_XF86Book, Qt::Key_Book }, - { XKB_KEY_XF86CD, Qt::Key_CD }, - { XKB_KEY_XF86Calculater, Qt::Key_Calculator }, - { XKB_KEY_XF86Clear, Qt::Key_Clear }, - { XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab }, - { XKB_KEY_XF86Close, Qt::Key_Close }, - { XKB_KEY_XF86Copy, Qt::Key_Copy }, - { XKB_KEY_XF86Cut, Qt::Key_Cut }, - { XKB_KEY_XF86Display, Qt::Key_Display }, - { XKB_KEY_XF86DOS, Qt::Key_DOS }, - { XKB_KEY_XF86Documents, Qt::Key_Documents }, - { XKB_KEY_XF86Excel, Qt::Key_Excel }, - { XKB_KEY_XF86Explorer, Qt::Key_Explorer }, - { XKB_KEY_XF86Game, Qt::Key_Game }, - { XKB_KEY_XF86Go, Qt::Key_Go }, - { XKB_KEY_XF86iTouch, Qt::Key_iTouch }, - { XKB_KEY_XF86LogOff, Qt::Key_LogOff }, - { XKB_KEY_XF86Market, Qt::Key_Market }, - { XKB_KEY_XF86Meeting, Qt::Key_Meeting }, - { XKB_KEY_XF86MenuKB, Qt::Key_MenuKB }, - { XKB_KEY_XF86MenuPB, Qt::Key_MenuPB }, - { XKB_KEY_XF86MySites, Qt::Key_MySites }, - { XKB_KEY_XF86News, Qt::Key_News }, - { XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome }, - { XKB_KEY_XF86Option, Qt::Key_Option }, - { XKB_KEY_XF86Paste, Qt::Key_Paste }, - { XKB_KEY_XF86Phone, Qt::Key_Phone }, - { XKB_KEY_XF86Reply, Qt::Key_Reply }, - { XKB_KEY_XF86Reload, Qt::Key_Reload }, - { XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows }, - { XKB_KEY_XF86RotationPB, Qt::Key_RotationPB }, - { XKB_KEY_XF86RotationKB, Qt::Key_RotationKB }, - { XKB_KEY_XF86Save, Qt::Key_Save }, - { XKB_KEY_XF86Send, Qt::Key_Send }, - { XKB_KEY_XF86Spell, Qt::Key_Spell }, - { XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen }, - { XKB_KEY_XF86Support, Qt::Key_Support }, - { XKB_KEY_XF86TaskPane, Qt::Key_TaskPane }, - { XKB_KEY_XF86Terminal, Qt::Key_Terminal }, - { XKB_KEY_XF86Tools, Qt::Key_Tools }, - { XKB_KEY_XF86Travel, Qt::Key_Travel }, - { XKB_KEY_XF86Video, Qt::Key_Video }, - { XKB_KEY_XF86Word, Qt::Key_Word }, - { XKB_KEY_XF86Xfer, Qt::Key_Xfer }, - { XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn }, - { XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut }, - { XKB_KEY_XF86Away, Qt::Key_Away }, - { XKB_KEY_XF86Messenger, Qt::Key_Messenger }, - { XKB_KEY_XF86WebCam, Qt::Key_WebCam }, - { XKB_KEY_XF86MailForward, Qt::Key_MailForward }, - { XKB_KEY_XF86Pictures, Qt::Key_Pictures }, - { XKB_KEY_XF86Music, Qt::Key_Music }, - { XKB_KEY_XF86Battery, Qt::Key_Battery }, - { XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth }, - { XKB_KEY_XF86WLAN, Qt::Key_WLAN }, - { XKB_KEY_XF86UWB, Qt::Key_UWB }, - { XKB_KEY_XF86AudioForward, Qt::Key_AudioForward }, - { XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat }, - { XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay }, - { XKB_KEY_XF86Subtitle, Qt::Key_Subtitle }, - { XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack }, - { XKB_KEY_XF86Time, Qt::Key_Time }, - { XKB_KEY_XF86Select, Qt::Key_Select }, - { XKB_KEY_XF86View, Qt::Key_View }, - { XKB_KEY_XF86TopMenu, Qt::Key_TopMenu }, - { XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth }, - { XKB_KEY_XF86Suspend, Qt::Key_Suspend }, - { XKB_KEY_XF86Hibernate, Qt::Key_Hibernate }, - { XKB_KEY_XF86TouchpadToggle, Qt::Key_TouchpadToggle }, - { XKB_KEY_XF86TouchpadOn, Qt::Key_TouchpadOn }, - { XKB_KEY_XF86TouchpadOff, Qt::Key_TouchpadOff }, - { XKB_KEY_XF86AudioMicMute, Qt::Key_MicMute }, - { XKB_KEY_XF86Launch0, Qt::Key_Launch2 }, - { XKB_KEY_XF86Launch1, Qt::Key_Launch3 }, - { XKB_KEY_XF86Launch2, Qt::Key_Launch4 }, - { XKB_KEY_XF86Launch3, Qt::Key_Launch5 }, - { XKB_KEY_XF86Launch4, Qt::Key_Launch6 }, - { XKB_KEY_XF86Launch5, Qt::Key_Launch7 }, - { XKB_KEY_XF86Launch6, Qt::Key_Launch8 }, - { XKB_KEY_XF86Launch7, Qt::Key_Launch9 }, - { XKB_KEY_XF86Launch8, Qt::Key_LaunchA }, - { XKB_KEY_XF86Launch9, Qt::Key_LaunchB }, - { XKB_KEY_XF86LaunchA, Qt::Key_LaunchC }, - { XKB_KEY_XF86LaunchB, Qt::Key_LaunchD }, - { XKB_KEY_XF86LaunchC, Qt::Key_LaunchE }, - { XKB_KEY_XF86LaunchD, Qt::Key_LaunchF } -}; - -static inline Qt::Key xkbToQtKey(xkb_keysym_t keySym) -{ - Qt::Key key = Qt::Key_unknown; - if (keySym >= XKB_KEY_KP_0 && keySym <= XKB_KEY_KP_9) { - // numeric keypad keys - key = Qt::Key(int(Qt::Key_0) + int(keySym) - XKB_KEY_KP_0); - } else if ((keySym >= XKB_KEY_a && keySym <= XKB_KEY_z) || - (keySym >= XKB_KEY_agrave && keySym < XKB_KEY_division) || - (keySym > XKB_KEY_division && keySym <= XKB_KEY_thorn)) { - key = Qt::Key(QChar(keySym).toUpper().unicode()); - } else if (keySym < 0x3000) { - key = Qt::Key(keySym); - } - if (key == Qt::Key_unknown) { - const auto it = s_mapping.find(keySym); - if (it != s_mapping.end()) { - key = it->second; - } - } - return key; -} - -static inline bool isKeypadKey(xkb_keysym_t keySym) -{ - return keySym >= XKB_KEY_KP_Space && keySym <= XKB_KEY_KP_9; -} - -static inline xkb_keysym_t qtKeyToXkb(Qt::Key qtKey, Qt::KeyboardModifiers modifiers) -{ - xkb_keysym_t sym = XKB_KEY_NoSymbol; - if (modifiers.testFlag(Qt::KeypadModifier) && qtKey >= Qt::Key_0 && qtKey <= Qt::Key_9) { - sym = XKB_KEY_KP_0 + qtKey - Qt::Key_0; - } else if (qtKey < 0x1000 && !modifiers.testFlag(Qt::KeypadModifier)) { - QChar character(qtKey); - if (!modifiers.testFlag(Qt::ShiftModifier)) { - character = character.toLower(); - } - sym = character.unicode(); - } - - if (sym == XKB_KEY_NoSymbol) { - std::vector possibleMatches; - for (auto pair : s_mapping) { - if (pair.second == qtKey) { - possibleMatches.emplace_back(pair.first); - } - } - if (!possibleMatches.empty()) { - sym = possibleMatches.front(); - for (auto match : possibleMatches) { - // is the current match better than existing? - if (modifiers.testFlag(Qt::KeypadModifier)) { - if (isKeypadKey(match)) { - sym = match; - } - } else { - if (isKeypadKey(sym)) { - sym = match; - } - } - } - } - } - return sym; -} - -} - -#endif