1 /****************************************************************************
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
5 ** This file is part of the QxtGui module of the Qt eXTension library
7 ** This library is free software; you can redistribute it and/or modify it
8 ** under the terms of th Common Public License, version 1.0, as published by
11 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
12 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
13 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
14 ** FITNESS FOR A PARTICULAR PURPOSE.
16 ** You should have received a copy of the CPL along with this file.
17 ** See the LICENSE file and the cpl1.0.txt file included with the source
18 ** distribution for more information. If you did not receive a copy of the
19 ** license, contact the Qxt Foundation.
21 ** <http://libqxt.sourceforge.net> <foundation@libqxt.org>
23 ****************************************************************************/
24 #include <Carbon/Carbon.h>
25 #include "qxtapplication.h"
26 #include "qxtapplication_p.h"
27 #include <QKeySequence>
31 static QMap<quint32, EventHotKeyRef> keyRefs;
32 static QHash<Identifier, quint32> keyIDs;
33 static quint32 hotKeySerial = 0;
34 static bool qxt_mac_handler_installed = false;
36 OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data)
38 // pass event to the app event filter
39 qApp->macEventFilter(nextHandler, event);
43 bool QxtApplication::macEventFilter(EventHandlerCallRef caller, EventRef event)
45 foreach (QxtNativeEventFilter* filter, qxt_d().nativeFilters)
47 if (filter && filter->macEventFilter(caller, event))
51 if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed)
54 GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(keyID), NULL, &keyID);
55 Identifier id = keyIDs.key(keyID.id);
56 qxt_d().activateHotKey(id.first, id.second);
58 return QApplication::macEventFilter(caller, event);
61 uint QxtApplicationPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) const
64 if (modifiers & Qt::ShiftModifier)
65 native |= shiftKeyBit;
66 if (modifiers & Qt::ControlModifier)
68 if (modifiers & Qt::AltModifier)
70 if (modifiers & Qt::MetaModifier)
72 if (modifiers & Qt::KeypadModifier)
73 native |= kEventKeyModifierNumLockMask;
77 uint QxtApplicationPrivate::nativeKeycode(Qt::Key key) const
80 // Constants found in NSEvent.h from AppKit.framework
81 if (key == Qt::Key_Up) ch = 0xF700;
82 else if (key == Qt::Key_Down) ch = 0xF701;
83 else if (key == Qt::Key_Left) ch = 0xF702;
84 else if (key == Qt::Key_Right) ch = 0xF703;
85 else if (key >= Qt::Key_F1 && key <= Qt::Key_F35)
86 ch = key - Qt::Key_F1 + 0xF704;
87 else if (key == Qt::Key_Insert) ch = 0xF727;
88 else if (key == Qt::Key_Delete) ch = 0xF728;
89 else if (key == Qt::Key_Home) ch = 0xF729;
90 else if (key == Qt::Key_End) ch = 0xF72B;
91 else if (key == Qt::Key_PageUp) ch = 0xF72C;
92 else if (key == Qt::Key_PageDown) ch = 0xF72D;
93 else if (key == Qt::Key_Print) ch = 0xF72E;
94 else if (key == Qt::Key_ScrollLock) ch = 0xF72F;
95 else if (key == Qt::Key_Pause) ch = 0xF730;
96 else if (key == Qt::Key_SysReq) ch = 0xF731;
97 else if (key == Qt::Key_Stop) ch = 0xF734;
98 else if (key == Qt::Key_Menu) ch = 0xF735;
99 else if (key == Qt::Key_Select) ch = 0xF741;
100 else if (key == Qt::Key_Execute) ch = 0xF742;
101 else if (key == Qt::Key_Help) ch = 0xF746;
102 else if (key == Qt::Key_Mode_switch) ch = 0xF747;
103 else if (key == Qt::Key_Escape) ch = 27;
104 else if (key == Qt::Key_Return) ch = 13;
105 else if (key == Qt::Key_Enter) ch = 3;
106 else if (key == Qt::Key_Tab) ch = 9;
109 KeyboardLayoutRef layout;
110 KeyboardLayoutKind layoutKind;
111 KLGetCurrentKeyboardLayout(&layout);
112 KLGetKeyboardLayoutProperty(layout, kKLKind, const_cast<const void**>(reinterpret_cast<void**>(&layoutKind)));
114 if (layoutKind == kKLKCHRKind)
115 { // no Unicode available
116 if (ch > 255) return 0;
119 KLGetKeyboardLayoutProperty(layout, kKLKCHRData, const_cast<const void**>(reinterpret_cast<void**>(&data)));
120 int ct = *reinterpret_cast<short*>(data + 258);
121 for (int i = 0; i < ct; i++)
123 char* keyTable = data + 260 + 128 * i;
124 for (int j = 0; j < 128; j++)
126 if (keyTable[j] == ch) return j;
134 KLGetKeyboardLayoutProperty(layout, kKLuchrData, const_cast<const void**>(reinterpret_cast<void**>(&data)));
135 UCKeyboardLayout* header = reinterpret_cast<UCKeyboardLayout*>(data);
136 UCKeyboardTypeHeader* table = header->keyboardTypeList;
138 for (uint i=0; i < header->keyboardTypeCount; i++)
140 UCKeyStateRecordsIndex* stateRec = 0;
141 if (table[i].keyStateRecordsIndexOffset != 0)
143 stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(data + table[i].keyStateRecordsIndexOffset);
144 if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0;
147 UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(data + table[i].keyToCharTableIndexOffset);
148 if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue;
150 for (uint j=0; j < charTable->keyToCharTableCount; j++)
152 UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(data + charTable->keyToCharTableOffsets[j]);
153 for (uint k=0; k < charTable->keyToCharTableSize; k++)
155 if (keyToChar[k] & kUCKeyOutputTestForIndexMask)
157 long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;
158 if (stateRec && idx < stateRec->keyStateRecordCount)
160 UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(data + stateRec->keyStateRecordOffsets[idx]);
161 if (rec->stateZeroCharData == ch) return k;
164 else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE)
166 if (keyToChar[k] == ch) return k;
175 bool QxtApplicationPrivate::registerHotKey(uint modifiers, uint keycode, QWidget* receiver)
179 if (!qxt_mac_handler_installed)
182 t.eventClass = kEventClassKeyboard;
183 t.eventKind = kEventHotKeyPressed;
184 InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, NULL, NULL);
188 keyID.signature = 'cute';
189 keyID.id = ++hotKeySerial;
191 EventHotKeyRef ref = 0;
192 bool rv = !RegisterEventHotKey(keycode, modifiers, keyID, GetApplicationEventTarget(), 0, &ref);
195 keyIDs.insert(Identifier(modifiers, keycode), keyID.id);
196 keyRefs.insert(keyID.id, ref);
202 bool QxtApplicationPrivate::unregisterHotKey(uint modifiers, uint keycode, QWidget* receiver)
206 Identifier id(modifiers, keycode);
207 if (!keyIDs.contains(id)) return false;
209 EventHotKeyRef ref = keyRefs.take(keyIDs[id]);
211 return !UnregisterEventHotKey(ref);