File indexing completed on 2024-05-05 16:19:50

0001 /*
0002     SPDX-FileCopyrightText: 2001 Ellis Whitehead <ellis@kde.org>
0003 
0004     Win32 port:
0005     SPDX-FileCopyrightText: 2004 Jarosław Staniek <staniek@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.1-or-later
0008 */
0009 
0010 #include "kkeyserver.h"
0011 #include "kkeyserver_x11.h"
0012 
0013 #include "platforms/xcb/kwindowsystem_xcb_debug.h"
0014 
0015 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
0016 #include <private/qtx11extras_p.h>
0017 #else
0018 #include <QX11Info>
0019 #endif
0020 
0021 #define XK_MISCELLANY
0022 #define XK_XKB_KEYS
0023 #include <X11/X.h>
0024 #include <X11/Xlib.h>
0025 #include <X11/Xutil.h>
0026 #include <X11/keysymdef.h>
0027 #include <xcb/xcb_keysyms.h>
0028 #define X11_ONLY(arg) arg, // allows to omit an argument
0029 
0030 // #define KKEYSERVER_DEBUG 1
0031 
0032 namespace KKeyServer
0033 {
0034 //---------------------------------------------------------------------
0035 // Data Structures
0036 //---------------------------------------------------------------------
0037 
0038 struct Mod {
0039     int m_mod;
0040 };
0041 
0042 //---------------------------------------------------------------------
0043 // Array Structures
0044 //---------------------------------------------------------------------
0045 
0046 struct X11ModInfo {
0047     int modQt;
0048     int modX;
0049 };
0050 
0051 struct SymVariation {
0052     uint sym, symVariation;
0053     bool bActive;
0054 };
0055 
0056 struct SymName {
0057     uint sym;
0058     const char *psName;
0059 };
0060 
0061 struct TransKey {
0062     int keySymQt;
0063     uint keySymX;
0064 };
0065 
0066 //---------------------------------------------------------------------
0067 // Arrays
0068 //---------------------------------------------------------------------
0069 // clang-format off
0070 
0071 static X11ModInfo g_rgX11ModInfo[4] = {
0072     { Qt::SHIFT,   X11_ONLY(ShiftMask) },
0073     { Qt::CTRL,    X11_ONLY(ControlMask) },
0074     { Qt::ALT,     X11_ONLY(Mod1Mask) },
0075     { Qt::META,    X11_ONLY(Mod4Mask) }
0076 };
0077 
0078 // These are the X equivalents to the Qt keycodes 0x1000 - 0x1026
0079 static const TransKey g_rgQtToSymX[] = {
0080     { Qt::Key_Escape,     XK_Escape },
0081     { Qt::Key_Tab,        XK_Tab },
0082     { Qt::Key_Backtab,    XK_ISO_Left_Tab },
0083     { Qt::Key_Backspace,  XK_BackSpace },
0084     { Qt::Key_Return,     XK_Return },
0085     { Qt::Key_Insert,     XK_Insert },
0086     { Qt::Key_Delete,     XK_Delete },
0087     { Qt::Key_Pause,      XK_Pause },
0088 #ifdef sun
0089     { Qt::Key_Print,      XK_F22 },
0090 #else
0091     { Qt::Key_Print,      XK_Print },
0092 #endif
0093     { Qt::Key_SysReq,     XK_Sys_Req },
0094     { Qt::Key_Home,       XK_Home },
0095     { Qt::Key_End,        XK_End },
0096     { Qt::Key_Left,       XK_Left },
0097     { Qt::Key_Up,         XK_Up },
0098     { Qt::Key_Right,      XK_Right },
0099     { Qt::Key_Down,       XK_Down },
0100     { Qt::Key_PageUp,      XK_Prior },
0101     { Qt::Key_PageDown,       XK_Next },
0102     //{ Qt::Key_Shift,      0 },
0103     //{ Qt::Key_Control,    0 },
0104     //{ Qt::Key_Meta,       0 },
0105     //{ Qt::Key_Alt,        0 },
0106     { Qt::Key_CapsLock,   XK_Caps_Lock },
0107     { Qt::Key_NumLock,    XK_Num_Lock },
0108     { Qt::Key_ScrollLock, XK_Scroll_Lock },
0109     { Qt::Key_F1,         XK_F1 },
0110     { Qt::Key_F2,         XK_F2 },
0111     { Qt::Key_F3,         XK_F3 },
0112     { Qt::Key_F4,         XK_F4 },
0113     { Qt::Key_F5,         XK_F5 },
0114     { Qt::Key_F6,         XK_F6 },
0115     { Qt::Key_F7,         XK_F7 },
0116     { Qt::Key_F8,         XK_F8 },
0117     { Qt::Key_F9,         XK_F9 },
0118     { Qt::Key_F10,        XK_F10 },
0119     { Qt::Key_F11,        XK_F11 },
0120     { Qt::Key_F12,        XK_F12 },
0121     { Qt::Key_F13,        XK_F13 },
0122     { Qt::Key_F14,        XK_F14 },
0123     { Qt::Key_F15,        XK_F15 },
0124     { Qt::Key_F16,        XK_F16 },
0125     { Qt::Key_F17,        XK_F17 },
0126     { Qt::Key_F18,        XK_F18 },
0127     { Qt::Key_F19,        XK_F19 },
0128     { Qt::Key_F20,        XK_F20 },
0129     { Qt::Key_F21,        XK_F21 },
0130     { Qt::Key_F22,        XK_F22 },
0131     { Qt::Key_F23,        XK_F23 },
0132     { Qt::Key_F24,        XK_F24 },
0133     { Qt::Key_F25,        XK_F25 },
0134     { Qt::Key_F26,        XK_F26 },
0135     { Qt::Key_F27,        XK_F27 },
0136     { Qt::Key_F28,        XK_F28 },
0137     { Qt::Key_F29,        XK_F29 },
0138     { Qt::Key_F30,        XK_F30 },
0139     { Qt::Key_F31,        XK_F31 },
0140     { Qt::Key_F32,        XK_F32 },
0141     { Qt::Key_F33,        XK_F33 },
0142     { Qt::Key_F34,        XK_F34 },
0143     { Qt::Key_F35,        XK_F35 },
0144     { Qt::Key_Super_L,    XK_Super_L },
0145     { Qt::Key_Super_R,    XK_Super_R },
0146     { Qt::Key_Menu,       XK_Menu },
0147     { Qt::Key_Hyper_L,    XK_Hyper_L },
0148     { Qt::Key_Hyper_R,    XK_Hyper_R },
0149     { Qt::Key_Help,       XK_Help },
0150     //{ Qt::Key_Direction_L, XK_Direction_L }, These keys don't exist in X11
0151     //{ Qt::Key_Direction_R, XK_Direction_R },
0152 
0153     { Qt::Key_Space,      XK_KP_Space },
0154     { Qt::Key_Tab,        XK_KP_Tab },
0155     { Qt::Key_Enter,      XK_KP_Enter },
0156     { Qt::Key_Home,       XK_KP_Home },
0157     { Qt::Key_Left,       XK_KP_Left },
0158     { Qt::Key_Up,         XK_KP_Up },
0159     { Qt::Key_Right,      XK_KP_Right },
0160     { Qt::Key_Down,       XK_KP_Down },
0161     { Qt::Key_PageUp,     XK_KP_Prior },
0162     { Qt::Key_PageDown,   XK_KP_Next },
0163     { Qt::Key_End,        XK_KP_End },
0164     { Qt::Key_Clear,      XK_KP_Begin },
0165     { Qt::Key_Insert,     XK_KP_Insert },
0166     { Qt::Key_Delete,     XK_KP_Delete },
0167     { Qt::Key_Equal,      XK_KP_Equal },
0168     { Qt::Key_Asterisk,   XK_KP_Multiply },
0169     { Qt::Key_Plus,       XK_KP_Add },
0170     { Qt::Key_Comma,      XK_KP_Separator },
0171     { Qt::Key_Minus,      XK_KP_Subtract },
0172     { Qt::Key_Period,     XK_KP_Decimal },
0173     { Qt::Key_Slash,      XK_KP_Divide },
0174 
0175 // the next lines are taken on 10/2009 from X.org (X11/XF86keysym.h), defining some special
0176 // multimedia keys. They are included here as not every system has them.
0177 #define XF86XK_MonBrightnessUp     0x1008FF02
0178 #define XF86XK_MonBrightnessDown   0x1008FF03
0179 #define XF86XK_KbdLightOnOff       0x1008FF04
0180 #define XF86XK_KbdBrightnessUp     0x1008FF05
0181 #define XF86XK_KbdBrightnessDown   0x1008FF06
0182 #define XF86XK_Standby             0x1008FF10
0183 #define XF86XK_AudioLowerVolume    0x1008FF11
0184 #define XF86XK_AudioMute           0x1008FF12
0185 #define XF86XK_AudioRaiseVolume    0x1008FF13
0186 #define XF86XK_AudioPlay           0x1008FF14
0187 #define XF86XK_AudioStop           0x1008FF15
0188 #define XF86XK_AudioPrev           0x1008FF16
0189 #define XF86XK_AudioNext           0x1008FF17
0190 #define XF86XK_HomePage            0x1008FF18
0191 #define XF86XK_Mail                0x1008FF19
0192 #define XF86XK_Start               0x1008FF1A
0193 #define XF86XK_Search              0x1008FF1B
0194 #define XF86XK_AudioRecord         0x1008FF1C
0195 #define XF86XK_Calculator          0x1008FF1D
0196 #define XF86XK_Memo                0x1008FF1E
0197 #define XF86XK_ToDoList            0x1008FF1F
0198 #define XF86XK_Calendar            0x1008FF20
0199 #define XF86XK_PowerDown           0x1008FF21
0200 #define XF86XK_ContrastAdjust      0x1008FF22
0201 #define XF86XK_Back                0x1008FF26
0202 #define XF86XK_Forward             0x1008FF27
0203 #define XF86XK_Stop                0x1008FF28
0204 #define XF86XK_Refresh             0x1008FF29
0205 #define XF86XK_PowerOff            0x1008FF2A
0206 #define XF86XK_WakeUp              0x1008FF2B
0207 #define XF86XK_Eject               0x1008FF2C
0208 #define XF86XK_ScreenSaver         0x1008FF2D
0209 #define XF86XK_WWW                 0x1008FF2E
0210 #define XF86XK_Sleep               0x1008FF2F
0211 #define XF86XK_Favorites           0x1008FF30
0212 #define XF86XK_AudioPause          0x1008FF31
0213 #define XF86XK_AudioMedia          0x1008FF32
0214 #define XF86XK_MyComputer          0x1008FF33
0215 #define XF86XK_LightBulb           0x1008FF35
0216 #define XF86XK_Shop                0x1008FF36
0217 #define XF86XK_History             0x1008FF37
0218 #define XF86XK_OpenURL             0x1008FF38
0219 #define XF86XK_AddFavorite         0x1008FF39
0220 #define XF86XK_HotLinks            0x1008FF3A
0221 #define XF86XK_BrightnessAdjust    0x1008FF3B
0222 #define XF86XK_Finance             0x1008FF3C
0223 #define XF86XK_Community           0x1008FF3D
0224 #define XF86XK_AudioRewind         0x1008FF3E
0225 #define XF86XK_BackForward         0x1008FF3F
0226 #define XF86XK_Launch0             0x1008FF40
0227 #define XF86XK_Launch1             0x1008FF41
0228 #define XF86XK_Launch2             0x1008FF42
0229 #define XF86XK_Launch3             0x1008FF43
0230 #define XF86XK_Launch4             0x1008FF44
0231 #define XF86XK_Launch5             0x1008FF45
0232 #define XF86XK_Launch6             0x1008FF46
0233 #define XF86XK_Launch7             0x1008FF47
0234 #define XF86XK_Launch8             0x1008FF48
0235 #define XF86XK_Launch9             0x1008FF49
0236 #define XF86XK_LaunchA             0x1008FF4A
0237 #define XF86XK_LaunchB             0x1008FF4B
0238 #define XF86XK_LaunchC             0x1008FF4C
0239 #define XF86XK_LaunchD             0x1008FF4D
0240 #define XF86XK_LaunchE             0x1008FF4E
0241 #define XF86XK_LaunchF             0x1008FF4F
0242 #define XF86XK_ApplicationLeft     0x1008FF50
0243 #define XF86XK_ApplicationRight    0x1008FF51
0244 #define XF86XK_Book                0x1008FF52
0245 #define XF86XK_CD                  0x1008FF53
0246 #define XF86XK_Calculater          0x1008FF54
0247 #define XF86XK_Clear               0x1008FF55
0248 #define XF86XK_ClearGrab           0x1008FE21
0249 #define XF86XK_Close               0x1008FF56
0250 #define XF86XK_Copy                0x1008FF57
0251 #define XF86XK_Cut                 0x1008FF58
0252 #define XF86XK_Display             0x1008FF59
0253 #define XF86XK_DOS                 0x1008FF5A
0254 #define XF86XK_Documents           0x1008FF5B
0255 #define XF86XK_Excel               0x1008FF5C
0256 #define XF86XK_Explorer            0x1008FF5D
0257 #define XF86XK_Game                0x1008FF5E
0258 #define XF86XK_Go                  0x1008FF5F
0259 #define XF86XK_iTouch              0x1008FF60
0260 #define XF86XK_LogOff              0x1008FF61
0261 #define XF86XK_Market              0x1008FF62
0262 #define XF86XK_Meeting             0x1008FF63
0263 #define XF86XK_MenuKB              0x1008FF65
0264 #define XF86XK_MenuPB              0x1008FF66
0265 #define XF86XK_MySites             0x1008FF67
0266 #define XF86XK_News                0x1008FF69
0267 #define XF86XK_OfficeHome          0x1008FF6A
0268 #define XF86XK_Option              0x1008FF6C
0269 #define XF86XK_Paste               0x1008FF6D
0270 #define XF86XK_Phone               0x1008FF6E
0271 #define XF86XK_Reply               0x1008FF72
0272 #define XF86XK_Reload              0x1008FF73
0273 #define XF86XK_RotateWindows       0x1008FF74
0274 #define XF86XK_RotationPB          0x1008FF75
0275 #define XF86XK_RotationKB          0x1008FF76
0276 #define XF86XK_Save                0x1008FF77
0277 #define XF86XK_Send                0x1008FF7B
0278 #define XF86XK_Spell               0x1008FF7C
0279 #define XF86XK_SplitScreen         0x1008FF7D
0280 #define XF86XK_Support             0x1008FF7E
0281 #define XF86XK_TaskPane            0x1008FF7F
0282 #define XF86XK_Terminal            0x1008FF80
0283 #define XF86XK_Tools               0x1008FF81
0284 #define XF86XK_Travel              0x1008FF82
0285 #define XF86XK_Video               0x1008FF87
0286 #define XF86XK_Word                0x1008FF89
0287 #define XF86XK_Xfer                0x1008FF8A
0288 #define XF86XK_ZoomIn              0x1008FF8B
0289 #define XF86XK_ZoomOut             0x1008FF8C
0290 #define XF86XK_Away                0x1008FF8D
0291 #define XF86XK_Messenger           0x1008FF8E
0292 #define XF86XK_WebCam              0x1008FF8F
0293 #define XF86XK_MailForward         0x1008FF90
0294 #define XF86XK_Pictures            0x1008FF91
0295 #define XF86XK_Music               0x1008FF92
0296 #define XF86XK_Battery             0x1008FF93
0297 #define XF86XK_Bluetooth           0x1008FF94
0298 #define XF86XK_WLAN                0x1008FF95
0299 #define XF86XK_UWB                 0x1008FF96
0300 #define XF86XK_AudioForward        0x1008FF97
0301 #define XF86XK_AudioRepeat         0x1008FF98
0302 #define XF86XK_AudioRandomPlay     0x1008FF99
0303 #define XF86XK_Subtitle            0x1008FF9A
0304 #define XF86XK_AudioCycleTrack     0x1008FF9B
0305 #define XF86XK_Time                0x1008FF9F
0306 #define XF86XK_Select              0x1008FFA0
0307 #define XF86XK_View                0x1008FFA1
0308 #define XF86XK_TopMenu             0x1008FFA2
0309 #define XF86XK_Suspend             0x1008FFA7
0310 #define XF86XK_Hibernate           0x1008FFA8
0311 #define XF86XK_TouchpadToggle      0x1008FFA9
0312 #define XF86XK_TouchpadOn          0x1008FFB0
0313 #define XF86XK_TouchpadOff         0x1008FFB1
0314 #define XF86XK_AudioMicMute        0x1008FFB2
0315 // end of XF86keysyms.h
0316 
0317     // All of the stuff below really has to match qxcbkeyboard.cpp in Qt!
0318     { Qt::Key_Back,       XF86XK_Back },
0319     { Qt::Key_Forward,    XF86XK_Forward },
0320     { Qt::Key_Stop,       XF86XK_Stop },
0321     { Qt::Key_Refresh,    XF86XK_Refresh },
0322     { Qt::Key_Favorites,  XF86XK_Favorites },
0323     { Qt::Key_LaunchMedia, XF86XK_AudioMedia },
0324     { Qt::Key_OpenUrl,    XF86XK_OpenURL },
0325     { Qt::Key_HomePage,   XF86XK_HomePage },
0326     { Qt::Key_Search,     XF86XK_Search },
0327     { Qt::Key_VolumeDown, XF86XK_AudioLowerVolume },
0328     { Qt::Key_VolumeMute, XF86XK_AudioMute },
0329     { Qt::Key_VolumeUp,   XF86XK_AudioRaiseVolume },
0330     { Qt::Key_MediaPlay,  XF86XK_AudioPlay },
0331     { Qt::Key_MediaStop,  XF86XK_AudioStop },
0332     { Qt::Key_MediaPrevious,  XF86XK_AudioPrev },
0333     { Qt::Key_MediaNext,  XF86XK_AudioNext },
0334     { Qt::Key_MediaRecord, XF86XK_AudioRecord },
0335     { Qt::Key_MediaPause, XF86XK_AudioPause },
0336     { Qt::Key_LaunchMail, XF86XK_Mail },
0337     { Qt::Key_Launch0,    XF86XK_MyComputer },
0338     { Qt::Key_Launch1,    XF86XK_Calculator },
0339     { Qt::Key_Memo,    XF86XK_Memo },
0340     { Qt::Key_ToDoList,    XF86XK_ToDoList },
0341     { Qt::Key_Calendar,    XF86XK_Calendar },
0342     { Qt::Key_PowerDown,    XF86XK_PowerDown },
0343     { Qt::Key_ContrastAdjust,    XF86XK_ContrastAdjust },
0344     { Qt::Key_Standby,    XF86XK_Standby },
0345     { Qt::Key_MonBrightnessUp,  XF86XK_MonBrightnessUp },
0346     { Qt::Key_MonBrightnessDown,  XF86XK_MonBrightnessDown },
0347     { Qt::Key_KeyboardLightOnOff,  XF86XK_KbdLightOnOff },
0348     { Qt::Key_KeyboardBrightnessUp,  XF86XK_KbdBrightnessUp },
0349     { Qt::Key_KeyboardBrightnessDown,  XF86XK_KbdBrightnessDown },
0350     { Qt::Key_PowerOff,  XF86XK_PowerOff },
0351     { Qt::Key_WakeUp,  XF86XK_WakeUp },
0352     { Qt::Key_Eject,  XF86XK_Eject },
0353     { Qt::Key_ScreenSaver,  XF86XK_ScreenSaver },
0354     { Qt::Key_WWW,  XF86XK_WWW },
0355     { Qt::Key_Sleep,  XF86XK_Sleep },
0356     { Qt::Key_LightBulb,  XF86XK_LightBulb },
0357     { Qt::Key_Shop,  XF86XK_Shop },
0358     { Qt::Key_History,  XF86XK_History },
0359     { Qt::Key_AddFavorite,  XF86XK_AddFavorite },
0360     { Qt::Key_HotLinks,  XF86XK_HotLinks },
0361     { Qt::Key_BrightnessAdjust,  XF86XK_BrightnessAdjust },
0362     { Qt::Key_Finance,  XF86XK_Finance },
0363     { Qt::Key_Community,  XF86XK_Community },
0364     { Qt::Key_AudioRewind,  XF86XK_AudioRewind },
0365     { Qt::Key_BackForward,  XF86XK_BackForward },
0366     { Qt::Key_ApplicationLeft,  XF86XK_ApplicationLeft },
0367     { Qt::Key_ApplicationRight,  XF86XK_ApplicationRight },
0368     { Qt::Key_Book,  XF86XK_Book },
0369     { Qt::Key_CD,  XF86XK_CD },
0370     { Qt::Key_Calculator,  XF86XK_Calculater },
0371     { Qt::Key_Clear,  XF86XK_Clear },
0372     { Qt::Key_ClearGrab,  XF86XK_ClearGrab },
0373     { Qt::Key_Close,  XF86XK_Close },
0374     { Qt::Key_Copy,  XF86XK_Copy },
0375     { Qt::Key_Cut,  XF86XK_Cut },
0376     { Qt::Key_Display,  XF86XK_Display },
0377     { Qt::Key_DOS,  XF86XK_DOS },
0378     { Qt::Key_Documents,  XF86XK_Documents },
0379     { Qt::Key_Excel,  XF86XK_Excel },
0380     { Qt::Key_Explorer,  XF86XK_Explorer },
0381     { Qt::Key_Game,  XF86XK_Game },
0382     { Qt::Key_Go,  XF86XK_Go },
0383     { Qt::Key_iTouch,  XF86XK_iTouch },
0384     { Qt::Key_LogOff,  XF86XK_LogOff },
0385     { Qt::Key_Market,  XF86XK_Market },
0386     { Qt::Key_Meeting,  XF86XK_Meeting },
0387     { Qt::Key_MenuKB,  XF86XK_MenuKB },
0388     { Qt::Key_MenuPB,  XF86XK_MenuPB },
0389     { Qt::Key_MySites,  XF86XK_MySites },
0390     { Qt::Key_News,  XF86XK_News },
0391     { Qt::Key_OfficeHome,  XF86XK_OfficeHome },
0392     { Qt::Key_Option,  XF86XK_Option },
0393     { Qt::Key_Paste,  XF86XK_Paste },
0394     { Qt::Key_Phone,  XF86XK_Phone },
0395     { Qt::Key_Reply,  XF86XK_Reply },
0396     { Qt::Key_Reload,  XF86XK_Reload },
0397     { Qt::Key_RotateWindows,  XF86XK_RotateWindows },
0398     { Qt::Key_RotationPB,  XF86XK_RotationPB },
0399     { Qt::Key_RotationKB,  XF86XK_RotationKB },
0400     { Qt::Key_Save,  XF86XK_Save },
0401     { Qt::Key_Send,  XF86XK_Send },
0402     { Qt::Key_Spell,  XF86XK_Spell },
0403     { Qt::Key_SplitScreen,  XF86XK_SplitScreen },
0404     { Qt::Key_Support,  XF86XK_Support },
0405     { Qt::Key_TaskPane,  XF86XK_TaskPane },
0406     { Qt::Key_Terminal,  XF86XK_Terminal },
0407     { Qt::Key_Tools,  XF86XK_Tools },
0408     { Qt::Key_Travel,  XF86XK_Travel },
0409     { Qt::Key_Video,  XF86XK_Video },
0410     { Qt::Key_Word,  XF86XK_Word },
0411     { Qt::Key_Xfer,  XF86XK_Xfer },
0412     { Qt::Key_ZoomIn,  XF86XK_ZoomIn },
0413     { Qt::Key_ZoomOut,  XF86XK_ZoomOut },
0414     { Qt::Key_Away,  XF86XK_Away },
0415     { Qt::Key_Messenger,  XF86XK_Messenger },
0416     { Qt::Key_WebCam,  XF86XK_WebCam },
0417     { Qt::Key_MailForward,  XF86XK_MailForward },
0418     { Qt::Key_Pictures,  XF86XK_Pictures },
0419     { Qt::Key_Music,  XF86XK_Music },
0420     { Qt::Key_Battery,  XF86XK_Battery },
0421     { Qt::Key_Bluetooth,  XF86XK_Bluetooth },
0422     { Qt::Key_WLAN,  XF86XK_WLAN },
0423     { Qt::Key_UWB,  XF86XK_UWB },
0424     { Qt::Key_AudioForward,  XF86XK_AudioForward },
0425     { Qt::Key_AudioRepeat,  XF86XK_AudioRepeat },
0426     { Qt::Key_AudioRandomPlay,  XF86XK_AudioRandomPlay },
0427     { Qt::Key_Subtitle,  XF86XK_Subtitle },
0428     { Qt::Key_AudioCycleTrack,  XF86XK_AudioCycleTrack },
0429     { Qt::Key_Time,  XF86XK_Time },
0430     { Qt::Key_Select,  XF86XK_Select },
0431     { Qt::Key_View,  XF86XK_View },
0432     { Qt::Key_TopMenu,  XF86XK_TopMenu },
0433     { Qt::Key_Bluetooth,  XF86XK_Bluetooth },
0434     { Qt::Key_Suspend,  XF86XK_Suspend },
0435     { Qt::Key_Hibernate,  XF86XK_Hibernate },
0436     { Qt::Key_TouchpadToggle, XF86XK_TouchpadToggle },
0437     { Qt::Key_TouchpadOn, XF86XK_TouchpadOn },
0438     { Qt::Key_TouchpadOff, XF86XK_TouchpadOff },
0439     { Qt::Key_MicMute, XF86XK_AudioMicMute },
0440     { Qt::Key_Launch2,    XF86XK_Launch0 },
0441     { Qt::Key_Launch3,    XF86XK_Launch1 },
0442     { Qt::Key_Launch4,    XF86XK_Launch2 },
0443     { Qt::Key_Launch5,    XF86XK_Launch3 },
0444     { Qt::Key_Launch6,    XF86XK_Launch4 },
0445     { Qt::Key_Launch7,    XF86XK_Launch5 },
0446     { Qt::Key_Launch8,    XF86XK_Launch6 },
0447     { Qt::Key_Launch9,    XF86XK_Launch7 },
0448     { Qt::Key_LaunchA,    XF86XK_Launch8 },
0449     { Qt::Key_LaunchB,    XF86XK_Launch9 },
0450     { Qt::Key_LaunchC,    XF86XK_LaunchA },
0451     { Qt::Key_LaunchD,    XF86XK_LaunchB },
0452     { Qt::Key_LaunchE,    XF86XK_LaunchC },
0453     { Qt::Key_LaunchF,    XF86XK_LaunchD },
0454 };
0455 // clang-format on
0456 
0457 //---------------------------------------------------------------------
0458 // Debugging
0459 //---------------------------------------------------------------------
0460 #ifndef NDEBUG
0461 inline void checkDisplay()
0462 {
0463     // Some non-GUI apps might try to use us.
0464     if (!QX11Info::display()) {
0465         qCCritical(LOG_KKEYSERVER_X11) << "QX11Info::display() returns 0.  I'm probably going to crash now.";
0466         qCCritical(LOG_KKEYSERVER_X11) << "If this is a KApplication initialized without GUI stuff, change it to be "
0467                                           "initialized with GUI stuff.";
0468     }
0469 }
0470 #else // NDEBUG
0471 #define checkDisplay()
0472 #endif
0473 
0474 //---------------------------------------------------------------------
0475 // Initialization
0476 //---------------------------------------------------------------------
0477 
0478 static bool g_bInitializedMods;
0479 static uint g_modXNumLock, g_modXScrollLock, g_modXModeSwitch, g_alt_mask, g_meta_mask, g_super_mask, g_hyper_mask;
0480 
0481 bool initializeMods()
0482 {
0483     // Reinitialize the masks
0484     g_modXNumLock = 0;
0485     g_modXScrollLock = 0;
0486     g_modXModeSwitch = 0;
0487     g_alt_mask = 0;
0488     g_meta_mask = 0;
0489     g_super_mask = 0;
0490     g_hyper_mask = 0;
0491 
0492     if (!QX11Info::isPlatformX11()) {
0493         qCWarning(LOG_KKEYSERVER_X11) << "X11 implementation of KKeyServer accessed from non-X11 platform! This is an application bug.";
0494         g_bInitializedMods = true;
0495         return false;
0496     }
0497 
0498     checkDisplay();
0499     xcb_key_symbols_t *symbols = xcb_key_symbols_alloc(QX11Info::connection());
0500     XModifierKeymap *xmk = XGetModifierMapping(QX11Info::display());
0501 
0502     int min_keycode;
0503     int max_keycode;
0504     int keysyms_per_keycode = 0;
0505 
0506     XDisplayKeycodes(QX11Info::display(), &min_keycode, &max_keycode);
0507     XFree(XGetKeyboardMapping(QX11Info::display(), min_keycode, 1, &keysyms_per_keycode));
0508 
0509     for (int i = Mod1MapIndex; i < 8; i++) {
0510         uint mask = (1 << i);
0511         uint keySymX = NoSymbol;
0512 
0513         // This used to be only XKeycodeToKeysym( ... , 0 ), but that fails with XFree4.3.99
0514         // and X.org R6.7 , where for some reason only ( ... , 1 ) works. I have absolutely no
0515         // idea what the problem is, but searching all possibilities until something valid is
0516         // found fixes the problem.
0517         for (int j = 0; j < xmk->max_keypermod; ++j) {
0518             for (int k = 0; k < keysyms_per_keycode; ++k) {
0519                 keySymX = xcb_key_symbols_get_keysym(symbols, xmk->modifiermap[xmk->max_keypermod * i + j], k);
0520 
0521                 switch (keySymX) {
0522                 case XK_Alt_L:
0523                 case XK_Alt_R:
0524                     g_alt_mask |= mask;
0525                     break;
0526 
0527                 case XK_Super_L:
0528                 case XK_Super_R:
0529                     g_super_mask |= mask;
0530                     break;
0531 
0532                 case XK_Hyper_L:
0533                 case XK_Hyper_R:
0534                     g_hyper_mask |= mask;
0535                     break;
0536 
0537                 case XK_Meta_L:
0538                 case XK_Meta_R:
0539                     g_meta_mask |= mask;
0540                     break;
0541 
0542                 case XK_Num_Lock:
0543                     g_modXNumLock |= mask;
0544                     break;
0545                 case XK_Scroll_Lock:
0546                     g_modXScrollLock |= mask;
0547                     break;
0548                 case XK_Mode_switch:
0549                     g_modXModeSwitch |= mask;
0550                     break;
0551                 }
0552             }
0553         }
0554     }
0555 
0556 #ifdef KKEYSERVER_DEBUG
0557     qCDebug(LOG_KKEYSERVER_X11) << "Alt:" << g_alt_mask;
0558     qCDebug(LOG_KKEYSERVER_X11) << "Meta:" << g_meta_mask;
0559     qCDebug(LOG_KKEYSERVER_X11) << "Super:" << g_super_mask;
0560     qCDebug(LOG_KKEYSERVER_X11) << "Hyper:" << g_hyper_mask;
0561     qCDebug(LOG_KKEYSERVER_X11) << "NumLock:" << g_modXNumLock;
0562     qCDebug(LOG_KKEYSERVER_X11) << "ScrollLock:" << g_modXScrollLock;
0563     qCDebug(LOG_KKEYSERVER_X11) << "ModeSwitch:" << g_modXModeSwitch;
0564 #endif
0565 
0566     // Check if hyper overlaps with super or meta or alt
0567     if (g_hyper_mask & (g_super_mask | g_meta_mask | g_alt_mask)) {
0568 #ifdef KKEYSERVER_DEBUG
0569         qCDebug(LOG_KKEYSERVER_X11) << "Hyper conflicts with super, meta or alt.";
0570 #endif
0571         // Remove the conflicting masks
0572         g_hyper_mask &= ~(g_super_mask | g_meta_mask | g_alt_mask);
0573     }
0574 
0575     // Check if super overlaps with meta or alt
0576     if (g_super_mask & (g_meta_mask | g_alt_mask)) {
0577 #ifdef KKEYSERVER_DEBUG
0578         qCDebug(LOG_KKEYSERVER_X11) << "Super conflicts with meta or alt.";
0579 #endif
0580         // Remove the conflicting masks
0581         g_super_mask &= ~(g_meta_mask | g_alt_mask);
0582     }
0583 
0584     // Check if meta overlaps with alt
0585     if (g_meta_mask | g_alt_mask) {
0586 #ifdef KKEYSERVER_DEBUG
0587         qCDebug(LOG_KKEYSERVER_X11) << "Meta conflicts with alt.";
0588 #endif
0589         // Remove the conflicting masks
0590         g_meta_mask &= ~(g_alt_mask);
0591     }
0592 
0593     if (!g_meta_mask) {
0594 #ifdef KKEYSERVER_DEBUG
0595         qCDebug(LOG_KKEYSERVER_X11) << "Meta is not set or conflicted with alt.";
0596 #endif
0597         if (g_super_mask) {
0598 #ifdef KKEYSERVER_DEBUG
0599             qCDebug(LOG_KKEYSERVER_X11) << "Using super for meta";
0600 #endif
0601             // Use Super
0602             g_meta_mask = g_super_mask;
0603         } else if (g_hyper_mask) {
0604 #ifdef KKEYSERVER_DEBUG
0605             qCDebug(LOG_KKEYSERVER_X11) << "Using hyper for meta";
0606 #endif
0607             // User Hyper
0608             g_meta_mask = g_hyper_mask;
0609         } else {
0610             // ???? Nothing left
0611             g_meta_mask = 0;
0612         }
0613     }
0614 
0615 #ifdef KKEYSERVER_DEBUG
0616     qCDebug(LOG_KKEYSERVER_X11) << "Alt:" << g_alt_mask;
0617     qCDebug(LOG_KKEYSERVER_X11) << "Meta:" << g_meta_mask;
0618     qCDebug(LOG_KKEYSERVER_X11) << "Super:" << g_super_mask;
0619     qCDebug(LOG_KKEYSERVER_X11) << "Hyper:" << g_hyper_mask;
0620     qCDebug(LOG_KKEYSERVER_X11) << "NumLock:" << g_modXNumLock;
0621     qCDebug(LOG_KKEYSERVER_X11) << "ScrollLock:" << g_modXScrollLock;
0622     qCDebug(LOG_KKEYSERVER_X11) << "ModeSwitch:" << g_modXModeSwitch;
0623 #endif
0624 
0625     if (!g_meta_mask) {
0626         qCWarning(LOG_KKEYSERVER_X11) << "Your keyboard setup doesn't provide a key to use for meta. See 'xmodmap -pm' or 'xkbcomp $DISPLAY'";
0627     }
0628 
0629     g_rgX11ModInfo[2].modX = g_alt_mask;
0630     g_rgX11ModInfo[3].modX = g_meta_mask;
0631 
0632     xcb_key_symbols_free(symbols);
0633     XFreeModifiermap(xmk);
0634     g_bInitializedMods = true;
0635 
0636     return true;
0637 }
0638 
0639 //---------------------------------------------------------------------
0640 // Helper functions
0641 //---------------------------------------------------------------------
0642 
0643 static bool is_keypad_key(xcb_keysym_t keysym)
0644 {
0645     return keysym >= XK_KP_Space && keysym <= XK_KP_9;
0646 }
0647 
0648 //---------------------------------------------------------------------
0649 // Public functions
0650 //---------------------------------------------------------------------
0651 
0652 uint modXShift()
0653 {
0654     return ShiftMask;
0655 }
0656 uint modXCtrl()
0657 {
0658     return ControlMask;
0659 }
0660 uint modXAlt()
0661 {
0662     if (!g_bInitializedMods) {
0663         initializeMods();
0664     }
0665     return g_alt_mask;
0666 }
0667 uint modXMeta()
0668 {
0669     if (!g_bInitializedMods) {
0670         initializeMods();
0671     }
0672     return g_meta_mask;
0673 }
0674 
0675 uint modXNumLock()
0676 {
0677     if (!g_bInitializedMods) {
0678         initializeMods();
0679     }
0680     return g_modXNumLock;
0681 }
0682 uint modXLock()
0683 {
0684     return LockMask;
0685 }
0686 uint modXScrollLock()
0687 {
0688     if (!g_bInitializedMods) {
0689         initializeMods();
0690     }
0691     return g_modXScrollLock;
0692 }
0693 uint modXModeSwitch()
0694 {
0695     if (!g_bInitializedMods) {
0696         initializeMods();
0697     }
0698     return g_modXModeSwitch;
0699 }
0700 
0701 bool keyboardHasMetaKey()
0702 {
0703     return modXMeta() != 0;
0704 }
0705 
0706 uint getModsRequired(uint sym)
0707 {
0708     if (!QX11Info::isPlatformX11()) {
0709         qCWarning(LOG_KKEYSERVER_X11) << "X11 implementation of KKeyServer accessed from non-X11 platform! This is an application bug.";
0710         return 0;
0711     }
0712     uint mod = 0;
0713 
0714     // FIXME: This might not be true on all keyboard layouts!
0715     if (sym == XK_Sys_Req) {
0716         return Qt::ALT;
0717     }
0718     if (sym == XK_Break) {
0719         return Qt::CTRL;
0720     }
0721 
0722     if (sym < 0x3000) {
0723         QChar c(sym);
0724         if (c.isLetter() && c.toLower() != c.toUpper() && sym == c.toUpper().unicode()) {
0725             return Qt::SHIFT;
0726         }
0727     }
0728 
0729     uchar code = XKeysymToKeycode(QX11Info::display(), sym);
0730     if (code) {
0731         // need to check index 0 before the others, so that a null-mod
0732         //  can take precedence over the others, in case the modified
0733         //  key produces the same symbol.
0734         if (sym == XKeycodeToKeysym(QX11Info::display(), code, 0)) {
0735             ;
0736         } else if (sym == XKeycodeToKeysym(QX11Info::display(), code, 1)) {
0737             mod = Qt::SHIFT;
0738         } else if (sym == XKeycodeToKeysym(QX11Info::display(), code, 2)) {
0739             mod = MODE_SWITCH;
0740         } else if (sym == XKeycodeToKeysym(QX11Info::display(), code, 3)) {
0741             mod = Qt::SHIFT | MODE_SWITCH;
0742         }
0743     }
0744     return mod;
0745 }
0746 
0747 bool keyQtToCodeX(int keyQt, int *keyCode)
0748 {
0749     if (!QX11Info::isPlatformX11()) {
0750         qCWarning(LOG_KKEYSERVER_X11) << "X11 implementation of KKeyServer accessed from non-X11 platform! This is an application bug.";
0751         return false;
0752     }
0753     int sym;
0754     uint mod;
0755     keyQtToSymX(keyQt, &sym);
0756     keyQtToModX(keyQt, &mod);
0757 
0758     // Get any extra mods required by the sym.
0759     //  E.g., XK_Plus requires SHIFT on the en layout.
0760     uint modExtra = getModsRequired(sym);
0761     // Get the X modifier equivalent.
0762     if (!sym || !keyQtToModX((keyQt & Qt::KeyboardModifierMask) | modExtra, &mod)) {
0763         *keyCode = 0;
0764         return false;
0765     }
0766 
0767     *keyCode = XKeysymToKeycode(QX11Info::display(), sym);
0768     return true;
0769 }
0770 
0771 bool keyQtToSymX(int keyQt, int *keySym)
0772 {
0773     int symQt = keyQt & ~Qt::KeyboardModifierMask;
0774 
0775     if (keyQt & Qt::KeypadModifier) {
0776         if (symQt >= Qt::Key_0 && symQt <= Qt::Key_9) {
0777             *keySym = XK_KP_0 + (symQt - Qt::Key_0);
0778             return true;
0779         }
0780     } else {
0781         if (symQt < 0x1000) {
0782             *keySym = QChar(symQt).toUpper().unicode();
0783             return true;
0784         }
0785     }
0786 
0787     for (const TransKey &tk : g_rgQtToSymX) {
0788         if (tk.keySymQt == symQt) {
0789             if ((keyQt & Qt::KeypadModifier) && !is_keypad_key(tk.keySymX)) {
0790                 continue;
0791             }
0792             *keySym = tk.keySymX;
0793             return true;
0794         }
0795     }
0796 
0797     *keySym = 0;
0798     if (symQt != Qt::Key_Shift && symQt != Qt::Key_Control && symQt != Qt::Key_Alt && symQt != Qt::Key_Meta && symQt != Qt::Key_Direction_L
0799         && symQt != Qt::Key_Direction_R) {
0800         // qCDebug(LOG_KKEYSERVER_X11) << "Sym::initQt( " << QString::number(keyQt,16) << " ): failed to convert key.";
0801     }
0802     return false;
0803 }
0804 
0805 bool symXModXToKeyQt(uint32_t keySym, uint16_t modX, int *keyQt)
0806 {
0807     int keyModQt = 0;
0808     *keyQt = Qt::Key_unknown;
0809 
0810     if (keySym >= XK_KP_0 && keySym <= XK_KP_9) {
0811         // numeric keypad keys
0812         *keyQt = Qt::Key_0 + ((int)keySym - XK_KP_0);
0813     } else if (keySym < 0x1000) {
0814         if (keySym >= 'a' && keySym <= 'z') {
0815             *keyQt = QChar(keySym).toUpper().unicode();
0816         } else {
0817             *keyQt = keySym;
0818         }
0819     }
0820 
0821     else if (keySym < 0x3000) {
0822         *keyQt = keySym;
0823     }
0824 
0825     else {
0826         for (const TransKey &tk : g_rgQtToSymX) {
0827             if (tk.keySymX == keySym) {
0828                 *keyQt = tk.keySymQt;
0829                 break;
0830             }
0831         }
0832     }
0833 
0834     if (*keyQt == Qt::Key_unknown) {
0835         return false;
0836     }
0837 
0838     if (modXToQt(modX, &keyModQt)) {
0839         *keyQt |= keyModQt;
0840         if (is_keypad_key(keySym)) {
0841             *keyQt |= Qt::KeypadModifier;
0842         }
0843         return true;
0844     }
0845     return false;
0846 }
0847 
0848 #if KWINDOWSYSTEM_BUILD_DEPRECATED_SINCE(5, 38)
0849 bool symXToKeyQt(uint keySym, int *keyQt)
0850 {
0851     return symXModXToKeyQt(keySym, 0, keyQt) & ~Qt::KeyboardModifierMask;
0852 }
0853 #endif
0854 
0855 bool keyQtToModX(int modQt, uint *modX)
0856 {
0857     if (!g_bInitializedMods) {
0858         initializeMods();
0859     }
0860 
0861     *modX = 0;
0862     for (int i = 0; i < 4; i++) {
0863         if (modQt & g_rgX11ModInfo[i].modQt) {
0864             if (g_rgX11ModInfo[i].modX) {
0865                 *modX |= g_rgX11ModInfo[i].modX;
0866             } else {
0867                 // The qt modifier has no x equivalent. Return false
0868                 return false;
0869             }
0870         }
0871     }
0872     return true;
0873 }
0874 
0875 bool modXToQt(uint modX, int *modQt)
0876 {
0877     if (!g_bInitializedMods) {
0878         initializeMods();
0879     }
0880 
0881     *modQt = 0;
0882     for (int i = 0; i < 4; i++) {
0883         if (modX & g_rgX11ModInfo[i].modX) {
0884             *modQt |= g_rgX11ModInfo[i].modQt;
0885             continue;
0886         }
0887     }
0888     return true;
0889 }
0890 
0891 bool codeXToSym(uchar codeX, uint modX, uint *sym)
0892 {
0893     if (!QX11Info::isPlatformX11()) {
0894         qCWarning(LOG_KKEYSERVER_X11) << "X11 implementation of KKeyServer accessed from non-X11 platform! This is an application bug.";
0895         return false;
0896     }
0897     KeySym keySym;
0898     XKeyPressedEvent event;
0899 
0900     checkDisplay();
0901 
0902     event.type = KeyPress;
0903     event.display = QX11Info::display();
0904     event.state = modX;
0905     event.keycode = codeX;
0906 
0907     XLookupString(&event, nullptr, 0, &keySym, nullptr);
0908     *sym = (uint)keySym;
0909     return true;
0910 }
0911 
0912 uint accelModMaskX()
0913 {
0914     return modXShift() | modXCtrl() | modXAlt() | modXMeta();
0915 }
0916 
0917 bool xEventToQt(XEvent *e, int *keyQt)
0918 {
0919     Q_ASSERT(e->type == KeyPress || e->type == KeyRelease);
0920 
0921     uchar keyCodeX = e->xkey.keycode;
0922     uint keyModX = e->xkey.state & (accelModMaskX() | MODE_SWITCH);
0923 
0924     KeySym keySym;
0925     char buffer[16];
0926     XLookupString((XKeyEvent *)e, buffer, 15, &keySym, nullptr);
0927     uint keySymX = (uint)keySym;
0928 
0929     // If numlock is active and a keypad key is pressed, XOR the SHIFT state.
0930     //  e.g., KP_4 => Shift+KP_Left, and Shift+KP_4 => KP_Left.
0931     if (e->xkey.state & modXNumLock()) {
0932         uint sym = XKeycodeToKeysym(QX11Info::display(), keyCodeX, 0);
0933         // TODO: what's the xor operator in c++?
0934         // If this is a keypad key,
0935         if (sym >= XK_KP_Space && sym <= XK_KP_9) {
0936             switch (sym) {
0937             // Leave the following keys unaltered
0938             // FIXME: The proper solution is to see which keysyms don't change when shifted.
0939             case XK_KP_Multiply:
0940             case XK_KP_Add:
0941             case XK_KP_Subtract:
0942             case XK_KP_Divide:
0943                 break;
0944             default:
0945                 if (keyModX & modXShift()) {
0946                     keyModX &= ~modXShift();
0947                 } else {
0948                     keyModX |= modXShift();
0949                 }
0950             }
0951         }
0952     }
0953 
0954     return KKeyServer::symXModXToKeyQt(keySymX, keyModX, keyQt);
0955 }
0956 
0957 bool xcbKeyPressEventToQt(xcb_generic_event_t *e, int *keyQt)
0958 {
0959     if ((e->response_type & ~0x80) != XCB_KEY_PRESS && (e->response_type & ~0x80) != XCB_KEY_RELEASE) {
0960         return false;
0961     }
0962     return xcbKeyPressEventToQt(reinterpret_cast<xcb_key_press_event_t *>(e), keyQt);
0963 }
0964 
0965 bool xcbKeyPressEventToQt(xcb_key_press_event_t *e, int *keyQt)
0966 {
0967     const uint16_t keyModX = e->state & (accelModMaskX() | MODE_SWITCH);
0968 
0969     xcb_key_symbols_t *symbols = xcb_key_symbols_alloc(QX11Info::connection());
0970 
0971     // We might have to use 4,5 instead of 0,1 here when mode_switch is active, just not sure how to test that.
0972     const xcb_keysym_t keySym0 = xcb_key_press_lookup_keysym(symbols, e, 0);
0973     const xcb_keysym_t keySym1 = xcb_key_press_lookup_keysym(symbols, e, 1);
0974     xcb_keysym_t keySymX;
0975 
0976     if ((e->state & KKeyServer::modXNumLock()) && is_keypad_key(keySym1)) {
0977         if ((e->state & XCB_MOD_MASK_SHIFT)) {
0978             keySymX = keySym0;
0979         } else {
0980             keySymX = keySym1;
0981         }
0982     } else {
0983         keySymX = keySym0;
0984     }
0985 
0986     bool ok = KKeyServer::symXModXToKeyQt(keySymX, keyModX, keyQt);
0987 
0988     if ((*keyQt & Qt::ShiftModifier) && !KKeyServer::isShiftAsModifierAllowed(*keyQt)) {
0989         if (*keyQt != Qt::Key_Tab) { // KKeySequenceWidget does not map shift+tab to backtab
0990             static const int FirstLevelShift = 1;
0991             keySymX = xcb_key_symbols_get_keysym(symbols, e->detail, FirstLevelShift);
0992             KKeyServer::symXModXToKeyQt(keySymX, keyModX, keyQt);
0993         }
0994         *keyQt &= ~Qt::ShiftModifier;
0995     }
0996 
0997     xcb_key_symbols_free(symbols);
0998     return ok;
0999 }
1000 
1001 } // end of namespace KKeyServer block