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