diff --git a/MacPass/MPAutotypeCommand.m b/MacPass/MPAutotypeCommand.m index f4357e91..1d531a59 100644 --- a/MacPass/MPAutotypeCommand.m +++ b/MacPass/MPAutotypeCommand.m @@ -20,6 +20,24 @@ #import +@interface NSNumber (AutotypeCommand) + +- (CGEventFlags)eventFlagsValue; +- (CGKeyCode)keyCodeValue; + +@end + +@implementation NSNumber (AutotypeCommand) + +- (CGEventFlags)eventFlagsValue { + return (CGEventFlags)[self integerValue]; +} +- (CGKeyCode)keyCodeValue { + return (CGKeyCode)[self integerValue]; +} + +@end + @implementation MPAutotypeCommand + (NSDictionary *)keypressCommands { @@ -57,7 +75,7 @@ /** * Mapping for modifier to CGEventFlags. - * @note KeypassControl is mapped to command! + * @note KeepassControl is mapped to command! * * @return dictionary with commands as keys and CGEventFlags as wrapped values */ @@ -83,7 +101,7 @@ NSMutableArray __block *commandRanges = [[NSMutableArray alloc] initWithCapacity:reserverd]; NSRegularExpression *commandRegExp = [[NSRegularExpression alloc] initWithPattern:@"\\{[^\\}]+\\}" options:NSRegularExpressionCaseInsensitive error:0]; NSAssert(commandRegExp, @"RegExp is constant. Has to work all the time"); - [commandRegExp enumerateMatchesInString:context.normalizedCommand options:0 range:NSMakeRange(0, [context.normalizedCommand length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { + [commandRegExp enumerateMatchesInString:context.evaluatedCommand options:0 range:NSMakeRange(0, [context.evaluatedCommand length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { @autoreleasepool { [commandRanges addObject:[NSValue valueWithRange:result.range]]; } @@ -94,16 +112,17 @@ NSRange commandRange = [rangeValue rangeValue]; /* All non-commands will get translated into paste commands */ if(commandRange.location > lastLocation) { - /* If were modifiers we need to use the next single stroke and make update the modifier command */ + /* If there were modifiers we need to use the next single stroke and make update the modifier command */ if(keyPress) { + } - NSString *pasteValue = [context.normalizedCommand substringWithRange:NSMakeRange(lastLocation, commandRange.location - lastLocation)]; + NSString *pasteValue = [context.evaluatedCommand substringWithRange:NSMakeRange(lastLocation, commandRange.location - lastLocation)]; // Determin if it's amodifier key, and collect them! [self appendPasteCommandForContent:pasteValue toCommands:commands]; } - NSString *commandString = [context.normalizedCommand substringWithRange:commandRange]; - [self appendCommandForString:commandString toCommands:commands]; - lastLocation = commandRange.location; + NSString *commandString = [context.evaluatedCommand substringWithRange:commandRange]; + [self appendCommandForString:commandString toCommands:commands keyPressCommand:&keyPress]; + lastLocation = commandRange.location + commandRange.length; } return commands; } @@ -115,10 +134,41 @@ } } -+ (void)appendCommandForString:(NSString *)commandString toCommands:(NSMutableArray *)commands { - MPAutotypeCommand *command; ++ (void)appendCommandForString:(NSString *)commandString toCommands:(NSMutableArray *)commands keyPressCommand:(MPAutotypeKeyPress **)keyPress { if(!commandString) { - NSDictionary *modifier = [self modifierCommands]; + return; + } + + NSNumber *flagNumber = [self modifierCommands][commandString]; + NSNumber *keyCodeNumber = [self keypressCommands][commandString]; + + /* modifier key */ + if(flagNumber) { + if(keyPress == NULL) { + return; // We need a pointer to return the keypress! + } + CGEventFlags flags = [flagNumber eventFlagsValue]; + if(*keyPress == nil) { + *keyPress = [[MPAutotypeKeyPress alloc] initWithModifierMask:flags keyCode:0]; + [commands addObject:*keyPress]; + } + else { + NSAssert([*keyPress isKindOfClass:[MPAutotypeKeyPress class]], @"Invalid command supplied"); + (*keyPress).modifierMask |= flags; + } + } + /* key press */ + else if(keyCodeNumber) { + CGKeyCode keyCode = [keyCodeNumber keyCodeValue]; + /* we have no modifers collected */ + if(keyPress != NULL && keyPress == nil) { + *keyPress = [[MPAutotypeKeyPress alloc] initWithModifierMask:0 keyCode:keyCode]; + [commands addObject:*keyPress]; + } + /* modifers collected, set keycode */ + else if(keyPress) { + (*keyPress).keyCode = keyCode; + } } } diff --git a/MacPass/MPAutotypeContext.h b/MacPass/MPAutotypeContext.h index 7b7a5097..d83cfd73 100644 --- a/MacPass/MPAutotypeContext.h +++ b/MacPass/MPAutotypeContext.h @@ -26,6 +26,10 @@ */ @property (nonatomic, readonly, copy) NSString *command; @property (nonatomic, readonly, copy) NSString *normalizedCommand; +/** + * Command with placeholders and references resolved + */ +@property (nonatomic, readonly, copy) NSString *evaluatedCommand; /** * Designated initializer @@ -45,6 +49,4 @@ */ - (BOOL)isValid; -- (NSString *)evaluatedCommand; - @end diff --git a/MacPass/MPAutotypeContext.m b/MacPass/MPAutotypeContext.m index f1ceca3a..fb7b12e6 100644 --- a/MacPass/MPAutotypeContext.m +++ b/MacPass/MPAutotypeContext.m @@ -13,6 +13,12 @@ #import "KPKWindowAssociation.h" #import "NSString+Commands.h" +@interface MPAutotypeContext () { + NSString *_evaluatedCommand; +} + +@end + @implementation MPAutotypeContext - (instancetype)initWithWindowAssociation:(KPKWindowAssociation *)association { @@ -46,12 +52,11 @@ } - (NSString *)evaluatedCommand { - static NSString *evaluated; - if(!evaluated) { + if(!_evaluatedCommand) { NSString *placeholderFilled = [self.normalizedCommand evaluatePlaceholderWithEntry:self.entry]; - evaluated = [placeholderFilled resolveReferencesWithTree:self.entry.tree]; + _evaluatedCommand = [[placeholderFilled resolveReferencesWithTree:self.entry.tree] copy]; } - return evaluated; + return _evaluatedCommand; } @end diff --git a/MacPass/MPAutotypeDaemon.m b/MacPass/MPAutotypeDaemon.m index a212615e..5f496d3e 100644 --- a/MacPass/MPAutotypeDaemon.m +++ b/MacPass/MPAutotypeDaemon.m @@ -65,7 +65,6 @@ NSString *const kMPApplciationNameKey = @"applicationName"; NSMenuItem *item = [self.matchSelectionButton selectedItem]; MPAutotypeContext *context = [item representedObject]; [self.matchSelectionWindow orderOut:self]; - } - (void)_didPressHotKey { diff --git a/MacPass/MPAutotypeKeyPress.h b/MacPass/MPAutotypeKeyPress.h index 4cd99b0a..f8b7ad61 100644 --- a/MacPass/MPAutotypeKeyPress.h +++ b/MacPass/MPAutotypeKeyPress.h @@ -16,4 +16,6 @@ @property (assign) CGEventFlags modifierMask; @property (assign) CGKeyCode keyCode; +- (instancetype)initWithModifierMask:(CGEventFlags)modiferMask keyCode:(CGKeyCode)code; + @end diff --git a/MacPass/MPAutotypeKeyPress.m b/MacPass/MPAutotypeKeyPress.m index 5f0fe8fc..c12687b9 100644 --- a/MacPass/MPAutotypeKeyPress.m +++ b/MacPass/MPAutotypeKeyPress.m @@ -11,6 +11,15 @@ @implementation MPAutotypeKeyPress +- (instancetype)initWithModifierMask:(CGEventFlags)modiferMask keyCode:(CGKeyCode)code { + self = [super init]; + if(self) { + _modifierMask = modiferMask; + _keyCode = code; + } + return self; +} + - (void)execute { if(![self isValid]) { return; // no valid command. Stop.