Reworked use of DDHotKey to prevent unwanted deregistration.

This commit is contained in:
michael starke
2017-01-03 14:50:08 +01:00
parent 0d5dcc4aad
commit d912285919
12 changed files with 61 additions and 56 deletions

View File

@@ -12,11 +12,17 @@
@property (readonly, copy) NSData *keyData; @property (readonly, copy) NSData *keyData;
/**
Use this method to retrieve the data, since deallocation of a hotkey unregisters it, this could yield unwanted behaviour!
@return data for the default hot key.
*/
+ (NSData *)hotKeyDataWithKeyCode:(unsigned short)keyCode modifierFlags:(NSUInteger)flags;
+ (NSData *)defaultHotKeyData;
+ (instancetype)defaultHotKey; + (instancetype)defaultHotKey;
+ (instancetype)defaultHotKeyWithTask:(DDHotKeyTask)task; + (instancetype)defaultHotKeyWithTask:(DDHotKeyTask)task;
+ (instancetype)hotKeyWithKeyData:(NSData *)data task:(DDHotKeyTask)task;
- (instancetype)initWithKeyData:(NSData *)data task:(DDHotKeyTask)task; + (instancetype)hotKeyWithKeyData:(NSData *)data;
- (instancetype)initWithKeyData:(NSData *)data;
@end @end

View File

