~ubuntu-branches/ubuntu/quantal/psi/quantal

« back to all changes in this revision

Viewing changes to cutestuff/globalaccel/globalaccelman_mac.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2005-01-10 17:41:43 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050110174143-ltocv5zapl6blf5d
Tags: 0.9.3-1
* New upstream release
* Cleaned up debian/rules (some things are done by upstream Makefiles now)
* Fixed some lintian warnings:
  - removed executable bit from some .png files
  - moved psi.desktop to /usr/share/applications
* Updated menu files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * globalaccelman_mac.cpp - manager for global hotkeys
 
3
 * Copyright (C) 2003  Eric Smith
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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
 
18
 *
 
19
 */
 
20
 
 
21
// TODO:
 
22
//  - don't invoke hotkey if there is a modal dialog?
 
23
//  - do multi-mapping, like the x11 version
 
24
 
 
25
#include"globalaccelman.h"
 
26
 
 
27
#include<qkeysequence.h>
 
28
#include<qwidget.h>
 
29
#include<qptrlist.h>
 
30
 
 
31
#include <Carbon/Carbon.h>
 
32
 
 
33
typedef struct {
 
34
        short kchrID;
 
35
        Str255 KCHRname;
 
36
        short transtable[256];
 
37
} Ascii2KeyCodeTable;
 
38
 
 
39
 
 
40
 
 
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);
 
45
 
 
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);
 
51
 
 
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);
 
57
 
 
58
enum {
 
59
        kTableCountOffset = 256+2,
 
60
        kFirstTableOffset = 256+4,
 
61
        kTableSize = 128
 
62
};
 
63
 
 
64
OSStatus InitAscii2KeyCodeTable(Ascii2KeyCodeTable *ttable) {
 
65
        unsigned char *theCurrentKCHR, *ithKeyTable;
 
66
        short count, i, j, resID;
 
67
        Handle theKCHRRsrc;
 
68
        ResType rType;
 
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;
 
87
                }
 
88
        }
 
89
        /* all done */
 
90
        return noErr;
 
91
}
 
92
 
 
93
 
 
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) {
 
97
        short theID;
 
98
        theID = (short) GetScriptVariable(smCurrentScript, smScriptKeys);
 
99
        if (theID != ttable->kchrID)
 
100
        {
 
101
                *wasChanged=true;
 
102
                return InitAscii2KeyCodeTable(ttable);
 
103
        }
 
104
        else
 
105
        {
 
106
                *wasChanged=false;
 
107
                return noErr;
 
108
        }
 
109
}
 
110
 
 
111
short AsciiToKeyCode(Ascii2KeyCodeTable *ttable, short asciiCode) {
 
112
        if (asciiCode >= 0 && asciiCode <= 255)
 
113
                return ttable->transtable[asciiCode];
 
114
        else return false;
 
115
}
 
116
 
 
117
 
 
118
// Not used.
 
119
char KeyCodeToAscii(short virtualKeyCode) {
 
120
        unsigned long state;
 
121
        long keyTrans;
 
122
        char charCode;
 
123
        Ptr kchr;
 
124
        state = 0;
 
125
        kchr = (Ptr) GetScriptVariable(smCurrentScript, smKCHRCache);
 
126
        keyTrans = KeyTranslate(kchr, virtualKeyCode, &state);
 
127
        charCode = keyTrans;
 
128
        if (!charCode) charCode = (keyTrans>>16);
 
129
        return charCode;
 
130
}
 
131
 
 
132
 
 
133
EventHotKeyID hotKeyID = {
 
134
        'QtHK',
 
135
        0
 
136
};
 
137
 
 
138
 
 
139
class MacHotKey
 
140
{
 
141
public:
 
142
        MacHotKey(EventHotKeyRef _ref, int _id)
 
143
        {
 
144
                hot_key_ref = _ref;
 
145
                id = _id;
 
146
        }
 
147
 
 
148
        ~MacHotKey()
 
149
        {
 
150
                UnregisterEventHotKey(hot_key_ref);
 
151
        }
 
152
 
 
153
        EventHotKeyRef hot_key_ref;
 
154
        int id;         // GlobalAccelManager unique ID for this hotkey
 
155
};
 
156
 
 
157
 
 
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>
 
162
//
 
163
// The constants on the chartappear to be the same values as are used in Apple's iGetKeys
 
164
// sample.
 
165
// <http://developer.apple.com/samplecode/Sample_Code/Human_Interface_Toolbox/Mac_OS_High_Level_Toolbox/iGetKeys.htm>.
 
166
//
 
167
// See also <http://www.mactech.com/articles/mactech/Vol.04/04.12/Macinkeys/>.
 
168
//
 
169
struct QtKeyMap
 
170
{
 
171
        int qt_key;
 
172
        int mac_key;
 
173
} qt_key_map[] = {
 
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 },
 
216
        { Qt::Key_F16,        0 },
 
217
        { Qt::Key_F17,        0 },
 
218
        { Qt::Key_F18,        0 },
 
219
        { Qt::Key_F19,        0 },
 
220
        { Qt::Key_F20,        0 },
 
221
        { Qt::Key_F21,        0 },
 
222
        { Qt::Key_F22,        0 },
 
223
        { Qt::Key_F23,        0 },
 
224
        { Qt::Key_F24,        0 },
 
225
        { Qt::Key_F25,        0 },
 
226
        { Qt::Key_F26,        0 },
 
227
        { Qt::Key_F27,        0 },
 
