How to save off the pasteboard contents first and restore them afterward?
Asked Answered
H

3

13

I have a faceless Mac OS X app which needs to copy selection from other apps. I achieve this by simulating CMD+C keystrokes. It works perfectly. But there is a, I think it's critical, side effect. It'll override users' pasteboard without their permission. So I was thinking before I copying selection I should save pasteboard content and then restore it. Can someone give me some hint, maybe sample code?

Hauteur answered 25/5, 2011 at 0:50 Comment(2)
You should look into the Accessibility API. It'll get you what you want without ugly hacks.Hungary
@JoakimBraun I wish the Accessibility API could cover all the cases.Tamqrah
A
9

Here's a category on NSPasteboard that I wrote to do this. It seems to work pretty well.

@implementation NSPasteboard (SaveAndRestore)

// save current contents as an array of pasteboard items
- (NSArray *)save
{
    NSMutableArray *archive=[NSMutableArray array];
    for (NSPasteboardItem *item in [self pasteboardItems]) 
    {
        NSPasteboardItem *archivedItem=[[NSPasteboardItem alloc] init];
        for (NSString *type in [item types])
        {
            /* The mutableCopy performs a deep copy of the data. This avoids
               memory leak issues (bug in Cocoa?), which you might run into if
               you don't copy the data. */
            NSData *data=[[item dataForType:type] mutableCopy];
            if (data) { // nil safety check
                [archivedItem setData:data forType:type];
            }
        }
        [archive addObject:archivedItem];
    }
    return archive;
}

// restore previously saved data
- (void)restore:(NSArray *)archive
{
    [self clearContents];
    [self writeObjects:archive];
}

@end
Afresh answered 2/9, 2011 at 19:33 Comment(5)
great man, the second time in less then a hour you helped me out. But sadly it is not compatible with your other answer https://mcmap.net/q/907442/-how-to-paste-text-from-one-app-to-another-using-cocoa the paste process is simply to slow, so that the pasteboard is restored before paste (even if its called in code later)Linguistic
It should work reliably if you just increase the delay, to about 1 second.Afresh
yep did that (even 0.01 works) but I don't like such hacky tricks. Its unclear what will happen if the pasteboard data volume exceed a certain level but anyway thanks for the response =)Linguistic
@relikd did you ever come up with a satisfactory solution?Cohen
nope, haven't looked deeper because the App I was working on, didn't get developed since :D ( oh this is over 2 years old :-o )Linguistic
C
2

Alternative self-contained implementation using object associations:

#import <objc/runtime.h>

static void * kArchiveKey = &kArchiveKey;

@implementation NSPasteboard (SaveRestore)

- (void)setArchive:(NSArray *)newArchive
{
    objc_setAssociatedObject(self, kArchiveKey, newArchive, OBJC_ASSOCIATION_RETAIN);
}

- (NSArray *)archive
{
    return objc_getAssociatedObject(self, kArchiveKey);
}

- (void)save
{
    NSMutableArray *archive = [NSMutableArray array];
    for (NSPasteboardItem *item in [self pasteboardItems]) {
        NSPasteboardItem *archivedItem = [[NSPasteboardItem alloc] init];
        for (NSString *type in [item types]) {
            NSData *data = [item dataForType:type];
            if (data) {
                [archivedItem setData:data forType:type];
            }
        }
        [archive addObject:archivedItem];
    }
    [self setArchive:archive];
}

- (void)restore
{
    [self clearContents];
    [self writeObjects:[self archive]];
}

@end
Cytochemistry answered 24/4, 2013 at 14:24 Comment(0)
A
1

Look at NSPasteboard.

+[NSPasteboard generalPasteboard] will give you the shared pasteboard and you can use that class to get and set the contents.

Aground answered 25/5, 2011 at 3:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.