@@ -14,45 +14,48 @@
@implementation DDHotKey (MPKeydata) @implementation DDHotKey (MPKeydata)
+ (NSData *)hotKeyDataWithKeyCode:(unsigned short)keyCode modifierFlags:(NSUInteger)flags {
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeInt:keyCode forKey:NSStringFromSelector(@selector(keyCode))];
[archiver encodeInteger:flags forKey:NSStringFromSelector(@selector(modifierFlags))];
[archiver finishEncoding];
return [data copy];
}
+ (NSData *)defaultHotKeyData {
return [self hotKeyDataWithKeyCode:kVK_ANSI_M modifierFlags:kCGEventFlagMaskControl|kCGEventFlagMaskAlternate];
}
+ (instancetype)defaultHotKey { + (instancetype)defaultHotKey {
return [DDHotKey defaultHotKeyWithTask:nil]; return [DDHotKey defaultHotKeyWithTask:nil];
} }
+ (instancetype)defaultHotKeyWithTask:(DDHotKeyTask)task { + (instancetype)defaultHotKeyWithTask:(DDHotKeyTask)task {
return [[DDHotKey alloc] initWithKeyData:nil task:task]; return [DDHotKey hotKeyWithKeyData:nil task:task];
} }
- (instancetype)initWithKeyData:(NSData *)data { + (instancetype)hotKeyWithKeyData:(NSData *)data {
self = [self initWithKeyData:data task:nil]; return [self hotKeyWithKeyData:data task:nil];
return self;
} }
- (instancetype)initWithKeyData:(NSData *)data task:(DDHotKeyTask)task{ + (instancetype)hotKeyWithKeyData:(NSData *)data task:(DDHotKeyTask)task {
NSUInteger modifierFlags; NSUInteger modifierFlags;
unsigned short keyCode; unsigned short keyCode;
if(!data) { if(!data) {
self = [DDHotKey hotKeyWithKeyCode:kVK_ANSI_M modifierFlags:kCGEventFlagMaskControl|kCGEventFlagMaskAlternate task:task]; return [DDHotKey hotKeyWithKeyCode:kVK_ANSI_M modifierFlags:kCGEventFlagMaskControl|kCGEventFlagMaskAlternate task:task];
} }
else if([self _getKeyCode:&keyCode modifierFlags:&modifierFlags fromData:data]) { if([self _getKeyCode:&keyCode modifierFlags:&modifierFlags fromData:data]) {
self = [DDHotKey hotKeyWithKeyCode:keyCode modifierFlags:modifierFlags task:task]; return [DDHotKey hotKeyWithKeyCode:keyCode modifierFlags:modifierFlags task:task];
} }
else { return nil;
self = nil;
}
return self;
} }
- (NSData *)keyData { - (NSData *)keyData {
NSMutableData *data = [[NSMutableData alloc] init]; return [self.class hotKeyDataWithKeyCode:self.keyCode modifierFlags:self.modifierFlags];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeInt:self.keyCode forKey:NSStringFromSelector(@selector(keyCode))];
[archiver encodeInteger:self.modifierFlags forKey:NSStringFromSelector(@selector(modifierFlags))];
[archiver finishEncoding];
return [data copy];
} }
+ (BOOL)_getKeyCode:(unsigned short *)keyCode modifierFlags:(NSUInteger *)modifierFlags fromData:(NSData *)data {
- (BOOL)_getKeyCode:(unsigned short *)keyCode modifierFlags:(NSUInteger *)modifierFlags fromData:(NSData *)data {
if(keyCode == NULL || modifierFlags == NULL || data == nil) { if(keyCode == NULL || modifierFlags == NULL || data == nil) {
return NO; return NO;
} }

View File

@@ -147,16 +147,32 @@ static MPAutotypeDaemon *_sharedInstance;
return; // We do not perform Autotype on ourselves return; // We do not perform Autotype on ourselves
} }
NSArray *documents = [self _findAutotypeDocuments]; /* find autotype documents */
NSArray *documents = [NSApp orderedDocuments];
/* No open document, inform the user and return without any action */
if(documents.count == 0) { if(documents.count == 0) {
/* We do not have a document. This can be NSUserNotification *notification = [[NSUserNotification alloc] init];
a) there is none - nothing happens notification.title = NSApp.applicationName;
b) there is at least one, but locked - we get called again after the document has been unlocked notification.informativeText = NSLocalizedString(@"AUTOTYPE_OVERLAY_NO_DOCUMENTS", "");
*/ [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
return; return;
} }
NSPredicate *filterPredicate = [NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
MPDocument *document = evaluatedObject;
return !document.encrypted;}];
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 */
if(unlockedDocuments.count == 0) {
[NSApp activateIgnoringOtherApps:YES];
[NSApp.mainWindow makeKeyAndOrderFront:self];
/* show the actual document window to the user */
[documents.firstObject showWindows];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didUnlockDatabase:) name:MPDocumentDidUnlockDatabaseNotification object:nil];
return; // wait for the unlock to happen
}
MPAutotypeContext *context = [self _autotypeContextForDocuments:documents forWindowTitle:self.targetWindowTitle preferredEntry:entryOrNil]; MPAutotypeContext *context = [self _autotypeContextForDocuments:documents forWindowTitle:self.targetWindowTitle preferredEntry:entryOrNil];
/* TODO: that's popping up if the mulit seleciton dialog goes up! */ /* TODO: that's popping up if the mulit selection dialog goes up! */
if(!entryOrNil) { if(!entryOrNil) {
NSUserNotification *notification = [[NSUserNotification alloc] init]; NSUserNotification *notification = [[NSUserNotification alloc] init];
notification.title = NSApp.applicationName; notification.title = NSApp.applicationName;
@@ -171,22 +187,6 @@ static MPAutotypeDaemon *_sharedInstance;
[self _performAutotypeForContext:context]; [self _performAutotypeForContext:context];
} }
- (NSArray<MPDocument *> *)_findAutotypeDocuments {
NSArray *documents = [NSApp orderedDocuments];
NSPredicate *filterPredicate = [NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
MPDocument *document = evaluatedObject;
return !document.encrypted;}];
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 */
if(unlockedDocuments.count == 0 && documents.count > 0) {
[NSApp activateIgnoringOtherApps:YES];
[NSApp.mainWindow makeKeyAndOrderFront:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didUnlockDatabase:) name:MPDocumentDidUnlockDatabaseNotification object:nil];
}
return unlockedDocuments;
}
- (MPAutotypeContext *)_autotypeContextForDocuments:(NSArray<MPDocument *> *)documents forWindowTitle:(NSString *)windowTitle preferredEntry:(KPKEntry *)entry { - (MPAutotypeContext *)_autotypeContextForDocuments:(NSArray<MPDocument *> *)documents forWindowTitle:(NSString *)windowTitle preferredEntry:(KPKEntry *)entry {
/* /*
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
@@ -230,22 +230,18 @@ static MPAutotypeDaemon *_sharedInstance;
#pragma mark - #pragma mark -
#pragma mark Hotkey Registration #pragma mark Hotkey Registration
- (void)_registerHotKey { - (void)_registerHotKey {
if(!self.hotKeyData) {
return;
}
__weak MPAutotypeDaemon *welf = self; __weak MPAutotypeDaemon *welf = self;
DDHotKeyTask aTask = ^(NSEvent *event) { DDHotKeyTask aTask = ^(NSEvent *event) {
[welf _didPressHotKey]; [welf _didPressHotKey];
}; };
DDHotKey *storedHotkey; self.registredHotKey = [[DDHotKeyCenter sharedHotKeyCenter] registerHotKey:[DDHotKey hotKeyWithKeyData:self.hotKeyData task:aTask]];
if(nil == self.hotKeyData) {
storedHotkey = [DDHotKey defaultHotKeyWithTask:aTask];
}
else {
storedHotkey = [[DDHotKey alloc] initWithKeyData:self.hotKeyData task:aTask];
}
self.registredHotKey = [[DDHotKeyCenter sharedHotKeyCenter] registerHotKey:storedHotkey];
} }
- (void)_unregisterHotKey { - (void)_unregisterHotKey {
if(nil != self.registredHotKey) { if(self.registredHotKey) {
[[DDHotKeyCenter sharedHotKeyCenter] unregisterHotKey:self.registredHotKey]; [[DDHotKeyCenter sharedHotKeyCenter] unregisterHotKey:self.registredHotKey];
self.registredHotKey = nil; self.registredHotKey = nil;
} }

View File

@@ -58,7 +58,7 @@
} }
- (void)willShowTab { - (void)willShowTab {
_hotKey = [[DDHotKey alloc] initWithKeyData:[[NSUserDefaults standardUserDefaults] dataForKey:kMPSettingsKeyGlobalAutotypeKeyDataKey]]; _hotKey = [DDHotKey hotKeyWithKeyData:[[NSUserDefaults standardUserDefaults] dataForKey:kMPSettingsKeyGlobalAutotypeKeyDataKey]];
/* Change any invalid hotkeys to valid ones? */ /* Change any invalid hotkeys to valid ones? */
self.hotKeyTextField.hotKey = self.hotKey; self.hotKeyTextField.hotKey = self.hotKey;
} }

