diff options
| author | Stanislaw Halik <sthalik@misaki.pl> | 2013-10-15 08:54:37 +0200 | 
|---|---|---|
| committer | Stanislaw Halik <sthalik@misaki.pl> | 2013-10-15 08:54:37 +0200 | 
| commit | 5ef2679167e1dbe19f738587f1e59f812e38211b (patch) | |
| tree | 842e5ae1d1713b171d2f088cce8c405a50a371c5 /qxt-mini/plat | |
| parent | e384433c993ee062d6d4c1b1e0224dd870a6455f (diff) | |
import cut out qxtgui/global-shortcuts :( sorry guys!
Diffstat (limited to 'qxt-mini/plat')
| -rw-r--r-- | qxt-mini/plat/qxtglobalshortcut_mac.cpp | 258 | ||||
| -rw-r--r-- | qxt-mini/plat/qxtglobalshortcut_x11.cpp | 235 | 
2 files changed, 493 insertions, 0 deletions
| diff --git a/qxt-mini/plat/qxtglobalshortcut_mac.cpp b/qxt-mini/plat/qxtglobalshortcut_mac.cpp new file mode 100644 index 00000000..58b9a904 --- /dev/null +++ b/qxt-mini/plat/qxtglobalshortcut_mac.cpp @@ -0,0 +1,258 @@ +#include <Carbon/Carbon.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 "qxtglobalshortcut_p.h"
 +#include <QMap>
 +#include <QHash>
 +#include <QtDebug>
 +#include <QApplication>
 +
 +typedef QPair<uint, uint> Identifier;
 +static QMap<quint32, EventHotKeyRef> keyRefs;
 +static QHash<Identifier, quint32> keyIDs;
 +static quint32 hotKeySerial = 0;
 +static bool qxt_mac_handler_installed = false;
 +
 +OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data)
 +{
 +    Q_UNUSED(nextHandler);
 +    Q_UNUSED(data);
 +    if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed)
 +    {
 +        EventHotKeyID keyID;
 +        GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(keyID), NULL, &keyID);
 +        Identifier id = keyIDs.key(keyID.id);
 +        QxtGlobalShortcutPrivate::activateShortcut(id.second, id.first);
 +    }
 +    return noErr;
 +}
 +
 +quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers)
 +{
 +    quint32 native = 0;
 +    if (modifiers & Qt::ShiftModifier)
 +        native |= shiftKey;
 +    if (modifiers & Qt::ControlModifier)
 +        native |= cmdKey;
 +    if (modifiers & Qt::AltModifier)
 +        native |= optionKey;
 +    if (modifiers & Qt::MetaModifier)
 +        native |= controlKey;
 +    if (modifiers & Qt::KeypadModifier)
 +        native |= kEventKeyModifierNumLockMask;
 +    return native;
 +}
 +
 +quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key)
 +{
 +    UTF16Char ch;
 +    // Constants found in NSEvent.h from AppKit.framework
 +    switch (key)
 +    {
 +    case Qt::Key_Return:
 +        return kVK_Return;
 +    case Qt::Key_Enter:
 +        return kVK_ANSI_KeypadEnter;
 +    case Qt::Key_Tab:
 +        return kVK_Tab;
 +    case Qt::Key_Space:
 +        return kVK_Space;
 +    case Qt::Key_Backspace:
 +        return kVK_Delete;
 +    case Qt::Key_Control:
 +        return kVK_Command;
 +    case Qt::Key_Shift:
 +        return kVK_Shift;
 +    case Qt::Key_CapsLock:
 +        return kVK_CapsLock;
 +    case Qt::Key_Option:
 +        return kVK_Option;
 +    case Qt::Key_Meta:
 +        return kVK_Control;
 +    case Qt::Key_F17:
 +        return kVK_F17;
 +    case Qt::Key_VolumeUp:
 +        return kVK_VolumeUp;
 +    case Qt::Key_VolumeDown:
 +        return kVK_VolumeDown;
 +    case Qt::Key_F18:
 +        return kVK_F18;
 +    case Qt::Key_F19:
 +        return kVK_F19;
 +    case Qt::Key_F20:
 +        return kVK_F20;
 +    case Qt::Key_F5:
 +        return kVK_F5;
 +    case Qt::Key_F6:
 +        return kVK_F6;
 +    case Qt::Key_F7:
 +        return kVK_F7;
 +    case Qt::Key_F3:
 +        return kVK_F3;
 +    case Qt::Key_F8:
 +        return kVK_F8;
 +    case Qt::Key_F9:
 +        return kVK_F9;
 +    case Qt::Key_F11:
 +        return kVK_F11;
 +    case Qt::Key_F13:
 +        return kVK_F13;
 +    case Qt::Key_F16:
 +        return kVK_F16;
 +    case Qt::Key_F14:
 +        return kVK_F14;
 +    case Qt::Key_F10:
 +        return kVK_F10;
 +    case Qt::Key_F12:
 +        return kVK_F12;
 +    case Qt::Key_F15:
 +        return kVK_F15;
 +    case Qt::Key_Help:
 +        return kVK_Help;
 +    case Qt::Key_Home:
 +        return kVK_Home;
 +    case Qt::Key_PageUp:
 +        return kVK_PageUp;
 +    case Qt::Key_Delete:
 +        return kVK_ForwardDelete;
 +    case Qt::Key_F4:
 +        return kVK_F4;
 +    case Qt::Key_End:
 +        return kVK_End;
 +    case Qt::Key_F2:
 +        return kVK_F2;
 +    case Qt::Key_PageDown:
 +        return kVK_PageDown;
 +    case Qt::Key_F1:
 +        return kVK_F1;
 +    case Qt::Key_Left:
 +        return kVK_LeftArrow;
 +    case Qt::Key_Right:
 +        return kVK_RightArrow;
 +    case Qt::Key_Down:
 +        return kVK_DownArrow;
 +    case Qt::Key_Up:
 +        return kVK_UpArrow;
 +    default:
 +        ;
 +    }
 +
 +    if (key == Qt::Key_Escape)	ch = 27;
 +    else if (key == Qt::Key_Return) ch = 13;
 +    else if (key == Qt::Key_Enter) ch = 3;
 +    else if (key == Qt::Key_Tab) ch = 9;
 +    else ch = key;
 +
 +    CFDataRef currentLayoutData;
 +    TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
 +
 +    if (currentKeyboard == NULL)
 +        return 0;
 +
 +    currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
 +    CFRelease(currentKeyboard);
 +    if (currentLayoutData == NULL)
 +        return 0;
 +
 +    UCKeyboardLayout* header = (UCKeyboardLayout*)CFDataGetBytePtr(currentLayoutData);
 +    UCKeyboardTypeHeader* table = header->keyboardTypeList;
 +
 +    uint8_t *data = (uint8_t*)header;
 +    // God, would a little documentation for this shit kill you...
 +    for (quint32 i=0; i < header->keyboardTypeCount; i++)
 +    {
 +        UCKeyStateRecordsIndex* stateRec = 0;
 +        if (table[i].keyStateRecordsIndexOffset != 0)
 +        {
 +            stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(data + table[i].keyStateRecordsIndexOffset);
 +            if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0;
 +        }
 +
 +        UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(data + table[i].keyToCharTableIndexOffset);
 +        if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue;
 +
 +        for (quint32 j=0; j < charTable->keyToCharTableCount; j++)
 +        {
 +            UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(data + charTable->keyToCharTableOffsets[j]);
 +            for (quint32 k=0; k < charTable->keyToCharTableSize; k++)
 +            {
 +                if (keyToChar[k] & kUCKeyOutputTestForIndexMask)
 +                {
 +                    long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;
 +                    if (stateRec && idx < stateRec->keyStateRecordCount)
 +                    {
 +                        UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(data + stateRec->keyStateRecordOffsets[idx]);
 +                        if (rec->stateZeroCharData == ch) return k;
 +                    }
 +                }
 +                else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE)
 +                {
 +                    if (keyToChar[k] == ch) return k;
 +                }
 +            } // for k
 +        } // for j
 +    } // for i
 +    return 0;
 +}
 +
 +bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods)
 +{
 +    if (!qxt_mac_handler_installed)
 +    {
 +        EventTypeSpec t;
 +        t.eventClass = kEventClassKeyboard;
 +        t.eventKind = kEventHotKeyPressed;
 +        InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, NULL, NULL);
 +    }
 +
 +    EventHotKeyID keyID;
 +    keyID.signature = 'cute';
 +    keyID.id = ++hotKeySerial;
 +
 +    EventHotKeyRef ref = 0;
 +    bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref);
 +    if (rv)
 +    {
 +        keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id);
 +        keyRefs.insert(keyID.id, ref);
 +    }
 +    return rv;
 +}
 +
 +bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods)
 +{
 +    Identifier id(nativeMods, nativeKey);
 +    if (!keyIDs.contains(id)) return false;
 +
 +    EventHotKeyRef ref = keyRefs.take(keyIDs[id]);
 +    keyIDs.remove(id);
 +    return !UnregisterEventHotKey(ref);
 +}
 diff --git a/qxt-mini/plat/qxtglobalshortcut_x11.cpp b/qxt-mini/plat/qxtglobalshortcut_x11.cpp new file mode 100644 index 00000000..0c203dd8 --- /dev/null +++ b/qxt-mini/plat/qxtglobalshortcut_x11.cpp @@ -0,0 +1,235 @@ +#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>
 +#include <QApplication>
 +// include private header for great justice -sh 20131015
 +#include <X11/Xlib.h>
 +#include <xcb/xcb.h>
 +#include "qplatformnativeinterface.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));
 +    }
 +    return false;
 +}
 +
 +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());
 +}
 | 