228
        { Qt::Key_F28,        0 },
 
229
        { Qt::Key_F29,        0 },
 
230
        { Qt::Key_F30,        0 },
 
231
        { Qt::Key_F31,        0 },
 
232
        { Qt::Key_F32,        0 },
 
233
        { Qt::Key_F33,        0 },
 
234
        { Qt::Key_F34,        0 },
 
235
        { Qt::Key_F35,        0 },
 
236
        { Qt::Key_Super_L,    0 },
 
237
        { Qt::Key_Super_R,    0 },
 
238
        { Qt::Key_Menu,       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 },
 
244
 
 
245
        { Qt::Key_unknown,    0 }
 
246
};
 
247
 
 
248
 
 
249
class GlobalAccelManager::Private
 
250
{
 
251
public:
 
252
        Private(GlobalAccelManager *par)
 
253
        {
 
254
                id_at = 1;
 
255
                list.setAutoDelete(true);
 
256
 
 
257
                InitAscii2KeyCodeTable(&key_codes);
 
258
                hot_key_function = NewEventHandlerUPP(HotKeyHandler);
 
259
                EventTypeSpec type;
 
260
                type.eventClass = kEventClassKeyboard;
 
261
                type.eventKind = kEventHotKeyPressed;
 
262
                InstallApplicationEventHandler(hot_key_function, 1, &type, par, NULL);
 
263
        }
 
264
 
 
265
        ~Private() {
 
266
        }
 
267
 
 
268
private:
 
269
        static pascal OSStatus HotKeyHandler(EventHandlerCallRef /*nextHandler*/, EventRef theEvent, void *userData);
 
270
 
 
271
public:
 
272
        bool convertKeySequence(const QKeySequence &ks, UInt32 *_mod, UInt32 *_key)
 
273
{
 
274
        int code = ks[0];
 
275
 
 
276
        UInt32 mod = 0;
 
277
        if(code & Qt::META)
 
278
                mod |= cmdKey;
 
279
        if(code & Qt::SHIFT)
 
280
                mod |= shiftKey;
 
281
        if(code & Qt::CTRL)
 
282
                mod |= controlKey;
 
283
        if(code & Qt::ALT)
 
284
                mod |= optionKey;
 
285
 
 
286
        code &= 0xffff;
 
287
        UInt32 key = 0;
 
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;
 
291
                        break;
 
292
                }
 
293
        }
 
294
        if (key == 0) {
 
295
                key = AsciiToKeyCode(&key_codes, code & 0xffff);
 
296
        }
 
297
 
 
298
        if(_mod)
 
299
                *_mod = mod;
 
300
        if(_key)
 
301
                *_key = key;
 
302
 
 
303
        return true;
 
304
}
 
305
 
 
306
 
 
307
        int insertHotKey(int key, int mod)
 
308
        {
 
309
                EventHotKeyID hotKeyID;
 
310
                hotKeyID.signature = 'QtHK';
 
311
                hotKeyID.id = id_at++;
 
312
                EventHotKeyRef hotKeyRef = 0;
 
313
 
 
314
                OSStatus foo = RegisterEventHotKey(key, mod, hotKeyID, GetApplicationEventTarget(), 0, &hotKeyRef);
 
315
                if (foo != 0) {
 
316
                        fprintf(stderr, "RegisterEventHotKey(%x,%x) returned %ld\n", key, mod, foo);
 
317
                        return 0;
 
318
                }
 
319
 
 
320
                MacHotKey *hk = new MacHotKey(hotKeyRef, hotKeyID.id);
 
321
                list.append(hk);
 
322
                return hk->id;
 
323
        }
 
324
 
 
325
        
 
326
        int id_at;
 
327
        QPtrList<MacHotKey> list;
 
328
        EventHandlerUPP hot_key_function;
 
329
        Ascii2KeyCodeTable key_codes;
 
330
};
 
331
 
 
332
 
 
333
// Callback function invoked when the user hits a hot-key.
 
334
pascal OSStatus GlobalAccelManager::Private::HotKeyHandler(EventHandlerCallRef /*nextHandler*/, EventRef theEvent, void *userData)
 
335
{
 
336
        EventHotKeyID hkID;
 
337
        GetEventParameter(theEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(EventHotKeyID), NULL, &hkID);
 
338
        reinterpret_cast<GlobalAccelManager*>(userData)->triggerActivated(hkID.id);
 
339
        return noErr;
 
340
}
 
341
 
 
342
 
 
343
GlobalAccelManager::GlobalAccelManager()
 
344
{
 
345
        d = new Private(this);
 
346
}
 
347
 
 
348
GlobalAccelManager::~GlobalAccelManager()
 
349
{
 
350
        delete d;
 
351
}
 
352
 
 
353
int GlobalAccelManager::setAccel(const QKeySequence &ks)
 
354
{
 
355
        
 
356
        UInt32 mod, key;
 
357
        if(!d->convertKeySequence(ks, &mod, &key))
 
358
                return 0;
 
359
 
 
360
        return d->insertHotKey(key, mod);
 
361
}
 
362
 
 
363
void GlobalAccelManager::removeAccel(int id)
 
364
{
 
365
        QPtrListIterator<MacHotKey> it(d->list);
 
366
        for(MacHotKey *hk = 0; (hk = it.current()); ++it) {
 
367
                if(hk->id == id) {
 
368
                        d->list.removeRef(hk);
 
369
                        return;
 
370
                }
 
371
        }
 
372
}