[英]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];
我還嘗試了NSPasteboardItem
和NSPasteboardItemDataProvider
,其中我為 kUTITypeFileURL 上的內容設置了kUTITypeFileURL
。 它在粘貼板上提供了非常相似的條目,但是當我粘貼到 finder 中時仍然沒有動作。 訪問各個粘貼板條目時,剪貼板查看器將再次觸發提供程序。 ( NSPasteboard
的declareTypes: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.