2
* globalaccelman_mac.cpp - manager for global hotkeys
3
* Copyright (C) 2003 Eric Smith
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
// - don't invoke hotkey if there is a modal dialog?
23
// - do multi-mapping, like the x11 version
25
#include"globalaccelman.h"
27
#include<qkeysequence.h>
31
#include <Carbon/Carbon.h>
36
short transtable[256];
41
/* InitAscii2KeyCodeTable initializes the ascii to key code
42
look up table using the currently active KCHR resource. This
43
routine calls GetResource so it cannot be called at interrupt time.*/
44
OSStatus InitAscii2KeyCodeTable(Ascii2KeyCodeTable *ttable);
46
/* ValidateAscii2KeyCodeTable verifies that the ascii to key code
47
lookup table is synchronized with the current KCHR resource. If
48
it is not synchronized, then the table is re-built. This routine calls
49
GetResource so it cannot be called at interrupt time.*/
50
OSStatus ValidateAscii2KeyCodeTable(Ascii2KeyCodeTable *ttable,Boolean *wasChanged);
52
/* AsciiToKeyCode looks up the ascii character in the key
53
code look up table and returns the virtual key code for that
54
letter. If there is no virtual key code for that letter, then
55
the value -1 will be returned. */
56
short AsciiToKeyCode(Ascii2KeyCodeTable *ttable, short asciiCode);
59
kTableCountOffset = 256+2,
60
kFirstTableOffset = 256+4,
64
OSStatus InitAscii2KeyCodeTable(Ascii2KeyCodeTable *ttable) {
65
unsigned char *theCurrentKCHR, *ithKeyTable;
66
short count, i, j, resID;
69
/* set up our table to all minus ones */
70
for (i=0;i<256; i++) ttable->transtable[i] = -1;
71
/* find the current kchr resource ID */
72
ttable->kchrID = (short) GetScriptVariable(smCurrentScript, smScriptKeys);
73
/* get the current KCHR resource */
74
theKCHRRsrc = GetResource('KCHR', ttable->kchrID);
75
if (theKCHRRsrc == NULL) return resNotFound;
76
GetResInfo(theKCHRRsrc,&resID,&rType,ttable->KCHRname);
77
/* dereference the resource */
78
theCurrentKCHR = (unsigned char *) (*theKCHRRsrc);
79
/* get the count from the resource */
80
count = * (short *) (theCurrentKCHR + kTableCountOffset);
81
/* build inverse table by merging all key tables */
82
for (i=0; i<count; i++) {
83
ithKeyTable = theCurrentKCHR + kFirstTableOffset + (i * kTableSize);
84
for (j=0; j<kTableSize; j++) {
85
if ( ttable->transtable[ ithKeyTable[j] ] == -1)
86
ttable->transtable[ ithKeyTable[j] ] = j;
94
// Should probably call this at some point, in case the user has switched keyboard
95
// layouts while we were running.
96
OSStatus ValidateAscii2KeyCodeTable(Ascii2KeyCodeTable *ttable,Boolean *wasChanged) {
98
theID = (short) GetScriptVariable(smCurrentScript, smScriptKeys);
99
if (theID != ttable->kchrID)
102
return InitAscii2KeyCodeTable(ttable);
111
short AsciiToKeyCode(Ascii2KeyCodeTable *ttable, short asciiCode) {
112
if (asciiCode >= 0 && asciiCode <= 255)
113
return ttable->transtable[asciiCode];
119
char KeyCodeToAscii(short virtualKeyCode) {
125
kchr = (Ptr) GetScriptVariable(smCurrentScript, smKCHRCache);
126
keyTrans = KeyTranslate(kchr, virtualKeyCode, &state);
128
if (!charCode) charCode = (keyTrans>>16);
133
EventHotKeyID hotKeyID = {
142
MacHotKey(EventHotKeyRef _ref, int _id)
150
UnregisterEventHotKey(hot_key_ref);
153
EventHotKeyRef hot_key_ref;
154
int id; // GlobalAccelManager unique ID for this hotkey
158
// The following table is from Apple sample-code.
159
// Apple's headers don't appear to define any constants for the virtual key
160
// codes of special keys, but these constants are somewhat documented in the chart at
161
// <http://developer.apple.com/techpubs/mac/Text/Text-571.html#MARKER-9-18>
163
// The constants on the chartappear to be the same values as are used in Apple's iGetKeys
165
// <http://developer.apple.com/samplecode/Sample_Code/Human_Interface_Toolbox/Mac_OS_High_Level_Toolbox/iGetKeys.htm>.
167
// See also <http://www.mactech.com/articles/mactech/Vol.04/04.12/Macinkeys/>.
174
{ Qt::Key_Escape, 0x35 },
175
{ Qt::Key_Tab, 0x30 },
176
{ Qt::Key_Backtab, 0 },
177
{ Qt::Key_Backspace, 0x33 },
178
{ Qt::Key_Return, 0x24 },
179
{ Qt::Key_Enter, 0x4c }, // Return & Enter are different on the Mac
180
{ Qt::Key_Insert, 0 },
181
{ Qt::Key_Delete, 0x75 },
182
{ Qt::Key_Pause, 0 },
183
{ Qt::Key_Print, 0 },
184
{ Qt::Key_SysReq, 0 },
185
{ Qt::Key_Clear, 0x47 },
186
{ Qt::Key_Home, 0x73 },
187
{ Qt::Key_End, 0x77 },
188
{ Qt::Key_Left, 0x7b },
189
{ Qt::Key_Up, 0x7e },
190
{ Qt::Key_Right, 0x7c },
191
{ Qt::Key_Down, 0x7d },
192
{ Qt::Key_Prior, 0x74 }, // Page Up
193
{ Qt::Key_Next, 0x79 }, // Page Down
194
{ Qt::Key_Shift, 0x38 },
195
{ Qt::Key_Control, 0x3b },
196
{ Qt::Key_Meta, 0x37 }, // Command
197
{ Qt::Key_Alt, 0x3a }, // Option
198
{ Qt::Key_CapsLock, 57 },
199
{ Qt::Key_NumLock, 0 },
200
{ Qt::Key_ScrollLock, 0 },
201
{ Qt::Key_F1, 0x7a },
202
{ Qt::Key_F2, 0x78 },
203
{ Qt::Key_F3, 0x63 },
204
{ Qt::Key_F4, 0x76 },
205
{ Qt::Key_F5, 0x60 },
206
{ Qt::Key_F6, 0x61 },
207
{ Qt::Key_F7, 0x62 },
208
{ Qt::Key_F8, 0x64 },
209
{ Qt::Key_F9, 0x65 },
210
{ Qt::Key_F10, 0x6d },
211
{ Qt::Key_F11, 0x67 },
212
{ Qt::Key_F12, 0x6f },
213
{ Qt::Key_F13, 0x69 },
214
{ Qt::Key_F14, 0x6b },
215
{ Qt::Key_F15, 0x71 },
236
{ Qt::Key_Super_L, 0 },
237
{ Qt::Key_Super_R, 0 },
239
{ Qt::Key_Hyper_L, 0 },
240
{ Qt::Key_Hyper_R, 0 },
241
{ Qt::Key_Help, 0x72 },
242
{ Qt::Key_Direction_L,0 },
243
{ Qt::Key_Direction_R,0 },
245
{ Qt::Key_unknown, 0 }
249
class GlobalAccelManager::Private
252
Private(GlobalAccelManager *par)
255
list.setAutoDelete(true);
257
InitAscii2KeyCodeTable(&key_codes);
258
hot_key_function = NewEventHandlerUPP(HotKeyHandler);
260
type.eventClass = kEventClassKeyboard;
261
type.eventKind = kEventHotKeyPressed;
262
InstallApplicationEventHandler(hot_key_function, 1, &type, par, NULL);
269
static pascal OSStatus HotKeyHandler(EventHandlerCallRef /*nextHandler*/, EventRef theEvent, void *userData);
272
bool convertKeySequence(const QKeySequence &ks, UInt32 *_mod, UInt32 *_key)
288
for(int n = 0; qt_key_map[n].qt_key != Qt::Key_unknown; ++n) {
289
if(qt_key_map[n].qt_key == code) {
290
key = qt_key_map[n].mac_key;
295
key = AsciiToKeyCode(&key_codes, code & 0xffff);
307
int insertHotKey(int key, int mod)
309
EventHotKeyID hotKeyID;
310
hotKeyID.signature = 'QtHK';
311
hotKeyID.id = id_at++;
312
EventHotKeyRef hotKeyRef = 0;
314
OSStatus foo = RegisterEventHotKey(key, mod, hotKeyID, GetApplicationEventTarget(), 0, &hotKeyRef);
316
fprintf(stderr, "RegisterEventHotKey(%x,%x) returned %ld\n", key, mod, foo);
320
MacHotKey *hk = new MacHotKey(hotKeyRef, hotKeyID.id);
327
QPtrList<MacHotKey> list;
328
EventHandlerUPP hot_key_function;
329
Ascii2KeyCodeTable key_codes;
333
// Callback function invoked when the user hits a hot-key.
334
pascal OSStatus GlobalAccelManager::Private::HotKeyHandler(EventHandlerCallRef /*nextHandler*/, EventRef theEvent, void *userData)
337
GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(EventHotKeyID), NULL, &hkID);
338
reinterpret_cast<GlobalAccelManager*>(userData)->triggerActivated(hkID.id);
343
GlobalAccelManager::GlobalAccelManager()
345
d = new Private(this);
348
GlobalAccelManager::~GlobalAccelManager()
353
int GlobalAccelManager::setAccel(const QKeySequence &ks)
357
if(!d->convertKeySequence(ks, &mod, &key))
360
return d->insertHotKey(key, mod);
363
void GlobalAccelManager::removeAccel(int id)
365
QPtrListIterator<MacHotKey> it(d->list);
366
for(MacHotKey *hk = 0; (hk = it.current()); ++it) {
368
d->list.removeRef(hk);