Changed API for pasteboard to only use a single object. Arrays aren't required. Added concealed/transient type marker to copied items to enhance compatibility with clipboard managers

This commit is contained in:
Michael Starke
2020-07-10 15:37:25 +02:00
parent 641ba2a3fd
commit c759aeddd9
7 changed files with 54 additions and 21 deletions

View File

@@ -51,9 +51,9 @@
}
- (void)execute {
if([self.pasteData length] > 0) {
if(self.pasteData.length > 0) {
[MPPasteBoardController.defaultController stashObjects];
[MPPasteBoardController.defaultController copyObjectsWithoutTimeout:@[self.pasteData]];
[MPPasteBoardController.defaultController copyObjectWithoutTimeout:self.pasteData];
[MPKeyTyper sendPaste];
usleep(0.2 * NSEC_PER_MSEC); // on 10.10 we need to wait a bit before restoring the pasteboard contents
[MPPasteBoardController.defaultController restoreObjects];

View File

@@ -628,7 +628,7 @@ typedef NS_ENUM(NSUInteger, MPEntryTab) {
name = [_customFieldsController.arrangedObjects[index] key];
}
}
[MPPasteBoardController.defaultController copyObjects:@[selectedValue] overlayInfo:info name:name atView:self.view];
[MPPasteBoardController.defaultController copyObject:selectedValue overlayInfo:info name:name atView:self.view];
return NO;
}
return YES;

View File

@@ -647,7 +647,7 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
KPKEntry *selectedEntry = nodes.count == 1 ? [nodes.firstObject asEntry] : nil;
NSString *value = [selectedEntry.password kpk_finalValueForEntry:selectedEntry];
if(value) {
[MPPasteBoardController.defaultController copyObjects:@[value] overlayInfo:MPPasteboardOverlayInfoPassword name:nil atView:self.view];
[MPPasteBoardController.defaultController copyObject:value overlayInfo:MPPasteboardOverlayInfoPassword name:nil atView:self.view];
}
}
@@ -656,7 +656,7 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
KPKEntry *selectedEntry = nodes.count == 1 ? [nodes.firstObject asEntry] : nil;
NSString *value = [selectedEntry.username kpk_finalValueForEntry:selectedEntry];
if(value) {
[MPPasteBoardController.defaultController copyObjects:@[value] overlayInfo:MPPasteboardOverlayInfoUsername name:nil atView:self.view];
[MPPasteBoardController.defaultController copyObject:value overlayInfo:MPPasteboardOverlayInfoUsername name:nil atView:self.view];
}
}
@@ -669,7 +669,7 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
KPKAttribute *attribute = selectedEntry.customAttributes[index];
NSString *value = attribute.evaluatedValue;
if(value) {
[MPPasteBoardController.defaultController copyObjects:@[value] overlayInfo:MPPasteboardOverlayInfoCustom name:attribute.key atView:self.view];
[MPPasteBoardController.defaultController copyObject:value overlayInfo:MPPasteboardOverlayInfoCustom name:attribute.key atView:self.view];
}
}
}
@@ -679,7 +679,7 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
KPKEntry *selectedEntry = nodes.count == 1 ? [nodes.firstObject asEntry] : nil;
NSString *value = [selectedEntry.url kpk_finalValueForEntry:selectedEntry];
if(value) {
[MPPasteBoardController.defaultController copyObjects:@[value] overlayInfo:MPPasteboardOverlayInfoURL name:nil atView:self.view];
[MPPasteBoardController.defaultController copyObject:value overlayInfo:MPPasteboardOverlayInfoURL name:nil atView:self.view];
}
}
@@ -727,7 +727,7 @@ NSString *const _MPTableSecurCellView = @"PasswordCell";
KPKEntry *selectedEntry = nodes.count == 1 ? [nodes.firstObject asEntry] : nil;
if(referencesField && selectedEntry) {
NSString *value = [NSString stringWithFormat:@"{%@%@@%@:%@}", kKPKReferencePrefix, referencesField, kKPKReferenceUUIDKey, selectedEntry.uuid.UUIDString];
[MPPasteBoardController.defaultController copyObjects:@[value] overlayInfo:MPPasteboardOverlayInfoReference name:references[referencesField] atView:self.view];
[MPPasteBoardController.defaultController copyObject:value overlayInfo:MPPasteboardOverlayInfoReference name:references[referencesField] atView:self.view];
}
}

View File

@@ -154,7 +154,7 @@ typedef NS_ENUM(NSUInteger, MPContentTab) {
if(textView == self.notesTextView) {
name = NSLocalizedString(@"NOTES", "Displayed name when notes or part of notes was copied");
}
[[MPPasteBoardController defaultController] copyObjects:@[selectedString] overlayInfo:info name:name atView:self.view];
[MPPasteBoardController.defaultController copyObject:selectedString overlayInfo:info name:name atView:self.view];
return NO;
}
return YES;

View File