View File

@@ -110,7 +110,7 @@ NSString *const kMPDeprecatedSettingsKeyDefaultPasswordRounds = @"Ke
kMPSettingsKeyRememberKeyFilesForDatabases: @NO, kMPSettingsKeyRememberKeyFilesForDatabases: @NO,
kMPSettingsKeySendCommandForControlKey: @YES, kMPSettingsKeySendCommandForControlKey: @YES,
kMPSettingsKeyEnableGlobalAutotype: @NO, kMPSettingsKeyEnableGlobalAutotype: @NO,
kMPSettingsKeyGlobalAutotypeKeyDataKey: [[DDHotKey defaultHotKey] keyData], kMPSettingsKeyGlobalAutotypeKeyDataKey: [DDHotKey defaultHotKeyData],
kMPSettingsKeyDefaultGlobalAutotypeSequence: @"{USERNAME}{TAB}{PASSWORD}{ENTER}", kMPSettingsKeyDefaultGlobalAutotypeSequence: @"{USERNAME}{TAB}{PASSWORD}{ENTER}",
kMPSettingsKeyAutotypeMatchTitle: @YES, kMPSettingsKeyAutotypeMatchTitle: @YES,
kMPSettingsKeyAutotypeMatchURL: @NO, kMPSettingsKeyAutotypeMatchURL: @NO,

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.