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