e7dacea969dab81a8e49e74d67868b01bcdc42f9
[quassel.git] / src / contrib / libqxt-2007-10-24 / src / gui / qxtapplication_mac.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) Qxt Foundation. Some rights reserved.
4 **
5 ** This file is part of the QxtGui module of the Qt eXTension library
6 **
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
9 ** IBM.
10 **
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.
15 **
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.
20 **
21 ** <http://libqxt.sourceforge.net>  <foundation@libqxt.org>
22 **
23 ****************************************************************************/
24 #include <Carbon/Carbon.h>
25 #include "qxtapplication.h"
26 #include "qxtapplication_p.h"
27 #include <QKeySequence>
28 #include <QMap>
29 #include <QtDebug>
30
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;
35
36 OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data)
37 {
38     // pass event to the app event filter
39     qApp->macEventFilter(nextHandler, event);
40     return noErr;
41 }
42
43 bool QxtApplication::macEventFilter(EventHandlerCallRef caller, EventRef event)
44 {
45     foreach (QxtNativeEventFilter* filter, qxt_d().nativeFilters)
46     {
47         if (filter && filter->macEventFilter(caller, event))
48             return true;
49     }
50
51     if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed)
52     {
53         EventHotKeyID keyID;
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);
57     }
58     return QApplication::macEventFilter(caller, event);
59 }
60
61 uint QxtApplicationPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) const
62 {
63     uint native = 0;
64     if (modifiers & Qt::ShiftModifier)
65         native |= shiftKeyBit;
66     if (modifiers & Qt::ControlModifier)
67         native |= cmdKey;
68     if (modifiers & Qt::AltModifier)
69         native |= optionKey;
70     if (modifiers & Qt::MetaModifier)
71         native |= controlKey;
72     if (modifiers & Qt::KeypadModifier)
73         native |= kEventKeyModifierNumLockMask;
74     return native;
75 }
76
77 uint QxtApplicationPrivate::nativeKeycode(Qt::Key key) const
78 {
79     UTF16Char ch;
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;
107     else                                                                ch = key;
108
109     KeyboardLayoutRef layout;
110     KeyboardLayoutKind layoutKind;
111     KLGetCurrentKeyboardLayout(&layout);
112     KLGetKeyboardLayoutProperty(layout, kKLKind, const_cast<const void**>(reinterpret_cast<void**>(&layoutKind)));
113
114     if (layoutKind == kKLKCHRKind)
115     { // no Unicode available
116         if (ch > 255) return 0;
117
118         char* data;
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++)
122         {
123             char* keyTable = data + 260 + 128 * i;
124             for (int j = 0; j < 128; j++)
125             {
126                 if (keyTable[j] == ch) return j;
127             }
128         }
129
130         return 0;
131     }
132
133     char* data;
134     KLGetKeyboardLayoutProperty(layout, kKLuchrData, const_cast<const void**>(reinterpret_cast<void**>(&data)));
135     UCKeyboardLayout* header = reinterpret_cast<UCKeyboardLayout*>(data);
136     UCKeyboardTypeHeader* table = header->keyboardTypeList;
137
138     for (uint i=0; i < header->keyboardTypeCount; i++)
139     {
140         UCKeyStateRecordsIndex* stateRec = 0;
141         if (table[i].keyStateRecordsIndexOffset != 0)
142         {
143             stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(data + table[i].keyStateRecordsIndexOffset);
144             if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0;
145         }
146
147         UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(data + table[i].keyToCharTableIndexOffset);
148         if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue;
149
150         for (uint j=0; j < charTable->keyToCharTableCount; j++)
151         {
152             UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(data + charTable->keyToCharTableOffsets[j]);
153             for (uint k=0; k < charTable->keyToCharTableSize; k++)
154             {
155                 if (keyToChar[k] & kUCKeyOutputTestForIndexMask)
156                 {
157                     long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;
158                     if (stateRec && idx < stateRec->keyStateRecordCount)
159                     {
160                         UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(data + stateRec->keyStateRecordOffsets[idx]);
161                         if (rec->stateZeroCharData == ch) return k;
162                     }
163                 }
164                 else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE)
165                 {
166                     if (keyToChar[k] == ch) return k;
167                 }
168             } // for k
169         } // for j
170     } // for i
171
172     return 0;
173 }
174
175 bool QxtApplicationPrivate::registerHotKey(uint modifiers, uint keycode, QWidget* receiver)
176 {
177     Q_UNUSED(receiver);
178
179     if (!qxt_mac_handler_installed)
180     {
181         EventTypeSpec t;
182         t.eventClass = kEventClassKeyboard;
183         t.eventKind = kEventHotKeyPressed;
184         InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, NULL, NULL);
185     }
186
187     EventHotKeyID keyID;
188     keyID.signature = 'cute';
189     keyID.id = ++hotKeySerial;
190
191     EventHotKeyRef ref = 0;
192     bool rv = !RegisterEventHotKey(keycode, modifiers, keyID, GetApplicationEventTarget(), 0, &ref);
193     if (rv)
194     {
195         keyIDs.insert(Identifier(modifiers, keycode), keyID.id);
196         keyRefs.insert(keyID.id, ref);
197     }
198     qDebug() << ref;
199     return rv;
200 }
201
202 bool QxtApplicationPrivate::unregisterHotKey(uint modifiers, uint keycode, QWidget* receiver)
203 {
204     Q_UNUSED(receiver);
205
206     Identifier id(modifiers, keycode);
207     if (!keyIDs.contains(id)) return false;
208
209     EventHotKeyRef ref = keyRefs.take(keyIDs[id]);
210     keyIDs.remove(id);
211     return !UnregisterEventHotKey(ref);
212 }