mirror of
https://github.com/MacPass/MacPass.git
synced 2025-12-17 20:49:28 +00:00
Refactored Autotype to use environment for better encapsulation of parameters
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 = @"";
|
||||||
|
|||||||
Reference in New Issue
Block a user