diff options
Diffstat (limited to 'qxt-mini/qxtglobalshortcut_mac.cpp')
| -rw-r--r-- | qxt-mini/qxtglobalshortcut_mac.cpp | 271 | 
1 files changed, 271 insertions, 0 deletions
| diff --git a/qxt-mini/qxtglobalshortcut_mac.cpp b/qxt-mini/qxtglobalshortcut_mac.cpp new file mode 100644 index 00000000..34de694e --- /dev/null +++ b/qxt-mini/qxtglobalshortcut_mac.cpp @@ -0,0 +1,271 @@ +#ifdef __APPLE__ +#define QXT_BUILD +#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> +*****************************************************************************/ + +#pragma GCC diagnostic ignored "-Wfour-char-constants" +#pragma GCC diagnostic ignored "-Wunused-parameter" + +#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); +	if(id != Identifier()) +		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) +    { +	qxt_mac_handler_installed = true; +        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); +} +bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType, +    void *message, long *result) +{ +    return false; +} +#endif | 
