qxtglobalshortcut_x11.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. #include "qxtglobalshortcut_p.h"
  2. /****************************************************************************
  3. ** Copyright (c) 2006 - 2011, the LibQxt project.
  4. ** See the Qxt AUTHORS file for a list of authors and copyright holders.
  5. ** All rights reserved.
  6. **
  7. ** Redistribution and use in source and binary forms, with or without
  8. ** modification, are permitted provided that the following conditions are met:
  9. ** * Redistributions of source code must retain the above copyright
  10. ** notice, this list of conditions and the following disclaimer.
  11. ** * Redistributions in binary form must reproduce the above copyright
  12. ** notice, this list of conditions and the following disclaimer in the
  13. ** documentation and/or other materials provided with the distribution.
  14. ** * Neither the name of the LibQxt project nor the
  15. ** names of its contributors may be used to endorse or promote products
  16. ** derived from this software without specific prior written permission.
  17. **
  18. ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. ** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  22. ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. **
  29. ** <http://libqxt.org> <foundation@libqxt.org>
  30. *****************************************************************************/
  31. #include <QVector>
  32. #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
  33. # include <QX11Info>
  34. #else
  35. # include <QApplication>
  36. # include <qpa/qplatformnativeinterface.h>
  37. # include <xcb/xcb.h>
  38. #endif
  39. #include <X11/Xlib.h>
  40. namespace {
  41. const QVector<quint32> maskModifiers = QVector<quint32>()
  42. << 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
  43. typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event);
  44. class QxtX11ErrorHandler {
  45. public:
  46. static bool error;
  47. static int qxtX11ErrorHandler(Display *display, XErrorEvent *event)
  48. {
  49. Q_UNUSED(display);
  50. switch (event->error_code)
  51. {
  52. case BadAccess:
  53. case BadValue:
  54. case BadWindow:
  55. if (event->request_code == 33 /* X_GrabKey */ ||
  56. event->request_code == 34 /* X_UngrabKey */)
  57. {
  58. error = true;
  59. //TODO:
  60. //char errstr[256];
  61. //XGetErrorText(dpy, err->error_code, errstr, 256);
  62. }
  63. }
  64. return 0;
  65. }
  66. QxtX11ErrorHandler()
  67. {
  68. error = false;
  69. m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler);
  70. }
  71. ~QxtX11ErrorHandler()
  72. {
  73. XSetErrorHandler(m_previousErrorHandler);
  74. }
  75. private:
  76. X11ErrorHandler m_previousErrorHandler;
  77. };
  78. bool QxtX11ErrorHandler::error = false;
  79. class QxtX11Data {
  80. public:
  81. QxtX11Data()
  82. {
  83. #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
  84. m_display = QX11Info::display();
  85. #else
  86. QPlatformNativeInterface *native = qApp->platformNativeInterface();
  87. void *display = native->nativeResourceForScreen(QByteArray("display"),
  88. QGuiApplication::primaryScreen());
  89. m_display = reinterpret_cast<Display *>(display);
  90. #endif
  91. }
  92. bool isValid()
  93. {
  94. return m_display != 0;
  95. }
  96. Display *display()
  97. {
  98. Q_ASSERT(isValid());
  99. return m_display;
  100. }
  101. Window rootWindow()
  102. {
  103. return DefaultRootWindow(display());
  104. }
  105. bool grabKey(quint32 keycode, quint32 modifiers, Window window)
  106. {
  107. QxtX11ErrorHandler errorHandler;
  108. for (int i = 0; !errorHandler.error && i < maskModifiers.size(); ++i) {
  109. XGrabKey(display(), keycode, modifiers | maskModifiers[i], window, True,
  110. GrabModeAsync, GrabModeAsync);
  111. }
  112. if (errorHandler.error) {
  113. ungrabKey(keycode, modifiers, window);
  114. return false;
  115. }
  116. return true;
  117. }
  118. bool ungrabKey(quint32 keycode, quint32 modifiers, Window window)
  119. {
  120. QxtX11ErrorHandler errorHandler;
  121. foreach (quint32 maskMods, maskModifiers) {
  122. XUngrabKey(display(), keycode, modifiers | maskMods, window);
  123. }
  124. return !errorHandler.error;
  125. }
  126. private:
  127. Display *m_display;
  128. };
  129. } // namespace
  130. #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
  131. bool QxtGlobalShortcutPrivate::eventFilter(void *message)
  132. {
  133. XEvent *event = static_cast<XEvent *>(message);
  134. if (event->type == KeyPress)
  135. {
  136. XKeyEvent *key = reinterpret_cast<XKeyEvent *>(event);
  137. unsigned int keycode = key->keycode;
  138. unsigned int keystate = key->state;
  139. #else
  140. bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
  141. void *message, long *result)
  142. {
  143. Q_UNUSED(result);
  144. xcb_key_press_event_t *kev = 0;
  145. if (eventType == "xcb_generic_event_t") {
  146. xcb_generic_event_t *ev = static_cast<xcb_generic_event_t *>(message);
  147. if ((ev->response_type & 127) == XCB_KEY_PRESS)
  148. kev = static_cast<xcb_key_press_event_t *>(message);
  149. }
  150. if (kev != 0) {
  151. unsigned int keycode = kev->detail;
  152. unsigned int keystate = 0;
  153. if(kev->state & XCB_MOD_MASK_1)
  154. keystate |= Mod1Mask;
  155. if(kev->state & XCB_MOD_MASK_CONTROL)
  156. keystate |= ControlMask;
  157. if(kev->state & XCB_MOD_MASK_4)
  158. keystate |= Mod4Mask;
  159. if(kev->state & XCB_MOD_MASK_SHIFT)
  160. keystate |= ShiftMask;
  161. #endif
  162. activateShortcut(keycode,
  163. // Mod1Mask == Alt, Mod4Mask == Meta
  164. keystate & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask));
  165. }
  166. #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
  167. return prevEventFilter ? prevEventFilter(message) : false;
  168. #else
  169. return false;
  170. #endif
  171. }
  172. quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
  173. {
  174. // ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask
  175. quint32 native = 0;
  176. if (modifiers & Qt::ShiftModifier)
  177. native |= ShiftMask;
  178. if (modifiers & Qt::ControlModifier)
  179. native |= ControlMask;
  180. if (modifiers & Qt::AltModifier)
  181. native |= Mod1Mask;
  182. if (modifiers & Qt::MetaModifier)
  183. native |= Mod4Mask;
  184. // TODO: resolve these?
  185. //if (modifiers & Qt::MetaModifier)
  186. //if (modifiers & Qt::KeypadModifier)
  187. //if (modifiers & Qt::GroupSwitchModifier)
  188. return native;
  189. }
  190. quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
  191. {
  192. QxtX11Data x11;
  193. if (!x11.isValid())
  194. return 0;
  195. KeySym keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data());
  196. if (keysym == NoSymbol)
  197. keysym = static_cast<ushort>(key);
  198. return XKeysymToKeycode(x11.display(), keysym);
  199. }
  200. bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
  201. {
  202. QxtX11Data x11;
  203. return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
  204. }
  205. bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
  206. {
  207. QxtX11Data x11;
  208. return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
  209. }