diff --git a/MacPass/MPAutotypeClear.m b/MacPass/MPAutotypeClear.m index 106cb6f4..82ea6c87 100644 --- a/MacPass/MPAutotypeClear.m +++ b/MacPass/MPAutotypeClear.m @@ -17,12 +17,12 @@ } - (void)execute { - CGKeyCode keyCode = [MPKeyMapper keyCodeForCharacter:@"a" modifier:NULL]; - if(keyCode == kMPUnknownKeyCode) { + MPModifiedKey key = [MPKeyMapper modifiedKeyForCharacter:@"a"]; + if(key.keyCode == kMPUnknownKeyCode) { NSLog(@"Unable to generate key code for 'A'"); return; } - [self sendPressKey:keyCode modifierFlags:kCGEventFlagMaskCommand]; + [self sendPressKey:key.keyCode modifierFlags:kCGEventFlagMaskCommand]; [self sendPressKey:kVK_Delete modifierFlags:0]; } diff --git a/MacPass/MPAutotypeCommand.m b/MacPass/MPAutotypeCommand.m index 035a6ae2..381439a8 100644 --- a/MacPass/MPAutotypeCommand.m +++ b/MacPass/MPAutotypeCommand.m @@ -238,17 +238,16 @@ static CGKeyCode kMPFunctionKeyCodes[] = { kVK_F1, kVK_F2, kVK_F3, kVK_F4, kVK_F NSUInteger part = random() % 2; unichar key = [pasteContent characterAtIndex:i]; - CGKeyCode keyCode = [MPKeyMapper keyCodeForCharacter:[NSString stringWithFormat:@"%c", key] modifier:NULL]; - + MPModifiedKey mKey = [MPKeyMapper modifiedKeyForCharacter:[NSString stringWithFormat:@"%c", key]]; /* append unknown keycodes to the paste since we can't type them */ - if (part == 0 || keyCode == kMPUnknownKeyCode) { + if (part == 0 || mKey.keyCode == kMPUnknownKeyCode) { paste = [paste stringByAppendingFormat:@"%c", key]; [typeKeys addObject:@(kVK_RightArrow)]; [modifiers addObject:@0]; } else { - [typeKeys addObject:@(keyCode)]; + [typeKeys addObject:@(mKey.keyCode)]; if ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:key]) [modifiers addObject:@(kCGEventFlagMaskShift)]; @@ -398,11 +397,11 @@ static CGKeyCode kMPFunctionKeyCodes[] = { kVK_F1, kVK_F2, kVK_F3, kVK_F4, kVK_F } - (void)sendPasteKeyCode { - CGKeyCode keyCode = [MPKeyMapper keyCodeForCharacter:@"v" modifier:NULL]; - if(keyCode == kMPUnknownKeyCode) { + MPModifiedKey mKey = [MPKeyMapper modifiedKeyForCharacter:@"v"]; + if(mKey.keyCode == kMPUnknownKeyCode) { return; // We did not find a mapping for "V" } - [self sendPressKey:keyCode modifierFlags:kCGEventFlagMaskCommand]; + [self sendPressKey:mKey.keyCode modifierFlags:kCGEventFlagMaskCommand]; } - (void)execute { diff --git a/MacPass/MPAutotypeKeyPress.m b/MacPass/MPAutotypeKeyPress.m index 9cc7572e..26224959 100644 --- a/MacPass/MPAutotypeKeyPress.m +++ b/MacPass/MPAutotypeKeyPress.m @@ -32,16 +32,15 @@ static CGEventFlags _updateModifierMaskForCurrentDefaults(CGEventFlags modifiers } - (instancetype)initWithModifierMask:(CGEventFlags)modiferMask character:(NSString *)character { - CGEventFlags modifiers; - CGKeyCode mappedKey = [MPKeyMapper keyCodeForCharacter:character modifier:&modifiers]; - if(mappedKey == kMPUnknownKeyCode) { + MPModifiedKey mappedKey = [MPKeyMapper modifiedKeyForCharacter:character]; + if(mappedKey.keyCode == kMPUnknownKeyCode) { self = nil; } else { - if(modifiers && (modiferMask != modifiers)) { + if(mappedKey.modifier && (modiferMask != mappedKey.modifier)) { NSLog(@"Supplied modifiers for character %@ do not match required modifiers", character); } - self = [self initWithModifierMask:modiferMask keyCode:mappedKey]; + self = [self initWithModifierMask:modiferMask keyCode:mappedKey.modifier]; } return self; } diff --git a/MacPass/MPKeyMapper.h b/MacPass/MPKeyMapper.h index ce034f6e..b12a87ee 100644 --- a/MacPass/MPKeyMapper.h +++ b/MacPass/MPKeyMapper.h @@ -10,6 +10,18 @@ FOUNDATION_EXTERN uint16_t const kMPUnknownKeyCode; +typedef struct { + CGEventFlags modifier; + CGKeyCode keyCode; +} MPModifiedKey; + +NS_INLINE MPModifiedKey MPMakeModifiedKey(CGEventFlags modifier, CGKeyCode keyCode) { + MPModifiedKey k; + k.keyCode = keyCode; + k.modifier = modifier; + return k; +} + @interface MPKeyMapper : NSObject /** @@ -19,16 +31,16 @@ FOUNDATION_EXTERN uint16_t const kMPUnknownKeyCode; * @param modifier State of modifier flags being pressed with the key * @return NSString containing the current mapping for the keyCode */ -+ (NSString *)stringForKey:(CGKeyCode)keyCode modifier:(CGEventFlags)modifier; + (NSString *)stringForKey:(CGKeyCode)keyCode; ++ (NSString *)stringForModifiedKey:(MPModifiedKey)modifiedKey; /** - * Determines the keyCode (if possible) for the character. Modifiers might be needed + * Determines the modifiedkey (if possible) for the character. Modifiers might be needed * * @param character NSString with a single character to be transformed * @param modifier pointer to a modifer structure to return the modifer to use with the key code for the character - * @return virtual Keycode for the supplied string. If none is found, kMPUnkonwKeyCode is returned + * @return ModifiedKey if one was found. If none is found, the returned modifiedKey.keyCode has the value kMPUnkonwKeyCode. */ -+ (CGKeyCode)keyCodeForCharacter:(NSString *)character modifier:(CGEventFlags *)modifer; ++ (MPModifiedKey)modifiedKeyForCharacter:(NSString *)character; @end diff --git a/MacPass/MPKeyMapper.m b/MacPass/MPKeyMapper.m index d0d7aa63..288f05f2 100644 --- a/MacPass/MPKeyMapper.m +++ b/MacPass/MPKeyMapper.m @@ -20,18 +20,19 @@ #import "MPKeyMapper.h" - #import +#define MPSafeSetPointer(pointer, value) if(pointer != 0) { *pointer = value; } + uint16_t const kMPUnknownKeyCode = UINT16_MAX; @implementation MPKeyMapper + (NSString *)stringForKey:(CGKeyCode)keyCode { - return [self stringForKey:keyCode modifier:0]; + return [self stringForModifiedKey:MPMakeModifiedKey(0, keyCode)]; } -+ (NSString *)stringForKey:(CGKeyCode)keyCode modifier:(CGEventFlags)modifier { ++ (NSString *)stringForModifiedKey:(MPModifiedKey)modifiedKey { TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); CFDataRef layoutData = TISGetInputSourceProperty(currentKeyboard,kTISPropertyUnicodeKeyLayoutData); @@ -49,21 +50,21 @@ uint16_t const kMPUnknownKeyCode = UINT16_MAX; uint32_t modifierKeyState = 0; - if(modifier & kCGEventFlagMaskCommand) { + if(modifiedKey.modifier & kCGEventFlagMaskCommand) { modifierKeyState |= ((cmdKey >> 8 ) & 0xFF); } - if(modifier & kCGEventFlagMaskShift) { + if(modifiedKey.modifier & kCGEventFlagMaskShift) { modifierKeyState |= ((shiftKey >> 8) & 0xFF); } - if(modifier & kCGEventFlagMaskAlternate) { + if(modifiedKey.modifier & kCGEventFlagMaskAlternate) { modifierKeyState |= ((optionKey >> 8) & 0xFF); } - if(modifier & kCGEventFlagMaskControl) { + if(modifiedKey.modifier & kCGEventFlagMaskControl) { modifierKeyState |= ((controlKey >> 8) & 0xFF); } OSStatus success = 0; success = UCKeyTranslate(keyboardLayout, - keyCode, + modifiedKey.keyCode, kUCKeyActionDisplay, modifierKeyState, LMGetKbdType(), @@ -76,7 +77,7 @@ uint16_t const kMPUnknownKeyCode = UINT16_MAX; return CFBridgingRelease(CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1)); } -+ (CGKeyCode)keyCodeForCharacter:(NSString *)character modifier:(CGEventFlags *)modifer { ++ (MPModifiedKey)modifiedKeyForCharacter:(NSString *)character { static NSMutableDictionary *keyboardCodeDictionary; TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); @@ -89,21 +90,32 @@ uint16_t const kMPUnknownKeyCode = UINT16_MAX; keyboardCodeDictionary = [[NSMutableDictionary alloc] initWithCapacity:2]; } /* search for current character mapping */ - NSDictionary *> *charToCodeDict = keyboardCodeDictionary[localizedName]; + NSDictionary *charToCodeDict = keyboardCodeDictionary[localizedName]; if(nil == charToCodeDict) { /* Add mapping */ + static uint64_t modifierCombinations[] = { + 0, + kCGEventFlagMaskShift, + kCGEventFlagMaskAlternate, + kCGEventFlagMaskControl, + (kCGEventFlagMaskShift | kCGEventFlagMaskAlternate), + (kCGEventFlagMaskShift | kCGEventFlagMaskControl), + (kCGEventFlagMaskShift | kCGEventFlagMaskAlternate | kCGEventFlagMaskControl) + }; + NSMutableDictionary *tempCharToCodeDict = [[NSMutableDictionary alloc] initWithCapacity:128]; /* Generate table of keycodes and characters. */ /* Loop through every keycode (0 - 127) to find its current mapping. */ /* Loop throuhg every control key compbination for every virutal key */ for(CGKeyCode keyCode = 0; keyCode < 128; ++keyCode) { - uint64_t modifiers[] = { 0, kCGEventFlagMaskShift, kCGEventFlagMaskAlternate, kCGEventFlagMaskControl, kCGEventFlagMaskShift | kCGEventFlagMaskAlternate, kCGEventFlagMaskShift | kCGEventFlagMaskControl, kCGEventFlagMaskShift | kCGEventFlagMaskAlternate | kCGEventFlagMaskControl }; - for(int modifierIndex = 0; modifierIndex < sizeof(modifiers); modifierIndex++) { - NSString *string = [self stringForKey:keyCode modifier:modifiers[modifierIndex]]; + for(int modifierIndex = 0; modifierIndex < sizeof(modifierCombinations); modifierIndex++) { + MPModifiedKey mKey = MPMakeModifiedKey(modifierCombinations[modifierIndex], keyCode); + NSString *string = [self stringForModifiedKey:mKey]; if(string != nil && string.length > 0 && nil == tempCharToCodeDict[string]) { - tempCharToCodeDict[string] = @[@(keyCode), @(modifiers[modifierIndex])]; + NSValue *value = [NSValue valueWithBytes:&mKey objCType:@encode(MPModifiedKey)]; + tempCharToCodeDict[string] = value; } } } @@ -111,18 +123,13 @@ uint16_t const kMPUnknownKeyCode = UINT16_MAX; keyboardCodeDictionary[localizedName] = charToCodeDict; } NSString *singleCharacter = [character substringToIndex:1].lowercaseString; - NSArray *result = charToCodeDict[singleCharacter]; - if(result) { - if(modifer) { - *modifer = result[1].unsignedIntegerValue; - } - /* false positive when no modifier was supplied! */ - return result[0].integerValue; + NSValue *result = charToCodeDict[singleCharacter]; + if(!result) { + return MPMakeModifiedKey(0, kMPUnknownKeyCode); } - if(modifer) { - *modifer = 0; - } - return kMPUnknownKeyCode; + MPModifiedKey mKey; + [result getValue:&mKey]; + return mKey; } @end diff --git a/MacPassTests/MPTestKeyMapper.m b/MacPassTests/MPTestKeyMapper.m index 7b4506e2..0fcbcc54 100644 --- a/MacPassTests/MPTestKeyMapper.m +++ b/MacPassTests/MPTestKeyMapper.m @@ -19,10 +19,10 @@ @implementation MPTestKeyMapper - (void)testKeyMapper { - CGEventFlags flags = 0; - CGKeyCode keyCode = [MPKeyMapper keyCodeForCharacter:@"A" modifier:&flags]; - XCTAssertEqual(kVK_ANSI_A, keyCode); - XCTAssertEqual(kCGEventFlagMaskShift, flags); + + MPModifiedKey key = [MPKeyMapper modifiedKeyForCharacter:@"A"]; + XCTAssertEqual(kVK_ANSI_A, key.keyCode); + XCTAssertEqual(kCGEventFlagMaskShift, key.modifier); /* Test only works for german keyboard layout! XCTAssertEqualObjects(@"a",[MPKeyMapper stringForKey:kVK_ANSI_A modifier:0]);