@@ -193,7 +193,7 @@ typedef NS_ENUM(NSUInteger, MPPasswordRating) {
- (IBAction)_usePassword:(id)sender {
if(self.shouldCopyPasswordToPasteboardButton.state == NSOnState) {
[MPPasteBoardController.defaultController copyObjects:@[self.password]];
[MPPasteBoardController.defaultController copyObject:self.password];
}
KPKEntry *entry = self.representedObject;
if(entry && self.password.length > 0) {

View File

@@ -55,8 +55,8 @@ FOUNDATION_EXPORT NSString *const MPPasteBoardControllerDidClearClipboard;
- (void)stashObjects;
- (void)restoreObjects;
- (void)copyObjects:(NSArray<id<NSPasteboardWriting>> *)objects;
- (void)copyObjectsWithoutTimeout:(NSArray<id<NSPasteboardWriting>> *)objects;
- (void)copyObject:(id<NSPasteboardWriting>)objects;
- (void)copyObjectWithoutTimeout:(id<NSPasteboardWriting>)objects;
/**
The pastboard controller will copy the object to the clipboard, display an appropriate overlay image
@@ -65,11 +65,11 @@ FOUNDATION_EXPORT NSString *const MPPasteBoardControllerDidClearClipboard;
to the clipboard. If the clipboard is used internally (e.g. for autotype) you should call copyObjects:
or even copyObjectsWithoutTimeout:
@param objects object so be copied
@param object object so be copied
@param overlayInfoType infotype discribing what is copied
@param name a custom name
@param view the view that initiated the copy action
*/
- (void)copyObjects:(NSArray<id<NSPasteboardWriting>> *)objects overlayInfo:(MPPasteboardOverlayInfoType)overlayInfoType name:(NSString *)name atView:(NSView *)view;
- (void)copyObject:(id<NSPasteboardWriting>)object overlayInfo:(MPPasteboardOverlayInfoType)overlayInfoType name:(NSString *)name atView:(NSView *)view;
@end

View File

@@ -28,6 +28,14 @@
NSString *const MPPasteBoardControllerDidCopyObjects = @"com.hicknhack.macpass.MPPasteBoardControllerDidCopyObjects";
NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpass.MPPasteBoardControllerDidClearClipboard";
/*
Pasteboard types. See NSPasteboard.org for refernce
*/
NSString *const MPPasteBoardTypeTransient = @"org.nspasteboard.TransientType";
NSString *const MPPasteBoardTypeConcealed = @"org.nspasteboard.ConcealedType";
NSString *const MPPasteBoardTypeAutoGenerated = @"org.nspasteboard.AutoGeneratedType";
NSString *const MPPasteBoardTypeSource = @"org.nspasteboard.source";
@interface MPPasteBoardController ()
@property (assign) BOOL isEmpty;
@@ -72,6 +80,9 @@ NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpas
- (void)stashObjects {
self.stashedObjects = [NSMutableArray array];
for(NSPasteboardItem *item in NSPasteboard.generalPasteboard.pasteboardItems) {
if(![self _shouldStashPasteboardItem:item]) {
continue; // skip item we should not stash
}
NSPasteboardItem *newItem = [[NSPasteboardItem alloc] init];
for (NSString *type in item.types) {
/* mutable copy to ensure actual deep copy */
@@ -93,9 +104,11 @@ NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpas
}
}
- (void)copyObjects:(NSArray<id<NSPasteboardWriting>> *)objects {
[self copyObjectsWithoutTimeout:objects];
- (void)copyObject:(id<NSPasteboardWriting>)object {
[self copyObjectWithoutTimeout:object];
if(self.clearTimeout != 0) {
/* add transient since we do clear after delay */
[NSPasteboard.generalPasteboard setData:nil forType:MPPasteBoardTypeTransient];
[NSNotificationCenter.defaultCenter postNotificationName:MPPasteBoardControllerDidCopyObjects object:self];
/* cancel old timer */
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_clearPasteboardContents) object:nil];
@@ -104,18 +117,20 @@ NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpas
}
}
- (void)copyObjectsWithoutTimeout:(NSArray<id<NSPasteboardWriting>> *)objects {
- (void)copyObjectWithoutTimeout:(id<NSPasteboardWriting>)object {
NSPasteboardContentsOptions options = [NSUserDefaults.standardUserDefaults boolForKey:kMPSettingsKeyPreventUniversalClipboard] ? NSPasteboardContentsCurrentHostOnly : 0;
[NSPasteboard.generalPasteboard prepareForNewContentsWithOptions:options];
[NSPasteboard.generalPasteboard writeObjects:objects];
[NSPasteboard.generalPasteboard writeObjects:@[object]];
[NSPasteboard.generalPasteboard setData:nil forType:MPPasteBoardTypeConcealed]; // mark as concealed
[NSPasteboard.generalPasteboard setString:NSRunningApplication.currentApplication.bundleIdentifier forType:MPPasteBoardTypeSource]; // set source
self.isEmpty = NO;
}
- (void)copyObjects:(NSArray<id<NSPasteboardWriting>> *)objects overlayInfo:(MPPasteboardOverlayInfoType)overlayInfoType name:(NSString *)name atView:(NSView *)view{
if(!objects) {
- (void)copyObject:(id<NSPasteboardWriting>)object overlayInfo:(MPPasteboardOverlayInfoType)overlayInfoType name:(NSString *)name atView:(NSView *)view{
if(!object) {
return;
}
[MPPasteBoardController.defaultController copyObjects:objects];
[MPPasteBoardController.defaultController copyObject:object];
NSImage *infoImage = nil;
NSString *infoText = nil;
switch(overlayInfoType) {
@@ -185,4 +200,22 @@ NSString *const MPPasteBoardControllerDidClearClipboard = @"com.hicknhack.macpas
options:nil];
}
- (BOOL)_shouldStashPasteboardItem:(NSPasteboardItem *)item {
for(NSString *type in item.types) {
if([type isEqualToString:MPPasteBoardTypeConcealed]) {
return NO;
}
if([type isEqualToString:MPPasteBoardTypeTransient]) {
return NO;
}
if([type isEqualToString:MPPasteBoardTypeSource]) {
NSString *sourceBundle = [item stringForType:type];
if([NSRunningApplication.currentApplication.bundleIdentifier isEqualToString:sourceBundle]) {
return NO;
}
}
}
return YES;
}
@end