xref: /AOO41X/main/apple_remote/GlobalKeyboardDevice.m (revision 53e04a5dbf8709463ce908ac78248c6a889a9b40)
1/*****************************************************************************
2 * GlobalKeyboardDevice.m
3 * RemoteControlWrapper
4 *
5 * Created by Martin Kahr on 11.03.06 under a MIT-style license.
6 * Copyright (c) 2006 martinkahr.com. All rights reserved.
7 *
8 * Code modified and adapted to OpenOffice.org
9 * by Eric Bachard on 11.08.2008 under the same license
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * THE SOFTWARE.
28 *
29 *****************************************************************************/
30
31
32#import "GlobalKeyboardDevice.h"
33
34#define F1 122
35#define F2 120
36#define F3 99
37#define F4 118
38#define F5 96
39#define F6 97
40#define F7 98
41
42/*
43 the following default keys are read and shall be used to change the keyboard mapping
44
45 mac.remotecontrols.GlobalKeyboardDevice.plus_modifiers
46 mac.remotecontrols.GlobalKeyboardDevice.plus_keycode
47 mac.remotecontrols.GlobalKeyboardDevice.minus_modifiers
48 mac.remotecontrols.GlobalKeyboardDevice.minus_keycode
49 mac.remotecontrols.GlobalKeyboardDevice.play_modifiers
50 mac.remotecontrols.GlobalKeyboardDevice.play_keycode
51 mac.remotecontrols.GlobalKeyboardDevice.left_modifiers
52 mac.remotecontrols.GlobalKeyboardDevice.left_keycode
53 mac.remotecontrols.GlobalKeyboardDevice.right_modifiers
54 mac.remotecontrols.GlobalKeyboardDevice.right_keycode
55 mac.remotecontrols.GlobalKeyboardDevice.menu_modifiers
56 mac.remotecontrols.GlobalKeyboardDevice.menu_keycode
57 mac.remotecontrols.GlobalKeyboardDevice.playhold_modifiers
58 mac.remotecontrols.GlobalKeyboardDevice.playhold_keycode
59 */
60
61static OSStatus hotKeyEventHandler(EventHandlerCallRef, EventRef, void*);
62
63@implementation GlobalKeyboardDevice
64
65- (id) initWithDelegate: (id) _remoteControlDelegate {
66    if ( (self = [super initWithDelegate: _remoteControlDelegate]) ) {
67        hotKeyRemoteEventMapping = [[NSMutableDictionary alloc] init];
68
69        unsigned int modifiers = cmdKey + shiftKey /*+ optionKey*/ + controlKey;
70
71        [self mapRemoteButton:kRemoteButtonPlus         defaultKeycode:F1 defaultModifiers:modifiers];
72        [self mapRemoteButton:kRemoteButtonMinus        defaultKeycode:F2 defaultModifiers:modifiers];
73        [self mapRemoteButton:kRemoteButtonPlay         defaultKeycode:F3 defaultModifiers:modifiers];
74        [self mapRemoteButton:kRemoteButtonLeft         defaultKeycode:F4 defaultModifiers:modifiers];
75        [self mapRemoteButton:kRemoteButtonRight        defaultKeycode:F5 defaultModifiers:modifiers];
76        [self mapRemoteButton:kRemoteButtonMenu         defaultKeycode:F6 defaultModifiers:modifiers];
77        [self mapRemoteButton:kRemoteButtonPlay_Hold    defaultKeycode:F7 defaultModifiers:modifiers];
78    }
79    return self;
80}
81
82- (void) dealloc {
83    [hotKeyRemoteEventMapping release];
84    [super dealloc];
85}
86
87- (void) mapRemoteButton: (RemoteControlEventIdentifier) remoteButtonIdentifier defaultKeycode: (unsigned int) defaultKeycode defaultModifiers: (unsigned int) defaultModifiers {
88    NSString* defaultsKey = NULL;
89
90    switch(remoteButtonIdentifier) {
91        case kRemoteButtonPlus:
92            defaultsKey = @"plus";
93            break;
94        case kRemoteButtonMinus:
95            defaultsKey = @"minus";
96            break;
97        case kRemoteButtonMenu:
98            defaultsKey = @"menu";
99            break;
100        case kRemoteButtonPlay:
101            defaultsKey = @"play";
102            break;
103        case kRemoteButtonRight:
104            defaultsKey = @"right";
105            break;
106        case kRemoteButtonLeft:
107            defaultsKey = @"left";
108            break;
109        case kRemoteButtonPlay_Hold:
110            defaultsKey = @"playhold";
111            break;
112        default:
113#ifdef DEBUG
114            NSLog( @"Apple Remote: Unknown global keyboard defaults key for button identifier %d", remoteButtonIdentifier);
115#endif
116            break;
117    }
118
119    NSNumber* modifiersCfg = [[NSUserDefaults standardUserDefaults] objectForKey: [NSString stringWithFormat: @"mac.remotecontrols.GlobalKeyboardDevice.%@_modifiers", defaultsKey]];
120    NSNumber* keycodeCfg   = [[NSUserDefaults standardUserDefaults] objectForKey: [NSString stringWithFormat: @"mac.remotecontrols.GlobalKeyboardDevice.%@_keycode", defaultsKey]];
121
122    unsigned int modifiers = defaultModifiers;
123    if (modifiersCfg) modifiers = [modifiersCfg unsignedIntValue];
124
125    unsigned int keycode = defaultKeycode;
126    if (keycodeCfg) keycode = [keycodeCfg unsignedIntValue];
127
128    [self registerHotKeyCode: keycode  modifiers: modifiers remoteEventIdentifier: remoteButtonIdentifier];
129}
130
131- (void) setListeningToRemote: (BOOL) value {
132    if (value == [self isListeningToRemote]) return;
133    if (value) {
134        [self startListening: self];
135    } else {
136        [self stopListening: self];
137    }
138}
139- (BOOL) isListeningToRemote {
140    return (eventHandlerRef!=NULL);
141}
142
143- (void) startListening: (id) sender {
144
145    if (eventHandlerRef) return;
146
147    EventTypeSpec eventSpec[2] = {
148        { kEventClassKeyboard, kEventHotKeyPressed },
149        { kEventClassKeyboard, kEventHotKeyReleased }
150    };
151
152    InstallEventHandler( GetEventDispatcherTarget(),
153                         (EventHandlerProcPtr)hotKeyEventHandler,
154                         2, eventSpec, self, &eventHandlerRef);
155}
156- (void) stopListening: (id) sender {
157    RemoveEventHandler(eventHandlerRef);
158    eventHandlerRef = NULL;
159}
160
161- (BOOL) sendsEventForButtonIdentifier: (RemoteControlEventIdentifier) identifier {
162    NSEnumerator* values = [hotKeyRemoteEventMapping objectEnumerator];
163    NSNumber* remoteIdentifier;
164    while( (remoteIdentifier = [values nextObject]) ) {
165        if ([remoteIdentifier unsignedIntValue] == identifier) return YES;
166    }
167    return NO;
168}
169
170+ (const char*) remoteControlDeviceName {
171    return "Keyboard";
172}
173
174- (BOOL)registerHotKeyCode: (unsigned int) keycode modifiers: (unsigned int) modifiers remoteEventIdentifier: (RemoteControlEventIdentifier) identifier {
175    OSStatus err;
176    EventHotKeyID hotKeyID;
177    EventHotKeyRef carbonHotKey;
178
179    hotKeyID.signature = 'PTHk';
180    hotKeyID.id = (long)keycode;
181
182    err = RegisterEventHotKey(keycode, modifiers, hotKeyID, GetEventDispatcherTarget(), 0, &carbonHotKey );
183
184    if( err )
185        return NO;
186
187    [hotKeyRemoteEventMapping setObject: [NSNumber numberWithInt:identifier] forKey: [NSNumber numberWithUnsignedInt: hotKeyID.id]];
188
189    return YES;
190}
191/*
192- (void)unregisterHotKey: (PTHotKey*)hotKey
193{
194    OSStatus err;
195    EventHotKeyRef carbonHotKey;
196    NSValue* key;
197
198    if( [[self allHotKeys] containsObject: hotKey] == NO )
199        return;
200
201    carbonHotKey = [self _carbonHotKeyForHotKey: hotKey];
202    NSAssert( carbonHotKey != nil, @"" );
203
204    err = UnregisterEventHotKey( carbonHotKey );
205    //Watch as we ignore 'err':
206
207    key = [NSValue valueWithPointer: carbonHotKey];
208    [mHotKeys removeObjectForKey: key];
209
210    [self _updateEventHandler];
211
212    //See that? Completely ignored
213}
214*/
215
216- (RemoteControlEventIdentifier) remoteControlEventIdentifierForID: (unsigned int) id {
217    NSNumber* remoteEventIdentifier = [hotKeyRemoteEventMapping objectForKey:[NSNumber numberWithUnsignedInt: id]];
218    return [remoteEventIdentifier unsignedIntValue];
219}
220
221- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown {
222    [delegate sendRemoteButtonEvent: event pressedDown: pressedDown remoteControl:self];
223}
224
225static RemoteControlEventIdentifier lastEvent;
226
227
228static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* userData )
229{
230    GlobalKeyboardDevice* keyboardDevice = (GlobalKeyboardDevice*) userData;
231    EventHotKeyID hkCom;
232    GetEventParameter(inEvent,kEventParamDirectObject,typeEventHotKeyID,NULL,sizeof(hkCom),NULL,&hkCom);
233
234    RemoteControlEventIdentifier identifier = [keyboardDevice remoteControlEventIdentifierForID:hkCom.id];
235    if (identifier == 0) return noErr;
236
237    BOOL pressedDown = YES;
238    if (identifier != lastEvent) {
239        lastEvent = identifier;
240    } else {
241        lastEvent = 0;
242        pressedDown = NO;
243    }
244    [keyboardDevice sendRemoteButtonEvent: identifier pressedDown: pressedDown];
245
246    return noErr;
247}
248
249@end
250