Refactored Autotype to use environment for better encapsulation of parameters

This commit is contained in:
Michael Starke
2020-01-22 15:11:28 +01:00
parent 2216a14729
commit 77d96976ec
6 changed files with 57 additions and 56 deletions

View File

@@ -25,12 +25,12 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class MPAutotypeEnvironment; @class MPAutotypeEnvironment;
@class MPAutotypeContext;
@interface MPAutotypeCandidateSelectionViewController : NSViewController @interface MPAutotypeCandidateSelectionViewController : NSViewController
@property (strong) MPAutotypeEnvironment *environment; @property (strong) MPAutotypeEnvironment *environment;
@property (copy) NSArray *candidates; @property (copy) NSArray<MPAutotypeContext *> *candidates;
@property (copy) NSString *windowTitle;
- (IBAction)selectAutotypeContext:(id)sender; - (IBAction)selectAutotypeContext:(id)sender;
- (IBAction)cancelSelection:(id)sender; - (IBAction)cancelSelection:(id)sender;

View File

@@ -22,6 +22,7 @@
#import "MPAutotypeCandidateSelectionViewController.h" #import "MPAutotypeCandidateSelectionViewController.h"
#import "MPAutotypeContext.h" #import "MPAutotypeContext.h"
#import "MPAutotypeDaemon.h" #import "MPAutotypeDaemon.h"
#import "MPAutotypeEnvironment.h"
#import "KPKNode+IconImage.h" #import "KPKNode+IconImage.h"
@@ -43,7 +44,7 @@
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
NSString *template = NSLocalizedString(@"AUTOTYPE_CANDIDATE_SELECTION_WINDOW_MESSAGE_%@", "Message text in the autotype selection window. Placeholder is %1 - windowTitle"); NSString *template = NSLocalizedString(@"AUTOTYPE_CANDIDATE_SELECTION_WINDOW_MESSAGE_%@", "Message text in the autotype selection window. Placeholder is %1 - windowTitle");
self.messageTextField.stringValue = [NSString stringWithFormat:template, self.windowTitle]; self.messageTextField.stringValue = [NSString stringWithFormat:template, self.environment.windowTitle];
self.selectAutotypeContextButton.enabled = NO; self.selectAutotypeContextButton.enabled = NO;
NSNotification *notification = [NSNotification notificationWithName:NSTableViewSelectionDidChangeNotification object:self.contextTableView]; NSNotification *notification = [NSNotification notificationWithName:NSTableViewSelectionDidChangeNotification object:self.contextTableView];
[self tableViewSelectionDidChange:notification]; [self tableViewSelectionDidChange:notification];
@@ -80,7 +81,7 @@
- (void)selectAutotypeContext:(id)sender { - (void)selectAutotypeContext:(id)sender {
NSInteger selectedRow = self.contextTableView.selectedRow; NSInteger selectedRow = self.contextTableView.selectedRow;
if(selectedRow >= 0 && selectedRow < self.candidates.count) { if(selectedRow >= 0 && selectedRow < self.candidates.count) {
[MPAutotypeDaemon.defaultDaemon selectAutotypeCandiate:self.candidates[selectedRow]]; [MPAutotypeDaemon.defaultDaemon selectAutotypeContext:self.candidates[selectedRow] forEnvironment:self.environment];
} }
else { else {
[self cancelSelection:sender]; // cancel since the selection was invalid! [self cancelSelection:sender]; // cancel since the selection was invalid!
@@ -88,7 +89,7 @@
} }
- (void)cancelSelection:(id)sender { - (void)cancelSelection:(id)sender {
[MPAutotypeDaemon.defaultDaemon cancelAutotypeCandidateSelection]; [MPAutotypeDaemon.defaultDaemon cancelAutotypeContextSelectionForEnvironment:self.environment];
} }

View File

@@ -40,7 +40,7 @@
- (void)performAutotypeForEntry:(KPKEntry *)entry; - (void)performAutotypeForEntry:(KPKEntry *)entry;
- (void)performAutotypeForEntry:(KPKEntry *)entry overrideSequence:(NSString *)sequence; - (void)performAutotypeForEntry:(KPKEntry *)entry overrideSequence:(NSString *)sequence;
- (void)selectAutotypeCandiate:(MPAutotypeContext *)context forEnvironment:(MPAutotypeEnvironment *)environment; - (void)selectAutotypeContext:(MPAutotypeContext *)context forEnvironment:(MPAutotypeEnvironment *)environment;
- (void)cancelAutotypeCandidateSelectionForEnvironment:(MPAutotypeEnvironment *)environment; - (void)cancelAutotypeContextSelectionForEnvironment:(MPAutotypeEnvironment *)environment;
@end @end

View File

@@ -154,23 +154,25 @@ static MPAutotypeDaemon *_sharedInstance;
} }
#pragma mark - #pragma mark -
#pragma mark Actions #pragma mark Autotype Execution
- (void)selectAutotypeCandiate:(MPAutotypeContext *)context forEnvironment:(MPAutotypeEnvironment *)environment { - (void)selectAutotypeContext:(MPAutotypeContext *)context forEnvironment:(MPAutotypeEnvironment *)environment {
[self.matchSelectionWindow orderOut:self]; [self.matchSelectionWindow orderOut:self];
self.matchSelectionWindow = nil; self.matchSelectionWindow = nil;
[self _runAutotypeWithEnvirnment:environment forContext:context]; [self _runAutotypeWithEnvironment:environment forContext:context];
} if(environment.hidden) {
[NSApplication.sharedApplication hide:nil];
- (void)cancelAutotypeCandidateSelectionForEnvironment:(MPAutotypeEnvironment *)environment { }
[self.matchSelectionWindow orderOut:self]; }
self.matchSelectionWindow = nil;
if(self.targetPID) { - (void)cancelAutotypeContextSelectionForEnvironment:(MPAutotypeEnvironment *)environment {
[self _orderApplicationToFront:self.targetPID forContext:nil]; [self.matchSelectionWindow orderOut:self];
self.matchSelectionWindow = nil;
[NSApplication.sharedApplication hide:nil];
if(environment.pid) {
[self _orderApplicationToFront:environment.pid completionHandler:nil];
} }
} }
#pragma mark -
#pragma mark Autotype Execution
- (void)_runAutotypeAfterDatabaseUnlockWithEnvironment:(MPAutotypeEnvironment *)environment requestedAt:(NSTimeInterval)requestTime { - (void)_runAutotypeAfterDatabaseUnlockWithEnvironment:(MPAutotypeEnvironment *)environment requestedAt:(NSTimeInterval)requestTime {
NSTimeInterval now = NSDate.date.timeIntervalSinceReferenceDate; NSTimeInterval now = NSDate.date.timeIntervalSinceReferenceDate;
if(now - requestTime > 30) { if(now - requestTime > 30) {
@@ -249,12 +251,12 @@ static MPAutotypeDaemon *_sharedInstance;
return; // wait for the unlock to happen return; // wait for the unlock to happen
} }
MPAutotypeContext *context = [self _autotypeContextForDocuments:documents forWindowTitle:env.windowTitle preferredEntry:env.entry]; MPAutotypeContext *context = [self _autotypeContextForDocuments:documents withEnvironment:env];
/* TODO: that's popping up if the multi selection dialog goes up! */ /* TODO: that's popping up if the multi selection dialog goes up! */
if(self.matchSelectionWindow) { if(self.matchSelectionWindow) {
return; // we present the match selection window, just return return; // we present the match selection window, just return
} }
if(!env.entry) { if(!env.preferredEntry) {
NSUserNotification *notification = [[NSUserNotification alloc] init]; NSUserNotification *notification = [[NSUserNotification alloc] init];
notification.title = NSApp.applicationName; notification.title = NSApp.applicationName;
notification.userInfo = @{ MPUserNotificationTypeKey: MPUserNotificationTypeAutotypeFeedback }; notification.userInfo = @{ MPUserNotificationTypeKey: MPUserNotificationTypeAutotypeFeedback };
@@ -266,17 +268,17 @@ static MPAutotypeDaemon *_sharedInstance;
} }
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification]; [NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
} }
[self _performAutotypeForContext:context]; [self _runAutotypeWithEnvironment:env forContext:context];
} }
- (MPAutotypeContext *)_autotypeContextForDocuments:(NSArray<MPDocument *> *)documents forWindowTitle:(NSString *)windowTitle preferredEntry:(KPKEntry *)entry { - (MPAutotypeContext *)_autotypeContextForDocuments:(NSArray<MPDocument *> *)documents withEnvironment:(MPAutotypeEnvironment *)environment {
/* /*
Query the document to generate a autotype command list for the window title Query the document to generate a autotype command list for the window title
We do not care where this came form, just get the autotype commands We do not care where this came form, just get the autotype commands
*/ */
NSMutableArray *autotypeCandidates = [[NSMutableArray alloc] init]; NSMutableArray *autotypeCandidates = [[NSMutableArray alloc] init];
for(MPDocument *document in documents) { for(MPDocument *document in documents) {
NSArray *contexts = [document autotypContextsForWindowTitle:windowTitle preferredEntry:entry]; NSArray *contexts = [document autotypContextsForWindowTitle:environment.windowTitle preferredEntry:environment.preferredEntry];
if(contexts ) { if(contexts ) {
[autotypeCandidates addObjectsFromArray:contexts]; [autotypeCandidates addObjectsFromArray:contexts];
} }
@@ -285,20 +287,22 @@ static MPAutotypeDaemon *_sharedInstance;
if(autotypeCandidates.count <= 1) { if(autotypeCandidates.count <= 1) {
return autotypeCandidates.lastObject; return autotypeCandidates.lastObject;
} }
[self _presentCandiadates:autotypeCandidates forEnvironment:environment];
[self _presentCandiadates:autotypeCandidates forWindowTitle:windowTitle];
return nil; // Nothing to do, we get called back by the window return nil; // Nothing to do, we get called back by the window
} }
- (void)_runAutotypeWithEnvirnment:(MPAutotypeEnvironment *)environment forContext:(MPAutotypeContext *)context { - (void)_runAutotypeWithEnvironment:(MPAutotypeEnvironment *)environment forContext:(MPAutotypeContext *)context {
if(nil == environment) { if(nil == environment) {
return; // no Environment to work in return; // no Environment to work in
} }
if(nil == context) { if(nil == context) {
return; // No context to work with return; // No context to work with
} }
__weak MPAutotypeDaemon *welf = self;
if(NO == [self _orderApplicationToFront:self.targetPID forContext:(MPAutotypeContext *)context]) { BOOL appIsFrontmost = [self _orderApplicationToFront:environment.pid completionHandler:^{
[welf _runAutotypeWithEnvironment:environment forContext:context];
}];
if(!appIsFrontmost) {
return; // We will get called back when the application is in front - hopfully return; // We will get called back when the application is in front - hopfully
} }
@@ -346,7 +350,7 @@ static MPAutotypeDaemon *_sharedInstance;
} }
} }
- (void)_presentCandiadates:(NSArray *)candidates forWindowTitle:(NSString *)windowTitle { - (void)_presentCandiadates:(NSArray *)candidates forEnvironment:(MPAutotypeEnvironment *)environment {
if(!self.matchSelectionWindow) { if(!self.matchSelectionWindow) {
self.matchSelectionWindow = [[NSPanel alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100) self.matchSelectionWindow = [[NSPanel alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
styleMask:NSWindowStyleMaskNonactivatingPanel|NSWindowStyleMaskTitled styleMask:NSWindowStyleMaskNonactivatingPanel|NSWindowStyleMaskTitled
@@ -355,12 +359,7 @@ static MPAutotypeDaemon *_sharedInstance;
self.matchSelectionWindow.level = kCGAssistiveTechHighWindowLevel; self.matchSelectionWindow.level = kCGAssistiveTechHighWindowLevel;
MPAutotypeCandidateSelectionViewController *vc = [[MPAutotypeCandidateSelectionViewController alloc] init]; MPAutotypeCandidateSelectionViewController *vc = [[MPAutotypeCandidateSelectionViewController alloc] init];
vc.candidates = candidates; vc.candidates = candidates;
vc.windowTitle = windowTitle; vc.environment = environment;
if(NSRunningApplication.currentApplication.isHidden) {
vc.completionHandler = ^{
[NSRunningApplication.currentApplication hide];
};
}
self.matchSelectionWindow.collectionBehavior |= (NSWindowCollectionBehaviorFullScreenAuxiliary | self.matchSelectionWindow.collectionBehavior |= (NSWindowCollectionBehaviorFullScreenAuxiliary |
NSWindowCollectionBehaviorMoveToActiveSpace | NSWindowCollectionBehaviorMoveToActiveSpace |
NSWindowCollectionBehaviorTransient ); NSWindowCollectionBehaviorTransient );
@@ -380,27 +379,24 @@ static MPAutotypeDaemon *_sharedInstance;
#pragma mark - #pragma mark -
#pragma mark Application information #pragma mark Application information
- (BOOL)_orderApplicationToFront:(pid_t)processIdentifier inEnvironment:(MPAutotypeEnvironment *) environment { //- (BOOL)_orderApplicationToFront:(pid_t)processIdentifier inEnvironment:(MPAutotypeEnvironment *) environment {
- (BOOL)_orderApplicationToFront:(pid_t)processIdentifier forContext:(MPAutotypeContext *)context { - (BOOL)_orderApplicationToFront:(pid_t)processIdentifier completionHandler:(void (^_Nullable)(void))completionHandler {
NSRunningApplication *runingApplication = [NSRunningApplication runningApplicationWithProcessIdentifier:processIdentifier]; NSRunningApplication *runingApplication = [NSRunningApplication runningApplicationWithProcessIdentifier:processIdentifier];
NSRunningApplication *frontApplication = NSWorkspace.sharedWorkspace.frontmostApplication; NSRunningApplication *frontApplication = NSWorkspace.sharedWorkspace.frontmostApplication;
if(frontApplication.processIdentifier == processIdentifier) { if(frontApplication.processIdentifier == processIdentifier) {
return YES; return YES;
} }
/* cleanup before to make sure everything is top notch */ NSNotificationCenter * __weak nc = NSWorkspace.sharedWorkspace.notificationCenter;
if(self.applicationActivationObserver) { id __block didActivateToken = [nc addObserverForName:NSWorkspaceDidActivateApplicationNotification
[NSWorkspace.sharedWorkspace.notificationCenter removeObserver:self.applicationActivationObserver name:NSWorkspaceDidActivateApplicationNotification object:nil]; object:nil
self.applicationActivationObserver = nil; queue:NSOperationQueue.mainQueue
} usingBlock:^(NSNotification *notification) {
[nc removeObserver:didActivateToken];
self.applicationActivationObserver = [NSWorkspace.sharedWorkspace.notificationCenter addObserverForName:NSWorkspaceDidActivateApplicationNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { if(completionHandler) {
if(self.applicationActivationObserver) { completionHandler();
[NSWorkspace.sharedWorkspace.notificationCenter removeObserver:self.applicationActivationObserver name:NSWorkspaceDidActivateApplicationNotification object:nil];
} }
[self _performAutotypeForContext:context];
}]; }];
[runingApplication activateWithOptions:NSApplicationActivateIgnoringOtherApps]; [runingApplication activateWithOptions:NSApplicationActivateIgnoringOtherApps];
return NO; return NO;
} }

View File

@@ -15,11 +15,15 @@ NS_ASSUME_NONNULL_BEGIN
@interface MPAutotypeEnvironment : NSObject @interface MPAutotypeEnvironment : NSObject
@property (readonly, weak) KPKEntry *entry; /**
@property (readonly) pid_t pid; The selected entry, if Autotype is run only for a single entry.
@property (readonly, copy) NSString *windowTitle; If autotype should search for entries, set this to nil.
@property (readonly) BOOL hidden; */
@property (readonly) BOOL isSelfTargeting; @property (readonly, weak, nullable) KPKEntry *preferredEntry;
@property (readonly) pid_t pid; // the PID of the target application to which the key strokes should be sent
@property (readonly, copy) NSString *windowTitle; /// The window title of the target application.
@property (readonly) BOOL hidden; /// If set to YES, MacPass was hidden when autotype was initiated
@property (readonly) BOOL isSelfTargeting; /// If MacPass should autotype to itself, YES, otherwise NO
+ (instancetype)environmentWithTargetApplication:(NSRunningApplication *)targetApplication entry:(KPKEntry * _Nullable)entry; + (instancetype)environmentWithTargetApplication:(NSRunningApplication *)targetApplication entry:(KPKEntry * _Nullable)entry;
- (instancetype)initWithTargetApplication:(NSRunningApplication *)targetApplication entry:(KPKEntry * _Nullable)entry NS_DESIGNATED_INITIALIZER; - (instancetype)initWithTargetApplication:(NSRunningApplication *)targetApplication entry:(KPKEntry * _Nullable)entry NS_DESIGNATED_INITIALIZER;

View File

@@ -20,7 +20,7 @@
- (instancetype)initWithTargetApplication:(NSRunningApplication *)targetApplication entry:(KPKEntry *)entry { - (instancetype)initWithTargetApplication:(NSRunningApplication *)targetApplication entry:(KPKEntry *)entry {
self = [super init]; self = [super init];
if(self) { if(self) {
_entry = entry; _preferredEntry = entry;
if(!targetApplication) { if(!targetApplication) {
_pid = -1; _pid = -1;
_windowTitle = @""; _windowTitle = @"";