diff --git a/MacPass/MPAutotypeDaemon.m b/MacPass/MPAutotypeDaemon.m index 48191cdd..c33e4b4f 100644 --- a/MacPass/MPAutotypeDaemon.m +++ b/MacPass/MPAutotypeDaemon.m @@ -26,6 +26,7 @@ #import "MPAutotypeCommand.h" #import "MPAutotypeContext.h" #import "MPAutotypePaste.h" +#import "MPAutotypeDelay.h" #import "MPPasteBoardController.h" #import "MPSettingsHelper.h" #import "MPAutotypeCandidateSelectionViewController.h" @@ -319,18 +320,24 @@ static MPAutotypeDaemon *_sharedInstance; usleep(1 * NSEC_PER_MSEC); } - useconds_t delay = 0; - if(nil != [NSUserDefaults.standardUserDefaults objectForKey:kMPSettingsKeyGlobalAutotypeDelay]) { - /* limit the delay to 1000 ms */ - delay = (useconds_t)MIN([NSUserDefaults.standardUserDefaults integerForKey:kMPSettingsKeyGlobalAutotypeDelay], 1000); - } - - + useconds_t globalDelay = 0; for(MPAutotypeCommand *command in [MPAutotypeCommand commandsForContext:context]) { + /* + FIXME: Introduce a global state for execution to allow command to set state value + e.g. [command executeWithContext:(MPCommandExectionContext *)context] + and inside the command set the sate e.g. context.delay = myDelay + then use this state in the command scheduling to set the global delay + */ + if([command isKindOfClass:MPAutotypeDelay.class]) { + MPAutotypeDelay *delayCommand = (MPAutotypeDelay *)command; + if(delayCommand.isGlobal) { + globalDelay = (useconds_t)delayCommand.delay; + } + } /* dispatch commands to main thread since most of them translate key events which is disallowed on background thread */ dispatch_async(dispatch_get_main_queue(), ^{ - if(delay > 0) { - usleep(delay * NSEC_PER_MSEC); + if(globalDelay > 0) { + usleep(globalDelay*NSEC_PER_USEC); } [command execute]; }); diff --git a/MacPass/MPAutotypeDelay.h b/MacPass/MPAutotypeDelay.h index 5195af0d..75b26024 100644 --- a/MacPass/MPAutotypeDelay.h +++ b/MacPass/MPAutotypeDelay.h @@ -25,6 +25,7 @@ @interface MPAutotypeDelay : MPAutotypeCommand @property (readonly) NSUInteger delay; +@property (readonly) BOOL isGlobal; /** * Creates an DelayCommand that delays the execution for n milliseconds * @@ -33,5 +34,6 @@ * @return <#return value description#> */ - (instancetype)initWithDelay:(NSUInteger)delay; +- (instancetype)initWithGlobalDelay:(NSUInteger)delay; @end diff --git a/MacPass/MPAutotypeDelay.m b/MacPass/MPAutotypeDelay.m index f76f12f7..b49281f4 100644 --- a/MacPass/MPAutotypeDelay.m +++ b/MacPass/MPAutotypeDelay.m @@ -29,7 +29,7 @@ @implementation MPAutotypeDelay - (id)init { - self = [self initWithDelay:0]; + self = [self _initWithDelay:0 global:NO]; return self; } @@ -38,17 +38,32 @@ } - (instancetype)initWithDelay:(NSUInteger)delay { + self = [self _initWithDelay:delay global:NO]; + return self; +} + +- (instancetype)initWithGlobalDelay:(NSUInteger)delay { + self = [self _initWithDelay:delay global:YES]; + return self; +} + +- (instancetype)_initWithDelay:(NSUInteger)delay global:(BOOL)global { self = [super init]; if(self) { + _isGlobal = global; /* Delays longer than a minute are a bit long */ - _delay = MIN(60*1000,delay); + _delay = MIN(60*NSEC_PER_USEC,delay); } return self; + } - (void)execute { /* milliseconds * 10000 = microseconds */ - usleep((useconds_t)(self.delay*1000)); + if(self.isGlobal) { + return; // global delays should not be executed locally + } + usleep((useconds_t)(self.delay*NSEC_PER_USEC)); } @end diff --git a/MacPass/MPAutotypeParser.m b/MacPass/MPAutotypeParser.m index 0efe0755..9046e9f3 100644 --- a/MacPass/MPAutotypeParser.m +++ b/MacPass/MPAutotypeParser.m @@ -281,7 +281,7 @@ static CGKeyCode kMPNumpadKeyCodes[] = { static NSRegularExpression *delayRegExp; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - NSString *delayPattern = [[NSString alloc] initWithFormat:@"\\{(%@|%@)[ |=]+([0-9]+)\\}", + NSString *delayPattern = [[NSString alloc] initWithFormat:@"\\{(%@|%@)([ |=])+([0-9]+)\\}", kKPKAutotypeDelay, kKPKAutotypeVirtualKey/*, kKPKAutotypeVirtualExtendedKey, @@ -327,9 +327,10 @@ static CGKeyCode kMPNumpadKeyCodes[] = { // TODO: add {APPLICATION } /* Delay */ NSTextCheckingResult *result = [delayRegExp firstMatchInString:commandString options:0 range:NSMakeRange(0, commandString.length)]; - if(result && (result.numberOfRanges == 3)) { + if(result && (result.numberOfRanges == 4)) { NSString *uppercaseCommand = [[commandString substringWithRange:[result rangeAtIndex:1]] uppercaseString]; - NSString *valueString = [commandString substringWithRange:[result rangeAtIndex:2]]; + NSString *assignOrNot = [commandString substringWithRange:[result rangeAtIndex:2]]; + NSString *valueString = [commandString substringWithRange:[result rangeAtIndex:3]]; NSScanner *numberScanner = [[NSScanner alloc] initWithString:valueString]; NSInteger value; if([numberScanner scanInteger:&value]) { @@ -337,7 +338,12 @@ static CGKeyCode kMPNumpadKeyCodes[] = { if(MAX(0, value) <= 0) { return; // Value too low, just skipp } - [self.mutableCommands addObject:[[MPAutotypeDelay alloc] initWithDelay:value]]; + if([assignOrNot isEqualToString:@"="]) { + [self.mutableCommands addObject:[[MPAutotypeDelay alloc] initWithGlobalDelay:value]]; + } + else { + [self.mutableCommands addObject:[[MPAutotypeDelay alloc] initWithDelay:value]]; + } return; // Done } else if([kKPKAutotypeVirtualKey isEqualToString:uppercaseCommand]) { diff --git a/MacPassTests/MPTestAutotypeDelay.m b/MacPassTests/MPTestAutotypeDelay.m index e2238fd8..5e0f78d2 100644 --- a/MacPassTests/MPTestAutotypeDelay.m +++ b/MacPassTests/MPTestAutotypeDelay.m @@ -31,7 +31,7 @@ [super tearDown]; } -- (void)testValidDelayCommands { +- (void)testLocalDelayCommands { /* Command 1 */ MPAutotypeContext *context = [[MPAutotypeContext alloc] initWithEntry:self.entry andSequence:@"{DELAY 200}"]; NSArray *commands = [MPAutotypeCommand commandsForContext:context]; @@ -41,8 +41,23 @@ XCTAssertTrue([commands.firstObject isKindOfClass:[MPAutotypeDelay class]], @"Command is Delay command"); MPAutotypeDelay *delay = commands.firstObject; XCTAssertEqual(delay.delay, 200, @"Delay is 200 ms"); + XCTAssertFalse(delay.isGlobal, @"Delay is no global delay"); } +- (void)testGlobalDelayCommands { + /* Command 1 */ + MPAutotypeContext *context = [[MPAutotypeContext alloc] initWithEntry:self.entry andSequence:@"{DELAY=200}"]; + NSArray *commands = [MPAutotypeCommand commandsForContext:context]; + + XCTAssertEqual(commands.count, 1); + /* {DELAY=200} */ + XCTAssertTrue([commands.firstObject isKindOfClass:MPAutotypeDelay.class], @"Command is Delay command"); + MPAutotypeDelay *delay = commands.firstObject; + XCTAssertEqual(delay.delay, 200, @"Delay is 200 ms"); + XCTAssertTrue(delay.isGlobal, @"Delay is global delay"); +} + + - (void)testDelayExecution { MPAutotypeDelay *delay = [[MPAutotypeDelay alloc] initWithDelay:200]; XCTestExpectation *expectation = [self expectationWithDescription:delay.description];