// Created by Justin Williams on 7/26/09. // Copyright 2009 Second Gear. All rights reserved. #import <Carbon/Carbon.h> #import "SGKeyCodeTranslator.h" NSString * const kKeyCodeDictionaryKey = @"keyCode"; NSString * const kModifiersDictionaryKey = @"modifiers"; @implementation SGKeyCombo return [self keyComboWithKeyCode:-1 modifiers:-1]; + (id)keyComboWithKeyCode:(signed short)theKeyCode modifiers:(NSUInteger)theModifiers { return [[[self alloc] initWithKeyCode:theKeyCode modifiers:theModifiers] autorelease]; - (id)initWithKeyCode:(signed short)theKeyCode modifiers:(NSUInteger)theModifiers { if ((self = [super init])) { modifiers = theModifiers; - (id)initWithPlistRepresentation:(id)thePlist { if (!thePlist || ![thePlist count]) { theKeyCode = [[thePlist objectForKey:kKeyCodeDictionaryKey] integerValue]; if (theKeyCode < 0) theKeyCode = -1; theModifiers = [[thePlist objectForKey:kModifiersDictionaryKey] integerValue]; if (theModifiers <= 0) theModifiers = -1; return [self initWithKeyCode:theKeyCode modifiers:theModifiers]; - (id)plistRepresentation { return [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInteger:self.keyCode], kKeyCodeDictionaryKey, [NSNumber numberWithInteger:self.modifiers], kModifiersDictionaryKey, - (BOOL)isEqual:(SGKeyCombo *)theCombo { return self.keyCode == theCombo.keyCode && self.modifiers == theCombo.modifiers; return keyCode == -1 && modifiers == -1; - (BOOL)isValidHotKeyCombo { return keyCode >= 0 && modifiers > 0; + (NSString*)_stringForModifiers:(NSInteger)theModifiers { static unichar modToChar[4][2] = { cmdKey, kCommandUnicode }, { optionKey, kOptionUnicode }, { controlKey, kControlUnicode }, { shiftKey, kShiftUnicode } NSString *string = [NSString string]; for( i = 0; i < 4; i++ ) { if (theModifiers & modToChar[i][0] ) string = [string stringByAppendingString: [NSString stringWithCharacters: &modToChar[i][1] length: 1]]; + (NSDictionary *)_keyCodesDictionary { static NSDictionary *keyCodes = nil; path = [[NSBundle bundleForClass:self] pathForResource:@"SGKeyCodes" ofType:@"plist"]; contents = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error]; NSAssert(contents != nil, @"Contents of SGKeyCodes is nil"); keyCodes = [[contents propertyList] retain]; + (NSString*)_stringForKeyCode: (short)theKeyCode legacyKeyCodeMap: (NSDictionary*)theDictionary { key = [NSString stringWithFormat:@"%d", theKeyCode]; string = [theDictionary objectForKey:key]; string = [NSString stringWithFormat:@"%X", theKeyCode]; + (NSString*)_stringForKeyCode:(short)theKeyCode newKeyCodeMap:(NSDictionary*)theDictionary { NSDictionary *unmappedKeys; keyCodeString = [NSString stringWithFormat: @"%d", theKeyCode]; //Handled if its not handled by translator unmappedKeys = [theDictionary objectForKey:@"unmappedKeys"]; result = [unmappedKeys objectForKey:keyCodeString]; result = [[[SGKeyCodeTranslator currentTranslator] translateKeyCode:theKeyCode] uppercaseString]; //Handle if its a key-pad key padKeys = [theDictionary objectForKey:@"padKeys"]; if([padKeys indexOfObject:keyCodeString] != NSNotFound) { result = [NSString stringWithFormat:@"%@ %@", [theDictionary objectForKey:@"padKeyString"], result]; + (NSString *)_stringForKeyCode:(short)theKeyCode { dict = [self _keyCodesDictionary]; if([[dict objectForKey:@"version"] integerValue] <= 0) return [self _stringForKeyCode:theKeyCode legacyKeyCodeMap:dict]; return [self _stringForKeyCode:theKeyCode newKeyCodeMap:dict]; - (NSString*)keyCodeString { // special case: the modifiers for the "clear" key are 0x0 if ( [self isClearCombo] ) return @""; return [[self class] _stringForKeyCode:self.keyCode]; - (NSUInteger)modifierMask { // special case: the modifiers for the "clear" key are 0x0 if ([self isClearCombo]) return 0; static NSUInteger modToChar[4][2] = { cmdKey, NSCommandKeyMask }, { optionKey, NSAlternateKeyMask }, { controlKey, NSControlKeyMask }, { shiftKey, NSShiftKeyMask } for (i = 0; i < 4; i++) { if (self.modifiers & modToChar[i][0]) { - (NSString *)description { if ([self isValidHotKeyCombo]) { desc = [NSString stringWithFormat: @"%@%@", [[self class] _stringForModifiers:self.modifiers], [[self class] _stringForKeyCode:self.keyCode]]; desc = NSLocalizedString(@"(None)", @"Hot Keys: Key Combo text for 'empty' combo" );