/***************************************************************************** * GlobalKeyboardDevice.m * RemoteControlWrapper * * Created by Martin Kahr on 11.03.06 under a MIT-style license. * Copyright (c) 2006 martinkahr.com. All rights reserved. * * Code modified and adapted to OpenOffice.org * by Eric Bachard on 11.08.2008 under the same license * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * *****************************************************************************/ #import "GlobalKeyboardDevice.h" #define F1 122 #define F2 120 #define F3 99 #define F4 118 #define F5 96 #define F6 97 #define F7 98 /* the following default keys are read and shall be used to change the keyboard mapping mac.remotecontrols.GlobalKeyboardDevice.plus_modifiers mac.remotecontrols.GlobalKeyboardDevice.plus_keycode mac.remotecontrols.GlobalKeyboardDevice.minus_modifiers mac.remotecontrols.GlobalKeyboardDevice.minus_keycode mac.remotecontrols.GlobalKeyboardDevice.play_modifiers mac.remotecontrols.GlobalKeyboardDevice.play_keycode mac.remotecontrols.GlobalKeyboardDevice.left_modifiers mac.remotecontrols.GlobalKeyboardDevice.left_keycode mac.remotecontrols.GlobalKeyboardDevice.right_modifiers mac.remotecontrols.GlobalKeyboardDevice.right_keycode mac.remotecontrols.GlobalKeyboardDevice.menu_modifiers mac.remotecontrols.GlobalKeyboardDevice.menu_keycode mac.remotecontrols.GlobalKeyboardDevice.playhold_modifiers mac.remotecontrols.GlobalKeyboardDevice.playhold_keycode */ static OSStatus hotKeyEventHandler(EventHandlerCallRef, EventRef, void*); @implementation GlobalKeyboardDevice - (id) initWithDelegate: (id) _remoteControlDelegate { if ( (self = [super initWithDelegate: _remoteControlDelegate]) ) { hotKeyRemoteEventMapping = [[NSMutableDictionary alloc] init]; unsigned int modifiers = cmdKey + shiftKey /*+ optionKey*/ + controlKey; [self mapRemoteButton:kRemoteButtonPlus defaultKeycode:F1 defaultModifiers:modifiers]; [self mapRemoteButton:kRemoteButtonMinus defaultKeycode:F2 defaultModifiers:modifiers]; [self mapRemoteButton:kRemoteButtonPlay defaultKeycode:F3 defaultModifiers:modifiers]; [self mapRemoteButton:kRemoteButtonLeft defaultKeycode:F4 defaultModifiers:modifiers]; [self mapRemoteButton:kRemoteButtonRight defaultKeycode:F5 defaultModifiers:modifiers]; [self mapRemoteButton:kRemoteButtonMenu defaultKeycode:F6 defaultModifiers:modifiers]; [self mapRemoteButton:kRemoteButtonPlay_Hold defaultKeycode:F7 defaultModifiers:modifiers]; } return self; } - (void) dealloc { [hotKeyRemoteEventMapping release]; [super dealloc]; } - (void) mapRemoteButton: (RemoteControlEventIdentifier) remoteButtonIdentifier defaultKeycode: (unsigned int) defaultKeycode defaultModifiers: (unsigned int) defaultModifiers { NSString* defaultsKey = NULL; switch(remoteButtonIdentifier) { case kRemoteButtonPlus: defaultsKey = @"plus"; break; case kRemoteButtonMinus: defaultsKey = @"minus"; break; case kRemoteButtonMenu: defaultsKey = @"menu"; break; case kRemoteButtonPlay: defaultsKey = @"play"; break; case kRemoteButtonRight: defaultsKey = @"right"; break; case kRemoteButtonLeft: defaultsKey = @"left"; break; case kRemoteButtonPlay_Hold: defaultsKey = @"playhold"; break; default: #ifdef DEBUG NSLog( @"Apple Remote: Unknown global keyboard defaults key for button identifier %d", remoteButtonIdentifier); #endif break; } NSNumber* modifiersCfg = [[NSUserDefaults standardUserDefaults] objectForKey: [NSString stringWithFormat: @"mac.remotecontrols.GlobalKeyboardDevice.%@_modifiers", defaultsKey]]; NSNumber* keycodeCfg = [[NSUserDefaults standardUserDefaults] objectForKey: [NSString stringWithFormat: @"mac.remotecontrols.GlobalKeyboardDevice.%@_keycode", defaultsKey]]; unsigned int modifiers = defaultModifiers; if (modifiersCfg) modifiers = [modifiersCfg unsignedIntValue]; unsigned int keycode = defaultKeycode; if (keycodeCfg) keycode = [keycodeCfg unsignedIntValue]; [self registerHotKeyCode: keycode modifiers: modifiers remoteEventIdentifier: remoteButtonIdentifier]; } - (void) setListeningToRemote: (BOOL) value { if (value == [self isListeningToRemote]) return; if (value) { [self startListening: self]; } else { [self stopListening: self]; } } - (BOOL) isListeningToRemote { return (eventHandlerRef!=NULL); } - (void) startListening: (id) sender { if (eventHandlerRef) return; EventTypeSpec eventSpec[2] = { { kEventClassKeyboard, kEventHotKeyPressed }, { kEventClassKeyboard, kEventHotKeyReleased } }; InstallEventHandler( GetEventDispatcherTarget(), (EventHandlerProcPtr)hotKeyEventHandler, 2, eventSpec, self, &eventHandlerRef); } - (void) stopListening: (id) sender { RemoveEventHandler(eventHandlerRef); eventHandlerRef = NULL; } - (BOOL) sendsEventForButtonIdentifier: (RemoteControlEventIdentifier) identifier { NSEnumerator* values = [hotKeyRemoteEventMapping objectEnumerator]; NSNumber* remoteIdentifier; while( (remoteIdentifier = [values nextObject]) ) { if ([remoteIdentifier unsignedIntValue] == identifier) return YES; } return NO; } + (const char*) remoteControlDeviceName { return "Keyboard"; } - (BOOL)registerHotKeyCode: (unsigned int) keycode modifiers: (unsigned int) modifiers remoteEventIdentifier: (RemoteControlEventIdentifier) identifier { OSStatus err; EventHotKeyID hotKeyID; EventHotKeyRef carbonHotKey; hotKeyID.signature = 'PTHk'; hotKeyID.id = (long)keycode; err = RegisterEventHotKey(keycode, modifiers, hotKeyID, GetEventDispatcherTarget(), 0, &carbonHotKey ); if( err ) return NO; [hotKeyRemoteEventMapping setObject: [NSNumber numberWithInt:identifier] forKey: [NSNumber numberWithUnsignedInt: hotKeyID.id]]; return YES; } /* - (void)unregisterHotKey: (PTHotKey*)hotKey { OSStatus err; EventHotKeyRef carbonHotKey; NSValue* key; if( [[self allHotKeys] containsObject: hotKey] == NO ) return; carbonHotKey = [self _carbonHotKeyForHotKey: hotKey]; NSAssert( carbonHotKey != nil, @"" ); err = UnregisterEventHotKey( carbonHotKey ); //Watch as we ignore 'err': key = [NSValue valueWithPointer: carbonHotKey]; [mHotKeys removeObjectForKey: key]; [self _updateEventHandler]; //See that? Completely ignored } */ - (RemoteControlEventIdentifier) remoteControlEventIdentifierForID: (unsigned int) id { NSNumber* remoteEventIdentifier = [hotKeyRemoteEventMapping objectForKey:[NSNumber numberWithUnsignedInt: id]]; return [remoteEventIdentifier unsignedIntValue]; } - (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown { [delegate sendRemoteButtonEvent: event pressedDown: pressedDown remoteControl:self]; } static RemoteControlEventIdentifier lastEvent; static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* userData ) { GlobalKeyboardDevice* keyboardDevice = (GlobalKeyboardDevice*) userData; EventHotKeyID hkCom; GetEventParameter(inEvent,kEventParamDirectObject,typeEventHotKeyID,NULL,sizeof(hkCom),NULL,&hkCom); RemoteControlEventIdentifier identifier = [keyboardDevice remoteControlEventIdentifierForID:hkCom.id]; if (identifier == 0) return noErr; BOOL pressedDown = YES; if (identifier != lastEvent) { lastEvent = identifier; } else { lastEvent = 0; pressedDown = NO; } [keyboardDevice sendRemoteButtonEvent: identifier pressedDown: pressedDown]; return noErr; } @end