mirror of
https://github.com/MacPass/MacPass.git
synced 2026-02-02 05:18:15 +00:00
Merge branch 'feature/refactor_autotype'
This commit is contained in:
@@ -41,6 +41,8 @@
|
|||||||
4C1F7FA21E3A12E600D6A40E /* MPModifiedKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1F7FA11E3A12E600D6A40E /* MPModifiedKey.m */; };
|
4C1F7FA21E3A12E600D6A40E /* MPModifiedKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1F7FA11E3A12E600D6A40E /* MPModifiedKey.m */; };
|
||||||
4C1FA07B18231900003A3F8C /* MPDocument+Autotype.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1FA07A18231900003A3F8C /* MPDocument+Autotype.m */; };
|
4C1FA07B18231900003A3F8C /* MPDocument+Autotype.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1FA07A18231900003A3F8C /* MPDocument+Autotype.m */; };
|
||||||
4C2057EE23CDF6F900C731EC /* MPPathCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C2057ED23CDF6F900C731EC /* MPPathCell.m */; };
|
4C2057EE23CDF6F900C731EC /* MPPathCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C2057ED23CDF6F900C731EC /* MPPathCell.m */; };
|
||||||
|
4C2057F423CF3BA600C731EC /* MPAutotypeEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C2057F323CF3BA600C731EC /* MPAutotypeEnvironment.m */; };
|
||||||
|
4C2057F723CF3E9A00C731EC /* NSRunningApplication+MPAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C2057F623CF3E9A00C731EC /* NSRunningApplication+MPAdditions.m */; };
|
||||||
4C224B4217DFCB2400FF6AEE /* MPNumericalInputFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C224B4117DFCB2400FF6AEE /* MPNumericalInputFormatter.m */; };
|
4C224B4217DFCB2400FF6AEE /* MPNumericalInputFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C224B4117DFCB2400FF6AEE /* MPNumericalInputFormatter.m */; };
|
||||||
4C25703F1BF11C2300D39416 /* MPPluginPreferencesController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C25703D1BF11C2300D39416 /* MPPluginPreferencesController.m */; };
|
4C25703F1BF11C2300D39416 /* MPPluginPreferencesController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C25703D1BF11C2300D39416 /* MPPluginPreferencesController.m */; };
|
||||||
4C25D58716CF0FAA00F6806C /* EntryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C25D58616CF0FAA00F6806C /* EntryView.xib */; };
|
4C25D58716CF0FAA00F6806C /* EntryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C25D58616CF0FAA00F6806C /* EntryView.xib */; };
|
||||||
@@ -405,6 +407,10 @@
|
|||||||
4C2057EC23CDF6F900C731EC /* MPPathCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPathCell.h; sourceTree = "<group>"; };
|
4C2057EC23CDF6F900C731EC /* MPPathCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPathCell.h; sourceTree = "<group>"; };
|
||||||
4C2057ED23CDF6F900C731EC /* MPPathCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPathCell.m; sourceTree = "<group>"; };
|
4C2057ED23CDF6F900C731EC /* MPPathCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPathCell.m; sourceTree = "<group>"; };
|
||||||
4C2057EF23CDFC2000C731EC /* MPPathControl+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MPPathControl+Private.h"; sourceTree = "<group>"; };
|
4C2057EF23CDFC2000C731EC /* MPPathControl+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MPPathControl+Private.h"; sourceTree = "<group>"; };
|
||||||
|
4C2057F223CF3BA600C731EC /* MPAutotypeEnvironment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPAutotypeEnvironment.h; sourceTree = "<group>"; };
|
||||||
|
4C2057F323CF3BA600C731EC /* MPAutotypeEnvironment.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPAutotypeEnvironment.m; sourceTree = "<group>"; };
|
||||||
|
4C2057F523CF3E9A00C731EC /* NSRunningApplication+MPAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSRunningApplication+MPAdditions.h"; sourceTree = "<group>"; };
|
||||||
|
4C2057F623CF3E9A00C731EC /* NSRunningApplication+MPAdditions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSRunningApplication+MPAdditions.m"; sourceTree = "<group>"; };
|
||||||
4C21F29F195B3A48002D610D /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/MainMenu.strings; sourceTree = "<group>"; };
|
4C21F29F195B3A48002D610D /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/MainMenu.strings; sourceTree = "<group>"; };
|
||||||
4C224B4017DFCB2300FF6AEE /* MPNumericalInputFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPNumericalInputFormatter.h; sourceTree = "<group>"; };
|
4C224B4017DFCB2300FF6AEE /* MPNumericalInputFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPNumericalInputFormatter.h; sourceTree = "<group>"; };
|
||||||
4C224B4117DFCB2400FF6AEE /* MPNumericalInputFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNumericalInputFormatter.m; sourceTree = "<group>"; };
|
4C224B4117DFCB2400FF6AEE /* MPNumericalInputFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNumericalInputFormatter.m; sourceTree = "<group>"; };
|
||||||
@@ -1128,6 +1134,8 @@
|
|||||||
4C58A4A22192EC1600B13370 /* NSIndexPath+MPAdditions.m */,
|
4C58A4A22192EC1600B13370 /* NSIndexPath+MPAdditions.m */,
|
||||||
3C0CDECD21CFED9000B2A10B /* NSTextView+MPTouchBarExtension.h */,
|
3C0CDECD21CFED9000B2A10B /* NSTextView+MPTouchBarExtension.h */,
|
||||||
3C0CDECE21CFEDD200B2A10B /* NSTextView+MPTouchBarExtension.m */,
|
3C0CDECE21CFEDD200B2A10B /* NSTextView+MPTouchBarExtension.m */,
|
||||||
|
4C2057F523CF3E9A00C731EC /* NSRunningApplication+MPAdditions.h */,
|
||||||
|
4C2057F623CF3E9A00C731EC /* NSRunningApplication+MPAdditions.m */,
|
||||||
);
|
);
|
||||||
name = Categories;
|
name = Categories;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1521,6 +1529,8 @@
|
|||||||
4C90757B18A42E7A00E598DA /* Commands */,
|
4C90757B18A42E7A00E598DA /* Commands */,
|
||||||
4CEE46DB181C301D006BF1E5 /* MPAutotypeDaemon.h */,
|
4CEE46DB181C301D006BF1E5 /* MPAutotypeDaemon.h */,
|
||||||
4CEE46DC181C301D006BF1E5 /* MPAutotypeDaemon.m */,
|
4CEE46DC181C301D006BF1E5 /* MPAutotypeDaemon.m */,
|
||||||
|
4C2057F223CF3BA600C731EC /* MPAutotypeEnvironment.h */,
|
||||||
|
4C2057F323CF3BA600C731EC /* MPAutotypeEnvironment.m */,
|
||||||
4CD2B9041849424B0051B395 /* MPAutotypeContext.h */,
|
4CD2B9041849424B0051B395 /* MPAutotypeContext.h */,
|
||||||
4CD2B9051849424B0051B395 /* MPAutotypeContext.m */,
|
4CD2B9051849424B0051B395 /* MPAutotypeContext.m */,
|
||||||
4CA3530918A53CB800839B0F /* MPKeyMapper.h */,
|
4CA3530918A53CB800839B0F /* MPKeyMapper.h */,
|
||||||
@@ -2044,6 +2054,7 @@
|
|||||||
4CE39AC416ECE4F7000FE29D /* MPIconImageView.m in Sources */,
|
4CE39AC416ECE4F7000FE29D /* MPIconImageView.m in Sources */,
|
||||||
4C46B88517063A070046109A /* NSString+MPPasswordCreation.m in Sources */,
|
4C46B88517063A070046109A /* NSString+MPPasswordCreation.m in Sources */,
|
||||||
4C5A11FE1708DE8700223D8A /* MPPasswordCreatorViewController.m in Sources */,
|
4C5A11FE1708DE8700223D8A /* MPPasswordCreatorViewController.m in Sources */,
|
||||||
|
4C2057F423CF3BA600C731EC /* MPAutotypeEnvironment.m in Sources */,
|
||||||
4CE5B54B173AFBA700207B39 /* MPDocument.m in Sources */,
|
4CE5B54B173AFBA700207B39 /* MPDocument.m in Sources */,
|
||||||
4CE082C31F6FCD2A0034FF56 /* MPCollectionView.m in Sources */,
|
4CE082C31F6FCD2A0034FF56 /* MPCollectionView.m in Sources */,
|
||||||
4C4A100F176286FD00BBF2CA /* MPTableView.m in Sources */,
|
4C4A100F176286FD00BBF2CA /* MPTableView.m in Sources */,
|
||||||
@@ -2092,6 +2103,7 @@
|
|||||||
4CAD8AA622CF397B0090B2DD /* MPAutotypeDoctorReportViewController.m in Sources */,
|
4CAD8AA622CF397B0090B2DD /* MPAutotypeDoctorReportViewController.m in Sources */,
|
||||||
4C8990F71EE978EB0043B48D /* MPDuplicateEntryOptionsWindowController.m in Sources */,
|
4C8990F71EE978EB0043B48D /* MPDuplicateEntryOptionsWindowController.m in Sources */,
|
||||||
4CA3530B18A53CB800839B0F /* MPKeyMapper.m in Sources */,
|
4CA3530B18A53CB800839B0F /* MPKeyMapper.m in Sources */,
|
||||||
|
4C2057F723CF3E9A00C731EC /* NSRunningApplication+MPAdditions.m in Sources */,
|
||||||
4CE298EB1795FC2A00DF7BDB /* MPEntryContextMenuDelegate.m in Sources */,
|
4CE298EB1795FC2A00DF7BDB /* MPEntryContextMenuDelegate.m in Sources */,
|
||||||
4CCCE8011D75CA48006AA951 /* MPArrayController.m in Sources */,
|
4CCCE8011D75CA48006AA951 /* MPArrayController.m in Sources */,
|
||||||
4CC0D2CE17974A47000B4BDA /* MPCustomFieldTableViewDelegate.m in Sources */,
|
4CC0D2CE17974A47000B4BDA /* MPCustomFieldTableViewDelegate.m in Sources */,
|
||||||
|
|||||||
@@ -24,11 +24,13 @@
|
|||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class MPAutotypeEnvironment;
|
||||||
|
@class MPAutotypeContext;
|
||||||
|
|
||||||
@interface MPAutotypeCandidateSelectionViewController : NSViewController
|
@interface MPAutotypeCandidateSelectionViewController : NSViewController
|
||||||
|
|
||||||
@property (copy) NSArray *candidates;
|
@property (strong) MPAutotypeEnvironment *environment;
|
||||||
@property (copy) NSString *windowTitle;
|
@property (copy) NSArray<MPAutotypeContext *> *candidates;
|
||||||
@property (nonatomic, copy, nullable) void (^completionHandler)(void);
|
|
||||||
|
|
||||||
- (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,10 +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) {
|
||||||
if(self.completionHandler) {
|
[MPAutotypeDaemon.defaultDaemon selectAutotypeContext:self.candidates[selectedRow] forEnvironment:self.environment];
|
||||||
self.completionHandler();
|
|
||||||
}
|
|
||||||
[MPAutotypeDaemon.defaultDaemon selectAutotypeCandiate:self.candidates[selectedRow]];
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
[self cancelSelection:sender]; // cancel since the selection was invalid!
|
[self cancelSelection:sender]; // cancel since the selection was invalid!
|
||||||
@@ -91,10 +89,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancelSelection:(id)sender {
|
- (void)cancelSelection:(id)sender {
|
||||||
if(self.completionHandler) {
|
[MPAutotypeDaemon.defaultDaemon cancelAutotypeContextSelectionForEnvironment:self.environment];
|
||||||
self.completionHandler();
|
|
||||||
}
|
|
||||||
[MPAutotypeDaemon.defaultDaemon cancelAutotypeCandidateSelection];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
@class DDHotKey;
|
@class DDHotKey;
|
||||||
@class KPKEntry;
|
@class KPKEntry;
|
||||||
@class MPAutotypeContext;
|
@class MPAutotypeContext;
|
||||||
@class MPAutotypeExecutionContext;
|
@class MPAutotypeEnvironment;
|
||||||
/**
|
/**
|
||||||
* The autotype daemon is responsible for registering the global hotkey and to perform any autotype actions
|
* The autotype daemon is responsible for registering the global hotkey and to perform any autotype actions
|
||||||
*/
|
*/
|
||||||
@@ -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;
|
- (void)selectAutotypeContext:(MPAutotypeContext *)context forEnvironment:(MPAutotypeEnvironment *)environment;
|
||||||
- (void)cancelAutotypeCandidateSelection;
|
- (void)cancelAutotypeContextSelectionForEnvironment:(MPAutotypeEnvironment *)environment;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#import "MPDocumentWindowController.h"
|
#import "MPDocumentWindowController.h"
|
||||||
#import "MPAutotypeCommand.h"
|
#import "MPAutotypeCommand.h"
|
||||||
#import "MPAutotypeContext.h"
|
#import "MPAutotypeContext.h"
|
||||||
|
#import "MPAutotypeEnvironment.h"
|
||||||
#import "MPAutotypePaste.h"
|
#import "MPAutotypePaste.h"
|
||||||
#import "MPAutotypeDelay.h"
|
#import "MPAutotypeDelay.h"
|
||||||
#import "MPPasteBoardController.h"
|
#import "MPPasteBoardController.h"
|
||||||
@@ -45,16 +46,12 @@
|
|||||||
#import "KeePassKit/KeePassKit.h"
|
#import "KeePassKit/KeePassKit.h"
|
||||||
#import <Carbon/Carbon.h>
|
#import <Carbon/Carbon.h>
|
||||||
|
|
||||||
NSString *const kMPWindowTitleKey = @"kMPWindowTitleKey";
|
|
||||||
NSString *const kMPProcessIdentifierKey = @"kMPProcessIdentifierKey";
|
|
||||||
|
|
||||||
@interface MPAutotypeDaemon ()
|
@interface MPAutotypeDaemon ()
|
||||||
|
|
||||||
@property (nonatomic, assign) BOOL enabled;
|
@property (nonatomic, assign) BOOL enabled;
|
||||||
@property (nonatomic, copy) NSData *hotKeyData;
|
@property (nonatomic, copy) NSData *hotKeyData;
|
||||||
@property (strong) DDHotKey *registredHotKey;
|
@property (strong) DDHotKey *registredHotKey;
|
||||||
@property (assign) pid_t targetPID; // The pid of the process we want to sent commands to
|
|
||||||
@property (copy) NSString *targetWindowTitle; // The title of the window that we are targeting
|
|
||||||
@property (strong) NSRunningApplication *previousApplication; // The application that was active before we got invoked
|
@property (strong) NSRunningApplication *previousApplication; // The application that was active before we got invoked
|
||||||
@property (assign) NSTimeInterval userActionRequested;
|
@property (assign) NSTimeInterval userActionRequested;
|
||||||
@property (strong) id applicationActivationObserver;
|
@property (strong) id applicationActivationObserver;
|
||||||
@@ -85,7 +82,6 @@ static MPAutotypeDaemon *_sharedInstance;
|
|||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_enabled = NO;
|
_enabled = NO;
|
||||||
_targetPID = -1;
|
|
||||||
_userActionRequested = NSDate.distantPast.timeIntervalSinceReferenceDate;
|
_userActionRequested = NSDate.distantPast.timeIntervalSinceReferenceDate;
|
||||||
[self bind:NSStringFromSelector(@selector(enabled))
|
[self bind:NSStringFromSelector(@selector(enabled))
|
||||||
toObject:NSUserDefaultsController.sharedUserDefaultsController
|
toObject:NSUserDefaultsController.sharedUserDefaultsController
|
||||||
@@ -144,38 +140,55 @@ static MPAutotypeDaemon *_sharedInstance;
|
|||||||
- (void)performAutotypeForEntry:(KPKEntry *)entry {
|
- (void)performAutotypeForEntry:(KPKEntry *)entry {
|
||||||
[self performAutotypeForEntry:entry overrideSequence:nil];
|
[self performAutotypeForEntry:entry overrideSequence:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)performAutotypeForEntry:(KPKEntry *)entry overrideSequence:(NSString *)sequence {
|
- (void)performAutotypeForEntry:(KPKEntry *)entry overrideSequence:(NSString *)sequence {
|
||||||
if(entry) {
|
if(entry) {
|
||||||
[self _updateTargeInformationForApplication:self.previousApplication];
|
MPAutotypeEnvironment *env = [MPAutotypeEnvironment environmentWithTargetApplication:self.previousApplication entry:entry];
|
||||||
[self _performAutotypeForEntry:entry];
|
[self _runAutotypeWithEnvironment:env];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_didPressHotKey {
|
- (void)_didPressHotKey {
|
||||||
[self _updateTargeInformationForApplication:NSWorkspace.sharedWorkspace.frontmostApplication];
|
MPAutotypeEnvironment *env = [MPAutotypeEnvironment environmentWithTargetApplication:NSWorkspace.sharedWorkspace.frontmostApplication entry:nil];
|
||||||
[self _performAutotypeForEntry:nil];
|
[self _runAutotypeWithEnvironment:env];
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
#pragma mark Actions
|
|
||||||
- (void)selectAutotypeCandiate:(MPAutotypeContext *)context {
|
|
||||||
[self.matchSelectionWindow orderOut:self];
|
|
||||||
self.matchSelectionWindow = nil;
|
|
||||||
[self _performAutotypeForContext:context];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)cancelAutotypeCandidateSelection {
|
|
||||||
[self.matchSelectionWindow orderOut:self];
|
|
||||||
self.matchSelectionWindow = nil;
|
|
||||||
if(self.targetPID) {
|
|
||||||
[self _orderApplicationToFront:self.targetPID forContext:nil];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Autotype Execution
|
#pragma mark Autotype Execution
|
||||||
|
- (void)selectAutotypeContext:(MPAutotypeContext *)context forEnvironment:(MPAutotypeEnvironment *)environment {
|
||||||
|
[self.matchSelectionWindow orderOut:self];
|
||||||
|
self.matchSelectionWindow = nil;
|
||||||
|
[self _runAutotypeWithEnvironment:environment forContext:context];
|
||||||
|
if(environment.hidden) {
|
||||||
|
[NSApplication.sharedApplication hide:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)cancelAutotypeContextSelectionForEnvironment:(MPAutotypeEnvironment *)environment {
|
||||||
|
[self.matchSelectionWindow orderOut:self];
|
||||||
|
self.matchSelectionWindow = nil;
|
||||||
|
[NSApplication.sharedApplication hide:nil];
|
||||||
|
if(environment.pid) {
|
||||||
|
[self _orderApplicationToFront:environment.pid completionHandler:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_runAutotypeAfterDatabaseUnlockWithEnvironment:(MPAutotypeEnvironment *)environment requestedAt:(NSTimeInterval)requestTime {
|
||||||
|
NSTimeInterval now = NSDate.date.timeIntervalSinceReferenceDate;
|
||||||
|
if(now - requestTime > 30) {
|
||||||
|
NSUserNotification *notification = [[NSUserNotification alloc] init];
|
||||||
|
notification.title = NSApp.applicationName;
|
||||||
|
notification.informativeText = NSLocalizedString(@"AUTOTYPE_TIMED_OUT", "Notficication: Autotype timed out");
|
||||||
|
notification.userInfo = @{ MPUserNotificationTypeKey: MPUserNotificationTypeAutotypeFeedback };
|
||||||
|
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[self _runAutotypeWithEnvironment:environment];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_runAutotypeWithEnvironment:(MPAutotypeEnvironment *)env {
|
||||||
|
|
||||||
- (void)_performAutotypeForEntry:(KPKEntry *)entryOrNil {
|
|
||||||
if(!self.hasNecessaryAutotypePermissions) {
|
if(!self.hasNecessaryAutotypePermissions) {
|
||||||
NSUserNotification *notification = [[NSUserNotification alloc] init];
|
NSUserNotification *notification = [[NSUserNotification alloc] init];
|
||||||
notification.title = NSApp.applicationName;
|
notification.title = NSApp.applicationName;
|
||||||
@@ -186,10 +199,6 @@ static MPAutotypeDaemon *_sharedInstance;
|
|||||||
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NSInteger pid = NSProcessInfo.processInfo.processIdentifier;
|
|
||||||
if(self.targetPID == pid) {
|
|
||||||
return; // We do not perform Autotype on ourselves
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find autotype documents */
|
/* find autotype documents */
|
||||||
NSArray *documents = NSApp.orderedDocuments;
|
NSArray *documents = NSApp.orderedDocuments;
|
||||||
@@ -202,8 +211,15 @@ static MPAutotypeDaemon *_sharedInstance;
|
|||||||
notification.userInfo = @{ MPUserNotificationTypeKey: MPUserNotificationTypeAutotypeOpenDocumentRequest };
|
notification.userInfo = @{ MPUserNotificationTypeKey: MPUserNotificationTypeAutotypeOpenDocumentRequest };
|
||||||
notification.showsButtons = YES;
|
notification.showsButtons = YES;
|
||||||
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
||||||
self.userActionRequested = NSDate.date.timeIntervalSinceReferenceDate;
|
NSNotificationCenter * __weak nc = [NSNotificationCenter defaultCenter];
|
||||||
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(_didUnlockDatabase:) name:MPDocumentDidUnlockDatabaseNotification object:nil];
|
MPAutotypeDaemon * __weak welf = self;
|
||||||
|
id __block unlockToken = [nc addObserverForName:MPDocumentDidUnlockDatabaseNotification
|
||||||
|
object:nil
|
||||||
|
queue:NSOperationQueue.mainQueue
|
||||||
|
usingBlock:^(NSNotification *notification) {
|
||||||
|
[welf _runAutotypeAfterDatabaseUnlockWithEnvironment:env requestedAt:NSDate.date.timeIntervalSinceReferenceDate];
|
||||||
|
[nc removeObserver:unlockToken];
|
||||||
|
}];
|
||||||
return; // Unlock should trigger autotype
|
return; // Unlock should trigger autotype
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,6 +227,7 @@ static MPAutotypeDaemon *_sharedInstance;
|
|||||||
MPDocument *document = evaluatedObject;
|
MPDocument *document = evaluatedObject;
|
||||||
return !document.encrypted;
|
return !document.encrypted;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
NSArray *unlockedDocuments = [documents filteredArrayUsingPredicate:filterPredicate];
|
NSArray *unlockedDocuments = [documents filteredArrayUsingPredicate:filterPredicate];
|
||||||
/* We look for all unlocked documents, if all open documents are locked, we pop the front most and try to search again */
|
/* We look for all unlocked documents, if all open documents are locked, we pop the front most and try to search again */
|
||||||
if(unlockedDocuments.count == 0) {
|
if(unlockedDocuments.count == 0) {
|
||||||
@@ -221,39 +238,47 @@ static MPAutotypeDaemon *_sharedInstance;
|
|||||||
[document showWindows];
|
[document showWindows];
|
||||||
MPDocumentWindowController *wc = document.windowControllers.firstObject;
|
MPDocumentWindowController *wc = document.windowControllers.firstObject;
|
||||||
[wc showPasswordInputWithMessage:NSLocalizedString(@"AUTOTYPE_MESSAGE_UNLOCK_DATABASE", @"Message displayed to the user to unlock the database to perform global autotype")];
|
[wc showPasswordInputWithMessage:NSLocalizedString(@"AUTOTYPE_MESSAGE_UNLOCK_DATABASE", @"Message displayed to the user to unlock the database to perform global autotype")];
|
||||||
self.userActionRequested = NSDate.date.timeIntervalSinceReferenceDate;
|
NSNotificationCenter * __weak nc = [NSNotificationCenter defaultCenter];
|
||||||
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(_didUnlockDatabase:) name:MPDocumentDidUnlockDatabaseNotification object:nil];
|
MPAutotypeDaemon * __weak welf = self;
|
||||||
|
id __block unlockToken = [nc addObserverForName:MPDocumentDidUnlockDatabaseNotification
|
||||||
|
object:nil
|
||||||
|
queue:NSOperationQueue.mainQueue
|
||||||
|
usingBlock:^(NSNotification *notification) {
|
||||||
|
[welf _runAutotypeAfterDatabaseUnlockWithEnvironment:env requestedAt:NSDate.date.timeIntervalSinceReferenceDate];
|
||||||
|
|
||||||
|
[nc removeObserver:unlockToken];
|
||||||
|
}];
|
||||||
return; // wait for the unlock to happen
|
return; // wait for the unlock to happen
|
||||||
}
|
}
|
||||||
|
|
||||||
MPAutotypeContext *context = [self _autotypeContextForDocuments:documents forWindowTitle:self.targetWindowTitle preferredEntry:entryOrNil];
|
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(!entryOrNil) {
|
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 };
|
||||||
if(context) {
|
if(context) {
|
||||||
notification.informativeText = [NSString stringWithFormat:NSLocalizedString(@"AUTOTYPE_OVERLAY_SINGLE_MATCH_FOR_%@", "Notification: Autotype found a single match for %@ (string placeholder)."), self.targetWindowTitle];
|
notification.informativeText = [NSString stringWithFormat:NSLocalizedString(@"AUTOTYPE_OVERLAY_SINGLE_MATCH_FOR_%@", "Notification: Autotype found a single match for %@ (string placeholder)."), env.windowTitle];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
notification.informativeText = [NSString stringWithFormat:NSLocalizedString(@"AUTOTYPE_OVERLAY_NO_MATCH_FOR_%@", "Noticiation: Autotype failed to find a match for %@ (string placeholder)"), self.targetWindowTitle];
|
notification.informativeText = [NSString stringWithFormat:NSLocalizedString(@"AUTOTYPE_OVERLAY_NO_MATCH_FOR_%@", "Noticiation: Autotype failed to find a match for %@ (string placeholder)"), env.windowTitle];
|
||||||
}
|
}
|
||||||
[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];
|
||||||
}
|
}
|
||||||
@@ -262,17 +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)_performAutotypeForContext:(MPAutotypeContext *)context {
|
- (void)_runAutotypeWithEnvironment:(MPAutotypeEnvironment *)environment forContext:(MPAutotypeContext *)context {
|
||||||
|
if(nil == environment) {
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,38 +350,7 @@ static MPAutotypeDaemon *_sharedInstance;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *)_infoDictionaryForApplication:(NSRunningApplication *)application {
|
- (void)_presentCandiadates:(NSArray *)candidates forEnvironment:(MPAutotypeEnvironment *)environment {
|
||||||
NSArray *currentWindows = CFBridgingRelease(CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID));
|
|
||||||
NSArray *windowNumbers = [NSWindow windowNumbersWithOptions:NSWindowNumberListAllApplications];
|
|
||||||
NSUInteger minZIndex = NSNotFound;
|
|
||||||
NSDictionary *infoDict = nil;
|
|
||||||
for(NSDictionary *windowDict in currentWindows) {
|
|
||||||
NSString *windowTitle = windowDict[(NSString *)kCGWindowName];
|
|
||||||
if(windowTitle.length <= 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
NSNumber *processId = windowDict[(NSString *)kCGWindowOwnerPID];
|
|
||||||
if(processId && [processId isEqualToNumber:@(application.processIdentifier)]) {
|
|
||||||
|
|
||||||
NSNumber *number = (NSNumber *)windowDict[(NSString *)kCGWindowNumber];
|
|
||||||
NSUInteger zIndex = [windowNumbers indexOfObject:number];
|
|
||||||
if(zIndex < minZIndex) {
|
|
||||||
minZIndex = zIndex;
|
|
||||||
infoDict = @{
|
|
||||||
kMPWindowTitleKey: windowTitle,
|
|
||||||
kMPProcessIdentifierKey : processId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(currentWindows.count > 0 && infoDict.count == 0) {
|
|
||||||
// show some information about not being able to determine any windows
|
|
||||||
NSLog(@"Unable to retrieve any window names. If you encounter this issue you might be running 10.15 and MacPass has no permission for screen recording.");
|
|
||||||
}
|
|
||||||
return infoDict;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)_presentCandiadates:(NSArray *)candidates forWindowTitle:(NSString *)windowTitle {
|
|
||||||
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
|
||||||
@@ -360,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 );
|
||||||
@@ -376,24 +370,6 @@ static MPAutotypeDaemon *_sharedInstance;
|
|||||||
[self.matchSelectionWindow makeKeyAndOrderFront:self];
|
[self.matchSelectionWindow makeKeyAndOrderFront:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
#pragma mark MPDocument Notifications
|
|
||||||
- (void)_didUnlockDatabase:(NSNotification *)notification {
|
|
||||||
/* Remove ourselves and call again to search matches */
|
|
||||||
[NSNotificationCenter.defaultCenter removeObserver:self name:MPDocumentDidUnlockDatabaseNotification object:nil];
|
|
||||||
NSTimeInterval now = NSDate.date.timeIntervalSinceReferenceDate;
|
|
||||||
if(now - self.userActionRequested > 30) {
|
|
||||||
NSUserNotification *notification = [[NSUserNotification alloc] init];
|
|
||||||
notification.title = NSApp.applicationName;
|
|
||||||
notification.informativeText = NSLocalizedString(@"AUTOTYPE_TIMED_OUT", "Notficication: Autotype timed out");
|
|
||||||
notification.userInfo = @{ MPUserNotificationTypeKey: MPUserNotificationTypeAutotypeFeedback };
|
|
||||||
[NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
[self _performAutotypeForEntry:nil];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark NSApplication Notifications
|
#pragma mark NSApplication Notifications
|
||||||
- (void)_didDeactivateApplication:(NSNotification *)notification {
|
- (void)_didDeactivateApplication:(NSNotification *)notification {
|
||||||
@@ -403,51 +379,25 @@ static MPAutotypeDaemon *_sharedInstance;
|
|||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Application information
|
#pragma mark Application information
|
||||||
- (BOOL)_orderApplicationToFront:(pid_t)processIdentifier forContext:(MPAutotypeContext *)context {
|
//- (BOOL)_orderApplicationToFront:(pid_t)processIdentifier inEnvironment:(MPAutotypeEnvironment *) environment {
|
||||||
|
- (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];
|
||||||
|
if(completionHandler) {
|
||||||
|
completionHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.applicationActivationObserver = [NSWorkspace.sharedWorkspace.notificationCenter addObserverForName:NSWorkspaceDidActivateApplicationNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
|
|
||||||
if(self.applicationActivationObserver) {
|
|
||||||
[NSWorkspace.sharedWorkspace.notificationCenter removeObserver:self.applicationActivationObserver name:NSWorkspaceDidActivateApplicationNotification object:nil];
|
|
||||||
}
|
|
||||||
[self _performAutotypeForContext:context];
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[runingApplication activateWithOptions:NSApplicationActivateIgnoringOtherApps];
|
[runingApplication activateWithOptions:NSApplicationActivateIgnoringOtherApps];
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_updateTargeInformationForApplication:(NSRunningApplication *)application {
|
|
||||||
if(!application) {
|
|
||||||
self.targetPID = -1;
|
|
||||||
self.targetWindowTitle = @"";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
NSDictionary *frontApplicationInfoDict = [self _infoDictionaryForApplication:application];
|
|
||||||
|
|
||||||
self.targetPID = [frontApplicationInfoDict[kMPProcessIdentifierKey] intValue];
|
|
||||||
self.targetWindowTitle = frontApplicationInfoDict[kMPWindowTitleKey];
|
|
||||||
|
|
||||||
/* if we have any resolvers, let them provide the window title */
|
|
||||||
NSArray *resolvers = [MPPluginHost.sharedHost windowTitleResolverForRunningApplication:application];
|
|
||||||
for(MPPlugin<MPAutotypeWindowTitleResolverPlugin> *resolver in resolvers) {
|
|
||||||
NSString *windowTitle = [resolver windowTitleForRunningApplication:application];
|
|
||||||
if(windowTitle.length > 0) {
|
|
||||||
self.targetWindowTitle = windowTitle;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
34
MacPass/MPAutotypeEnvironment.h
Normal file
34
MacPass/MPAutotypeEnvironment.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// MPAutotypeEnvironment.h
|
||||||
|
// MacPass
|
||||||
|
//
|
||||||
|
// Created by Michael Starke on 15.01.20.
|
||||||
|
// Copyright © 2020 HicknHack Software GmbH. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@class KPKEntry;
|
||||||
|
@class MPAutotypeContext;
|
||||||
|
|
||||||
|
@interface MPAutotypeEnvironment : NSObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
The selected entry, if Autotype is run only for a single entry.
|
||||||
|
If autotype should search for entries, set this to nil.
|
||||||
|
*/
|
||||||
|
@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)initWithTargetApplication:(NSRunningApplication *)targetApplication entry:(KPKEntry * _Nullable)entry NS_DESIGNATED_INITIALIZER;
|
||||||
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
84
MacPass/MPAutotypeEnvironment.m
Normal file
84
MacPass/MPAutotypeEnvironment.m
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// MPAutotypeEnvironment.m
|
||||||
|
// MacPass
|
||||||
|
//
|
||||||
|
// Created by Michael Starke on 15.01.20.
|
||||||
|
// Copyright © 2020 HicknHack Software GmbH. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPAutotypeEnvironment.h"
|
||||||
|
#import "NSRunningApplication+MPAdditions.h"
|
||||||
|
#import "MPPluginHost.h"
|
||||||
|
#import "MPPlugin.h"
|
||||||
|
|
||||||
|
@implementation MPAutotypeEnvironment
|
||||||
|
|
||||||
|
+ (instancetype)environmentWithTargetApplication:(NSRunningApplication *)targetApplication entry:(KPKEntry *)entry {
|
||||||
|
return [[MPAutotypeEnvironment alloc] initWithTargetApplication:targetApplication entry:entry];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithTargetApplication:(NSRunningApplication *)targetApplication entry:(KPKEntry *)entry {
|
||||||
|
self = [super init];
|
||||||
|
if(self) {
|
||||||
|
_preferredEntry = entry;
|
||||||
|
if(!targetApplication) {
|
||||||
|
_pid = -1;
|
||||||
|
_windowTitle = @"";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NSDictionary *frontApplicationInfoDict = targetApplication.mp_infoDictionary;
|
||||||
|
|
||||||
|
_pid = [frontApplicationInfoDict[MPProcessIdentifierKey] intValue];
|
||||||
|
_windowTitle = frontApplicationInfoDict[MPWindowTitleKey];
|
||||||
|
|
||||||
|
/* if we have any resolvers, let them provide the window title */
|
||||||
|
NSArray *resolvers = [MPPluginHost.sharedHost windowTitleResolverForRunningApplication:targetApplication];
|
||||||
|
for(MPPlugin<MPAutotypeWindowTitleResolverPlugin> *resolver in resolvers) {
|
||||||
|
NSString *windowTitle = [resolver windowTitleForRunningApplication:targetApplication];
|
||||||
|
if(windowTitle.length > 0) {
|
||||||
|
_windowTitle = windowTitle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_hidden = NSRunningApplication.currentApplication.isHidden;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isSelfTargeting {
|
||||||
|
return NSRunningApplication.currentApplication.processIdentifier != _pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDictionary *)_infoDictionaryForApplication:(NSRunningApplication *)application {
|
||||||
|
NSArray *currentWindows = CFBridgingRelease(CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID));
|
||||||
|
NSArray *windowNumbers = [NSWindow windowNumbersWithOptions:NSWindowNumberListAllApplications];
|
||||||
|
NSUInteger minZIndex = NSNotFound;
|
||||||
|
NSDictionary *infoDict = nil;
|
||||||
|
for(NSDictionary *windowDict in currentWindows) {
|
||||||
|
NSString *windowTitle = windowDict[(NSString *)kCGWindowName];
|
||||||
|
if(windowTitle.length <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NSNumber *processId = windowDict[(NSString *)kCGWindowOwnerPID];
|
||||||
|
if(processId && [processId isEqualToNumber:@(application.processIdentifier)]) {
|
||||||
|
|
||||||
|
NSNumber *number = (NSNumber *)windowDict[(NSString *)kCGWindowNumber];
|
||||||
|
NSUInteger zIndex = [windowNumbers indexOfObject:number];
|
||||||
|
if(zIndex < minZIndex) {
|
||||||
|
minZIndex = zIndex;
|
||||||
|
infoDict = @{
|
||||||
|
MPWindowTitleKey: windowTitle,
|
||||||
|
MPProcessIdentifierKey : processId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(currentWindows.count > 0 && infoDict.count == 0) {
|
||||||
|
// show some information about not being able to determine any windows
|
||||||
|
NSLog(@"Unable to retrieve any window names. If you encounter this issue you might be running 10.15 and MacPass has no permission for screen recording.");
|
||||||
|
}
|
||||||
|
return infoDict;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
25
MacPass/NSRunningApplication+MPAdditions.h
Normal file
25
MacPass/NSRunningApplication+MPAdditions.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// NSRunningApplication+MPAdditions.h
|
||||||
|
// MacPass
|
||||||
|
//
|
||||||
|
// Created by Michael Starke on 15.01.20.
|
||||||
|
// Copyright © 2020 HicknHack Software GmbH. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
APPKIT_EXTERN NSString *const MPWindowTitleKey;
|
||||||
|
APPKIT_EXTERN NSString *const MPProcessIdentifierKey;
|
||||||
|
|
||||||
|
@interface NSRunningApplication (MPAdditions)
|
||||||
|
|
||||||
|
@property (readonly, copy) NSDictionary *mp_infoDictionary;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
50
MacPass/NSRunningApplication+MPAdditions.m
Normal file
50
MacPass/NSRunningApplication+MPAdditions.m
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// NSRunningApplication+MPAdditions.m
|
||||||
|
// MacPass
|
||||||
|
//
|
||||||
|
// Created by Michael Starke on 15.01.20.
|
||||||
|
// Copyright © 2020 HicknHack Software GmbH. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "NSRunningApplication+MPAdditions.h"
|
||||||
|
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
|
||||||
|
|
||||||
|
NSString *const MPWindowTitleKey = @"MPWindowTitleKey";
|
||||||
|
NSString *const MPProcessIdentifierKey = @"MPProcessIdentifierKey";
|
||||||
|
|
||||||
|
@implementation NSRunningApplication (MPAdditions)
|
||||||
|
|
||||||
|
- (NSDictionary *)mp_infoDictionary {
|
||||||
|
NSArray *currentWindows = CFBridgingRelease(CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID));
|
||||||
|
NSArray *windowNumbers = [NSWindow windowNumbersWithOptions:NSWindowNumberListAllApplications];
|
||||||
|
NSUInteger minZIndex = NSNotFound;
|
||||||
|
NSDictionary *infoDict = nil;
|
||||||
|
for(NSDictionary *windowDict in currentWindows) {
|
||||||
|
NSString *windowTitle = windowDict[(NSString *)kCGWindowName];
|
||||||
|
if(windowTitle.length <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NSNumber *processId = windowDict[(NSString *)kCGWindowOwnerPID];
|
||||||
|
if(processId && [processId isEqualToNumber:@(self.processIdentifier)]) {
|
||||||
|
|
||||||
|
NSNumber *number = (NSNumber *)windowDict[(NSString *)kCGWindowNumber];
|
||||||
|
NSUInteger zIndex = [windowNumbers indexOfObject:number];
|
||||||
|
if(zIndex < minZIndex) {
|
||||||
|
minZIndex = zIndex;
|
||||||
|
infoDict = @{
|
||||||
|
MPWindowTitleKey: windowTitle,
|
||||||
|
MPProcessIdentifierKey : processId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(currentWindows.count > 0 && infoDict.count == 0) {
|
||||||
|
// show some information about not being able to determine any windows
|
||||||
|
NSLog(@"Unable to retrieve any window names. If you encounter this issue you might be running 10.15 and MacPass has no permission for screen recording.");
|
||||||
|
}
|
||||||
|
return infoDict;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
Reference in New Issue
Block a user