File indexing completed on 2024-04-28 05:52:14

0001 // SPDX-License-Identifier: LGPL-2.1-only
0002 
0003 #include "qglobalshortcut.h"
0004 #include <QKeySequence>
0005 #include <QX11Info>
0006 #include <QApplication>
0007 #include <xcb/xcb.h>
0008 #include <X11/Xlib.h>
0009 #include <X11/keysym.h>
0010 
0011 bool QGlobalShortcut::QGlobalShortcutEventFilter::nativeEventFilter(
0012         const QByteArray& eventType, void* message, long* result)
0013 {
0014     if (eventType != "xcb_generic_event_t") {
0015         return false;
0016     }
0017 
0018     xcb_generic_event_t* e = static_cast<xcb_generic_event_t*>(message);
0019     if ((e->response_type & ~0x80) == XCB_KEY_PRESS) {
0020         xcb_key_press_event_t* ke = (xcb_key_press_event_t*)e;
0021         xcb_get_keyboard_mapping_reply_t rep;
0022         xcb_keysym_t* k = xcb_get_keyboard_mapping_keysyms(&rep);
0023         quint32 keycode = ke->detail;
0024         quint32 mods = ke->state & (ShiftMask|ControlMask|Mod1Mask|Mod3Mask);
0025         return activate(calcId(keycode, mods));
0026     }
0027     return false;
0028 }
0029 
0030 quint32 QGlobalShortcut::calcId(quint32 k, quint32 m) {
0031     return k | (m << 16);
0032 }
0033 
0034 quint32 QGlobalShortcut::toNativeKeycode(Qt::Key k) {
0035     if (qApp->closingDown()) {
0036         return 0;
0037     }
0038     /* keysymdef.h */
0039     quint32 key = 0;
0040     if (k >= Qt::Key_F1 && k <= Qt::Key_F35) {
0041         key = XK_F1 + (k - Qt::Key_F1);
0042     } else if (k >= Qt::Key_Space && k <= Qt::Key_QuoteLeft) {
0043         key = k;
0044     } else if (k >= Qt::Key_BraceLeft && k <= Qt::Key_AsciiTilde) {
0045         key = k;
0046     } else if (k >= Qt::Key_nobreakspace && k <= Qt::Key_ydiaeresis) {
0047         key = k;
0048     } else {
0049         switch (k) {
0050         case Qt::Key_Escape:
0051             key = XK_Escape;
0052             break;
0053         case Qt::Key_Tab:
0054         case Qt::Key_Backtab:
0055             key = XK_Tab;
0056             break;
0057         case Qt::Key_Backspace:
0058             key = XK_BackSpace;
0059             break;
0060         case Qt::Key_Return:
0061         case Qt::Key_Enter:
0062             key = XK_Return;
0063             break;
0064         case Qt::Key_Insert:
0065             key = XK_Insert;
0066             break;
0067         case Qt::Key_Delete:
0068             key = XK_Delete;
0069             break;
0070         case Qt::Key_Pause:
0071             key = XK_Pause;
0072             break;
0073         case Qt::Key_Print:
0074             key = XK_Print;
0075             break;
0076         case Qt::Key_SysReq:
0077             key = XK_Sys_Req;
0078             break;
0079         case Qt::Key_Clear:
0080             key = XK_Clear;
0081             break;
0082         case Qt::Key_Home:
0083             key = XK_Home;
0084             break;
0085         case Qt::Key_End:
0086             key = XK_End;
0087             break;
0088         case Qt::Key_Left:
0089             key = XK_Left;
0090             break;
0091         case Qt::Key_Up:
0092             key = XK_Up;
0093             break;
0094         case Qt::Key_Right:
0095             key = XK_Right;
0096             break;
0097         case Qt::Key_Down:
0098             key = XK_Down;
0099             break;
0100         case Qt::Key_PageUp:
0101             key = XK_Page_Up;
0102             break;
0103         case Qt::Key_PageDown:
0104             key = XK_Page_Down;
0105             break;
0106         default:
0107             key = 0;
0108         }
0109     }
0110     return XKeysymToKeycode(QX11Info::display(), key);
0111 }
0112 
0113 quint32 QGlobalShortcut::toNativeModifiers(Qt::KeyboardModifiers m) {
0114     quint32 mods = Qt::NoModifier;
0115     if (m & Qt::ShiftModifier)
0116         mods |= ShiftMask;
0117     if (m & Qt::ControlModifier)
0118         mods |= ControlMask;
0119     if (m & Qt::AltModifier)
0120         mods |= Mod1Mask;
0121     if (m & Qt::MetaModifier)
0122         mods |= Mod4Mask;
0123     return mods;
0124 }
0125 
0126 void QGlobalShortcut::registerKey(quint32 k, quint32 m, quint32 id) {
0127     if (qApp->closingDown()) {
0128         return;
0129     }
0130 
0131     xcb_grab_key(QX11Info::connection(), 1, QX11Info::appRootWindow(),
0132                  m, k, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
0133 }
0134 
0135 void QGlobalShortcut::unregisterKey(quint32 k, quint32 m, quint32 id) {
0136     // this function is called in the destructor, and if that is called during
0137     // quitting QX11Info has already been destroyed.
0138     if (qApp->closingDown()) {
0139         return;
0140     }
0141     xcb_ungrab_key(QX11Info::connection(), k, QX11Info::appRootWindow(), m);
0142 }