123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- #include "qxtglobalshortcut_p.h"
- /****************************************************************************
- ** Copyright (c) 2006 - 2011, the LibQxt project.
- ** See the Qxt AUTHORS file for a list of authors and copyright holders.
- ** All rights reserved.
- **
- ** Redistribution and use in source and binary forms, with or without
- ** modification, are permitted provided that the following conditions are met:
- ** * Redistributions of source code must retain the above copyright
- ** notice, this list of conditions and the following disclaimer.
- ** * Redistributions in binary form must reproduce the above copyright
- ** notice, this list of conditions and the following disclaimer in the
- ** documentation and/or other materials provided with the distribution.
- ** * Neither the name of the LibQxt project nor the
- ** names of its contributors may be used to endorse or promote products
- ** derived from this software without specific prior written permission.
- **
- ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- ** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
- ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- **
- ** <http://libqxt.org> <foundation@libqxt.org>
- *****************************************************************************/
- #include <QVector>
- #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
- # include <QX11Info>
- #else
- # include <QApplication>
- # include <qpa/qplatformnativeinterface.h>
- # include <xcb/xcb.h>
- #endif
- #include <X11/Xlib.h>
- namespace {
- const QVector<quint32> maskModifiers = QVector<quint32>()
- << 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask);
- typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event);
- class QxtX11ErrorHandler {
- public:
- static bool error;
- static int qxtX11ErrorHandler(Display *display, XErrorEvent *event)
- {
- Q_UNUSED(display);
- switch (event->error_code)
- {
- case BadAccess:
- case BadValue:
- case BadWindow:
- if (event->request_code == 33 /* X_GrabKey */ ||
- event->request_code == 34 /* X_UngrabKey */)
- {
- error = true;
- //TODO:
- //char errstr[256];
- //XGetErrorText(dpy, err->error_code, errstr, 256);
- }
- }
- return 0;
- }
- QxtX11ErrorHandler()
- {
- error = false;
- m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler);
- }
- ~QxtX11ErrorHandler()
- {
- XSetErrorHandler(m_previousErrorHandler);
- }
- private:
- X11ErrorHandler m_previousErrorHandler;
- };
- bool QxtX11ErrorHandler::error = false;
- class QxtX11Data {
- public:
- QxtX11Data()
- {
- #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
- m_display = QX11Info::display();
- #else
- QPlatformNativeInterface *native = qApp->platformNativeInterface();
- void *display = native->nativeResourceForScreen(QByteArray("display"),
- QGuiApplication::primaryScreen());
- m_display = reinterpret_cast<Display *>(display);
- #endif
- }
- bool isValid()
- {
- return m_display != 0;
- }
- Display *display()
- {
- Q_ASSERT(isValid());
- return m_display;
- }
- Window rootWindow()
- {
- return DefaultRootWindow(display());
- }
- bool grabKey(quint32 keycode, quint32 modifiers, Window window)
- {
- QxtX11ErrorHandler errorHandler;
- for (int i = 0; !errorHandler.error && i < maskModifiers.size(); ++i) {
- XGrabKey(display(), keycode, modifiers | maskModifiers[i], window, True,
- GrabModeAsync, GrabModeAsync);
- }
- if (errorHandler.error) {
- ungrabKey(keycode, modifiers, window);
- return false;
- }
- return true;
- }
- bool ungrabKey(quint32 keycode, quint32 modifiers, Window window)
- {
- QxtX11ErrorHandler errorHandler;
- foreach (quint32 maskMods, maskModifiers) {
- XUngrabKey(display(), keycode, modifiers | maskMods, window);
- }
- return !errorHandler.error;
- }
- private:
- Display *m_display;
- };
- } // namespace
- #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
- bool QxtGlobalShortcutPrivate::eventFilter(void *message)
- {
- XEvent *event = static_cast<XEvent *>(message);
- if (event->type == KeyPress)
- {
- XKeyEvent *key = reinterpret_cast<XKeyEvent *>(event);
- unsigned int keycode = key->keycode;
- unsigned int keystate = key->state;
- #else
- bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType,
- void *message, long *result)
- {
- Q_UNUSED(result);
- xcb_key_press_event_t *kev = 0;
- if (eventType == "xcb_generic_event_t") {
- xcb_generic_event_t *ev = static_cast<xcb_generic_event_t *>(message);
- if ((ev->response_type & 127) == XCB_KEY_PRESS)
- kev = static_cast<xcb_key_press_event_t *>(message);
- }
- if (kev != 0) {
- unsigned int keycode = kev->detail;
- unsigned int keystate = 0;
- if(kev->state & XCB_MOD_MASK_1)
- keystate |= Mod1Mask;
- if(kev->state & XCB_MOD_MASK_CONTROL)
- keystate |= ControlMask;
- if(kev->state & XCB_MOD_MASK_4)
- keystate |= Mod4Mask;
- if(kev->state & XCB_MOD_MASK_SHIFT)
- keystate |= ShiftMask;
- #endif
- activateShortcut(keycode,
- // Mod1Mask == Alt, Mod4Mask == Meta
- keystate & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask));
- }
- #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
- return prevEventFilter ? prevEventFilter(message) : false;
- #else
- return false;
- #endif
- }
- quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
- {
- // ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask
- quint32 native = 0;
- if (modifiers & Qt::ShiftModifier)
- native |= ShiftMask;
- if (modifiers & Qt::ControlModifier)
- native |= ControlMask;
- if (modifiers & Qt::AltModifier)
- native |= Mod1Mask;
- if (modifiers & Qt::MetaModifier)
- native |= Mod4Mask;
- // TODO: resolve these?
- //if (modifiers & Qt::MetaModifier)
- //if (modifiers & Qt::KeypadModifier)
- //if (modifiers & Qt::GroupSwitchModifier)
- return native;
- }
- quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
- {
- QxtX11Data x11;
- if (!x11.isValid())
- return 0;
- KeySym keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data());
- if (keysym == NoSymbol)
- keysym = static_cast<ushort>(key);
- return XKeysymToKeycode(x11.display(), keysym);
- }
- bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
- {
- QxtX11Data x11;
- return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow());
- }
- bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
- {
- QxtX11Data x11;
- return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow());
- }
|