You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
335 lines
7.4 KiB
335 lines
7.4 KiB
9 years ago
|
//
|
||
|
// PTHotKeyCenter.m
|
||
|
// Protein
|
||
|
//
|
||
|
// Created by Quentin Carnicelli on Sat Aug 02 2003.
|
||
|
// Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved.
|
||
|
//
|
||
|
|
||
|
#import "PTHotKeyCenter.h"
|
||
|
#import "PTHotKey.h"
|
||
|
#import "PTKeyCombo.h"
|
||
|
|
||
|
@interface PTHotKeyCenter (Private)
|
||
|
- (PTHotKey*)_hotKeyForCarbonHotKey: (EventHotKeyRef)carbonHotKey;
|
||
|
- (PTHotKey*)_hotKeyForCarbonHotKeyID: (EventHotKeyID)hotKeyID;
|
||
|
|
||
|
- (void)_updateEventHandler;
|
||
|
- (void)_hotKeyDown: (PTHotKey*)hotKey;
|
||
|
- (void)_hotKeyUp: (PTHotKey*)hotKey;
|
||
|
static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* refCon );
|
||
|
@end
|
||
|
|
||
|
@implementation PTHotKeyCenter
|
||
|
|
||
|
static PTHotKeyCenter *_sharedHotKeyCenter = nil;
|
||
|
|
||
|
+ (PTHotKeyCenter*)sharedCenter
|
||
|
{
|
||
|
if( _sharedHotKeyCenter == nil )
|
||
|
{
|
||
|
_sharedHotKeyCenter = [[self alloc] init];
|
||
|
}
|
||
|
|
||
|
return _sharedHotKeyCenter;
|
||
|
}
|
||
|
|
||
|
- (id)init
|
||
|
{
|
||
|
self = [super init];
|
||
|
|
||
|
if( self )
|
||
|
{
|
||
|
mHotKeys = [[NSMutableDictionary alloc] init];
|
||
|
}
|
||
|
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
|
||
|
#pragma mark -
|
||
|
|
||
|
- (BOOL)registerHotKey: (PTHotKey*)hotKey
|
||
|
{
|
||
|
if ( mIsPaused == NO )
|
||
|
{
|
||
|
OSStatus err;
|
||
|
EventHotKeyID hotKeyID;
|
||
|
EventHotKeyRef carbonHotKey;
|
||
|
|
||
|
if( [[self allHotKeys] containsObject: hotKey] == YES )
|
||
|
[self unregisterHotKey: hotKey];
|
||
|
|
||
|
if( [[hotKey keyCombo] isValidHotKeyCombo] == NO )
|
||
|
return YES;
|
||
|
|
||
|
hotKeyID.signature = 'PTHk';
|
||
|
hotKeyID.id = ++mHotKeyCount;
|
||
|
|
||
|
err = RegisterEventHotKey( (SInt32)[[hotKey keyCombo] keyCode],
|
||
|
(UInt32)[[hotKey keyCombo] modifiers],
|
||
|
hotKeyID,
|
||
|
GetEventDispatcherTarget(),
|
||
|
0,
|
||
|
&carbonHotKey );
|
||
|
|
||
|
if( err )
|
||
|
return NO;
|
||
|
|
||
|
[hotKey setCarbonHotKeyID:hotKeyID.id];
|
||
|
[hotKey setCarbonEventHotKeyRef:carbonHotKey];
|
||
|
|
||
|
if( hotKey )
|
||
|
[mHotKeys setObject: hotKey forKey: [NSNumber numberWithInteger:hotKeyID.id]];
|
||
|
|
||
|
[self _updateEventHandler];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
EventHotKeyID hotKeyID = {'PTHk', ++mHotKeyCount};
|
||
|
[hotKey setCarbonHotKeyID:hotKeyID.id];
|
||
|
|
||
|
if( hotKey )
|
||
|
[mHotKeys setObject: hotKey forKey: [NSNumber numberWithInteger:hotKeyID.id]];
|
||
|
}
|
||
|
return YES;
|
||
|
}
|
||
|
|
||
|
- (void)unregisterHotKey: (PTHotKey*)hotKey
|
||
|
{
|
||
|
if ( mIsPaused == NO )
|
||
|
{
|
||
|
EventHotKeyRef carbonHotKey;
|
||
|
|
||
|
if( [[self allHotKeys] containsObject: hotKey] == NO )
|
||
|
return;
|
||
|
|
||
|
carbonHotKey = [hotKey carbonEventHotKeyRef];
|
||
|
|
||
|
if( carbonHotKey )
|
||
|
{
|
||
|
UnregisterEventHotKey( carbonHotKey );
|
||
|
//Watch as we ignore 'err':
|
||
|
|
||
|
[mHotKeys removeObjectForKey: [NSNumber numberWithInteger:[hotKey carbonHotKeyID]]];
|
||
|
|
||
|
[hotKey setCarbonHotKeyID:0];
|
||
|
[hotKey setCarbonEventHotKeyRef:NULL];
|
||
|
|
||
|
[self _updateEventHandler];
|
||
|
|
||
|
//See that? Completely ignored
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
[mHotKeys removeObjectForKey: [NSNumber numberWithInteger:[hotKey carbonHotKeyID]]];
|
||
|
|
||
|
[hotKey setCarbonHotKeyID:0];
|
||
|
[hotKey setCarbonEventHotKeyRef:NULL];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (NSArray*)allHotKeys
|
||
|
{
|
||
|
return [mHotKeys allValues];
|
||
|
}
|
||
|
|
||
|
- (PTHotKey*)hotKeyWithIdentifier: (id)ident
|
||
|
{
|
||
|
NSEnumerator* hotKeysEnum = [[self allHotKeys] objectEnumerator];
|
||
|
PTHotKey* hotKey;
|
||
|
|
||
|
if( !ident )
|
||
|
return nil;
|
||
|
|
||
|
while( (hotKey = [hotKeysEnum nextObject]) != nil )
|
||
|
{
|
||
|
if( [[hotKey identifier] isEqual: ident] )
|
||
|
return hotKey;
|
||
|
}
|
||
|
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
#pragma mark -
|
||
|
|
||
|
- (PTHotKey*)_hotKeyForCarbonHotKey: (EventHotKeyRef)carbonHotKeyRef
|
||
|
{
|
||
|
NSEnumerator *e = [mHotKeys objectEnumerator];
|
||
|
PTHotKey *hotkey = nil;
|
||
|
|
||
|
while( (hotkey = [e nextObject]) )
|
||
|
{
|
||
|
if( [hotkey carbonEventHotKeyRef] == carbonHotKeyRef )
|
||
|
return hotkey;
|
||
|
}
|
||
|
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
- (PTHotKey*)_hotKeyForCarbonHotKeyID: (EventHotKeyID)hotKeyID
|
||
|
{
|
||
|
return [mHotKeys objectForKey:[NSNumber numberWithInteger:hotKeyID.id]];
|
||
|
}
|
||
|
|
||
|
- (void)_updateEventHandler
|
||
|
{
|
||
|
if( [mHotKeys count] && mEventHandlerInstalled == NO )
|
||
|
{
|
||
|
EventTypeSpec eventSpec[2] = {
|
||
|
{ kEventClassKeyboard, kEventHotKeyPressed },
|
||
|
{ kEventClassKeyboard, kEventHotKeyReleased }
|
||
|
};
|
||
|
|
||
|
InstallEventHandler( GetEventDispatcherTarget(),
|
||
|
(EventHandlerProcPtr)hotKeyEventHandler,
|
||
|
2, eventSpec, nil, &mEventHandler);
|
||
|
|
||
|
mEventHandlerInstalled = YES;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)_hotKeyDown: (PTHotKey*)hotKey
|
||
|
{
|
||
|
[hotKey invoke];
|
||
|
}
|
||
|
|
||
|
- (void)_hotKeyUp: (PTHotKey*)hotKey
|
||
|
{
|
||
|
[hotKey uninvoke];
|
||
|
}
|
||
|
|
||
|
- (void)sendEvent: (NSEvent*)event
|
||
|
{
|
||
|
// Not sure why this is needed? - Andy Kim (Aug 23, 2009)
|
||
|
|
||
|
short subType;
|
||
|
EventHotKeyRef carbonHotKey;
|
||
|
|
||
|
if( [event type] == NSSystemDefined )
|
||
|
{
|
||
|
subType = [event subtype];
|
||
|
|
||
|
if( subType == 6 ) //6 is hot key down
|
||
|
{
|
||
|
carbonHotKey= (EventHotKeyRef)[event data1]; //data1 is our hot key ref
|
||
|
if( carbonHotKey != nil )
|
||
|
{
|
||
|
PTHotKey* hotKey = [self _hotKeyForCarbonHotKey: carbonHotKey];
|
||
|
[self _hotKeyDown: hotKey];
|
||
|
}
|
||
|
}
|
||
|
else if( subType == 9 ) //9 is hot key up
|
||
|
{
|
||
|
carbonHotKey= (EventHotKeyRef)[event data1];
|
||
|
if( carbonHotKey != nil )
|
||
|
{
|
||
|
PTHotKey* hotKey = [self _hotKeyForCarbonHotKey: carbonHotKey];
|
||
|
[self _hotKeyUp: hotKey];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (OSStatus)sendCarbonEvent: (EventRef)event
|
||
|
{
|
||
|
OSStatus err;
|
||
|
EventHotKeyID hotKeyID;
|
||
|
PTHotKey* hotKey;
|
||
|
|
||
|
NSAssert( GetEventClass( event ) == kEventClassKeyboard, @"Unknown event class" );
|
||
|
|
||
|
err = GetEventParameter( event,
|
||
|
kEventParamDirectObject,
|
||
|
typeEventHotKeyID,
|
||
|
nil,
|
||
|
sizeof(EventHotKeyID),
|
||
|
nil,
|
||
|
&hotKeyID );
|
||
|
if( err )
|
||
|
return err;
|
||
|
|
||
|
if( hotKeyID.signature != 'PTHk' )
|
||
|
return eventNotHandledErr;
|
||
|
|
||
|
if (hotKeyID.id == 0)
|
||
|
return eventNotHandledErr;
|
||
|
|
||
|
hotKey = [self _hotKeyForCarbonHotKeyID:hotKeyID];
|
||
|
|
||
|
switch( GetEventKind( event ) )
|
||
|
{
|
||
|
case kEventHotKeyPressed:
|
||
|
[self _hotKeyDown: hotKey];
|
||
|
break;
|
||
|
|
||
|
case kEventHotKeyReleased:
|
||
|
[self _hotKeyUp: hotKey];
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return eventNotHandledErr;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return noErr;
|
||
|
}
|
||
|
|
||
|
- (void)pause
|
||
|
{
|
||
|
if ( mIsPaused )
|
||
|
return;
|
||
|
|
||
|
mIsPaused = YES;
|
||
|
for (NSNumber *hotKeyID in mHotKeys)
|
||
|
{
|
||
|
PTHotKey *hotKey = [mHotKeys objectForKey:hotKeyID];
|
||
|
EventHotKeyRef carbonHotKey = [hotKey carbonEventHotKeyRef];
|
||
|
UnregisterEventHotKey( carbonHotKey );
|
||
|
[hotKey setCarbonEventHotKeyRef:NULL];
|
||
|
}
|
||
|
if (mEventHandler != NULL)
|
||
|
{
|
||
|
RemoveEventHandler(mEventHandler);
|
||
|
mEventHandler = NULL;
|
||
|
mEventHandlerInstalled = NO;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- (void)resume
|
||
|
{
|
||
|
if ( mIsPaused == NO)
|
||
|
return;
|
||
|
|
||
|
mIsPaused = NO;
|
||
|
for (NSNumber *hotKeyIDNumber in mHotKeys)
|
||
|
{
|
||
|
PTHotKey *hotKey = [mHotKeys objectForKey:hotKeyIDNumber];
|
||
|
EventHotKeyRef carbonHotKey = NULL;
|
||
|
EventHotKeyID hotKeyID;
|
||
|
hotKeyID.signature = 'PTHk';
|
||
|
hotKeyID.id = [hotKey carbonHotKeyID];
|
||
|
RegisterEventHotKey( (SInt32)[[hotKey keyCombo] keyCode],
|
||
|
(UInt32)[[hotKey keyCombo] modifiers],
|
||
|
hotKeyID,
|
||
|
GetEventDispatcherTarget(),
|
||
|
0,
|
||
|
&carbonHotKey );
|
||
|
[hotKey setCarbonEventHotKeyRef:carbonHotKey];
|
||
|
}
|
||
|
[self _updateEventHandler];
|
||
|
}
|
||
|
|
||
|
- (BOOL)isPaused
|
||
|
{
|
||
|
return mIsPaused;
|
||
|
}
|
||
|
|
||
|
static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* refCon )
|
||
|
{
|
||
|
return [[PTHotKeyCenter sharedCenter] sendCarbonEvent: inEvent];
|
||
|
}
|
||
|
|
||
|
@end
|