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