簡體   English   中英

如何使用 NSPasteboard 和 kPasteboardTypeFileURLPromise 進行復制/粘貼?

[英]How to use NSPasteboard with kPasteboardTypeFileURLPromise for copy/paste?

我的應用程序想將 promise 添加到粘貼板上,以獲取遠程存儲的文件,並且可能永遠不會粘貼 - 類似於粘貼從控制 VM 或其他遠程系統的 session 復制的文件。 理想情況下,用戶可以粘貼到 Finder 文件夾(或桌面)中,promise 將觸發並離開我們 go。 promise一旦觸發,我願意處理的問題,但我一直無法讓promise觸發。

我發現的所有 promise 代碼都處理拖放,這不是我需要的功能(盡管可能需要來自 DnD 的某些東西才能使承諾起作用?)

我曾嘗試將NSFilePromiseProvider與委托一起使用,並將其添加到粘貼板。 我可以使用剪貼板查看器查看粘貼板上的條目,但是當我在 Finder 中粘貼時,什么也沒有發生,也沒有調用委托方法。 我可以通過讓剪貼板查看器訪問條目來觸發委托方法,所以我知道很多東西都被掛鈎了。

@interface ClipboardMacPromise : NSFilePromiseProvider<NSFilePromiseProviderDelegate>
{
    NSString* m_file;
}
@end
@implementation ClipboardMacPromise
- (id)initWithFileType:(NSString*)type andFile:(NSString*)file
{
    m_file = file;
    return [super initWithFileType:type delegate:self];
}
- (NSString *)filePromiseProvider:(NSFilePromiseProvider*)filePromiseProvider fileNameForType:(NSString *)fileType
{
    return m_file;
}
- (void)filePromiseProvider:(NSFilePromiseProvider*)filePromiseProvider writePromiseToURL:(NSURL *)url completionHandler:(void (^)(NSError * _Nullable errorOrNil))completionHandler
{
    // Finder can't paste, so we never get here...
}
@end

NSPasteboard* pboard = [NSPasteboard generalPasteboard];
[pboard clearContents];
NSMutableArray* items = [[NSMutableArray alloc] init];
ClipboardMacPromise* promise = [[ClipboardMacPromise alloc] initWithFileType:(NSString*)kUTTypeFileURL andFile:@"dummy.txt"];
[items addObject:promise];
[pboard writeObjects:items];

我還嘗試了NSPasteboardItemNSPasteboardItemDataProvider ,其中我為 kUTITypeFileURL 上的內容設置了kUTITypeFileURL 它在粘貼板上提供了非常相似的條目,但是當我粘貼到 finder 中時仍然沒有動作。 訪問各個粘貼板條目時,剪貼板查看器將再次觸發提供程序。 NSPasteboarddeclareTypes:owner:具有相同的行為)

@interface ClipboardMacPromise : NSPasteboardItem<NSPasteboardItemDataProvider>
{
    NSString* m_file;
}
@end
@implementation ClipboardMacPromise
- (id)initWithFile:(NSString*)file
{
    m_file = file;
    id _self = [super init];
    if (_self) {
        [_self setDataProvider:_self forTypes:@[(NSString*)kPasteboardTypeFileURLPromise]];
        [_self setString:(NSString*)kUTTypeFileURL forType:(NSString*)kPasteboardTypeFilePromiseContent];
    }
    return _self;
}
- (void)pasteboard:(NSPasteboard *)pasteboard item:(NSPasteboardItem *)item provideDataForType:(NSPasteboardType)type
{
    // we don't get here when we paste in Finder because
    // Finder doesn't think there's anything to paste
    // but using a clipboard viewer, we can force the promise to
    // resolve and we do get here
}
@end

NSPasteboard* pboard = [NSPasteboard generalPasteboard];
[pboard clearContents];
NSMutableArray* items = [[NSMutableArray alloc] init];
ClipboardMacPromise* promise = [[ClipboardMacPromise alloc] initWithFile:@"file:///tmp/dummy.txt"];
[items addObject:promise];
[pboard writeObjects:items];

為了完整起見,這是我的 Carbon 嘗試,因為 Pasteboard.h 似乎詳細說明了它在復制/粘貼場景中應該如何工作......但它仍然沒有為 Finder 提供它正在尋找的東西。 生成的剪貼板條目在三個實現之間看起來非常相似。

OSStatus PasteboardPromiseKeeperProc(PasteboardRef pasteboard, PasteboardItemID item, CFStringRef flavorType, void * _Nullable context)
{
    // 6) The sender's promise callback for kPasteboardTypeFileURLPromise is called.
    string s = "dummy.txt";
    CFDataRef inData = CFDataCreate(kCFAllocatorDefault, (UInt8*)s.c_str(), s.size());
    PasteboardPutItemFlavor(pasteboard, item, flavorType, inData, 0);
    return noErr;
}

PasteboardRef p = NULL;
PasteboardCreate(kPasteboardClipboard, &p);
PasteboardClear(p);
PasteboardSetPromiseKeeper(p, &PasteboardPromiseKeeperProc, this);

// 1) The sender promises kPasteboardTypeFileURLPromise for a file yet to be created.
PasteboardPutItemFlavor(p, (PasteboardItemID)1, kPasteboardTypeFileURLPromise, kPasteboardPromisedData, 0);
// 2) The sender adds kPasteboardTypeFilePromiseContent containing the UTI describing the file's content.
PasteboardPutItemFlavor(p, (PasteboardItemID)2, kPasteboardTypeFilePromiseContent,CFStringCreateExternalRepresentation(NULL, kUTTypeFileURL, kCFStringEncodingUTF8, 0), 0);

Finder 確實在粘貼板上尋找某個 UTI,但我沒有。 如果我將kUTTypeFileURL直接放在剪貼板上,看起來 finder 在提供粘貼之前實際上會檢查文件是否存在(即觸發 Catalina 的桌面訪問提示)。

有誰知道是否或如何通過復制/粘貼而不是拖放向 Finder 提供文件承諾?

看來這里的關鍵部分是 Finder 要求文件實際存在於磁盤上,才能為文件 URL 啟用粘貼操作。 這一細節排除了承諾用於復制/粘貼的可能性——至少在 Finder 中是這樣。

因此,正確的解決方案需要一個虛擬化文件系統(如 FUSE),以便可以在文件系統級別做出和履行承諾。 因此,可以將臨時零長度文件的集合寫入磁盤,並將實際文件 URL 添加到粘貼板。 這滿足了 Finder 啟用粘貼的要求。 然后,當進行粘貼操作時,將從虛擬化文件系統中讀取文件數據,而虛擬化文件系統又可以從遠程系統中檢索實際數據。 Finder 並不明智。 副本甚至會有一個內置的進度條!

似乎微軟的 Mac RDP 客戶端大多以這種方式工作,盡管我只能讓它復制零長度文件,所以這可能比聽起來更難。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM