问题描述
我的应用程序希望向远程存储的文件的粘贴板添加一个承诺,并且可能永远不会粘贴-类似于粘贴从控制VM或其他远程系统的会话复制的文件.理想情况下,用户可以粘贴到Finder文件夹(或桌面)中,并且诺言将触发并消失.我愿意处理一旦触发就兑现诺言的问题,但我一直无法兑现诺言.
My application would like to add a promise to the pasteboard for a file that is stored remotely, and may never be pasted—similar to pasting a file copied from a session controlling a VM or other remote system. Ideally, a user can paste in a Finder folder (or the desktop) and the promise would trigger and away we go. I am willing to deal with the issues of fulfilling the promise once triggered, but I have been unable to get the promise to trigger.
我发现的所有诺言代码都涉及拖放操作,这不是我所需要的功能(尽管为实现诺言,可能需要DnD中的某些内容吗?)
All of the promise code I have found deals with drag and drop, which is not functionality what I need (though it is possible that something from DnD needs to be in place for promises to work?)
我尝试将 NSFilePromiseProvider
与委托一起使用,并将其添加到剪贴板.我可以使用剪贴板查看器在粘贴板上看到条目,但是当我在Finder中粘贴时,什么也没有发生,也没有调用任何委托方法.我可以通过让剪贴板查看器访问条目来触发委托方法,所以我知道已经有很多事情了.
I have tried using NSFilePromiseProvider
with a delegate, and adding that to the pasteboard. I can see the entries on the pasteboard using a clipboard viewer, but when I paste in Finder nothing happens and no delegate methods are called. I can trigger the delegate methods by having the clipboard viewer access the entries, so I know that much is hooked up.
@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];
我还尝试过使用 NSPasteboardItemDataProvider
进行 NSPasteboardItem
,在其中我为 kUTITypeFileURL
上的内容设置了承诺.它在粘贴板上提供了非常相似的条目,但是当我粘贴到finder中时仍然没有任何动作.当访问各个粘贴板条目时,剪贴板查看器将再次触发提供程序罚款.( NSPasteboard
的 declareTypes:owner:
具有相同的行为)
I have also tried NSPasteboardItem
with NSPasteboardItemDataProvider
where I setup a promise for content on kUTITypeFileURL
. It provided very similar entries on the pasteboard, but still no action when I paste in finder. Clipboard viewer will again trigger the provider fine when accessing the individual pasteboard entries. (NSPasteboard
's declareTypes:owner:
has the same behavior)
@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提供所需的内容.三种实现之间生成的剪贴板条目看起来非常相似.
And for completeness, here is my Carbon attempt since Pasteboard.h seems to detail how this should work in a copy/paste scenario... but it still does not provide Finder what it is looking for. The generated clipboard entries look very similar between the three implementations.
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
放置在剪贴板上,则查找器实际上会在提供文件之前先检查文件是否存在(即触发Catalina的Desktop访问提示).
It really seems that there is a certain UTI that Finder is looking for on the pasteboard, and I don't have it. If I put a kUTTypeFileURL
directly on the clipboard, it appears that finder actually checks for the existence of the file (ie. triggers Catalina's Desktop access prompt) before offering it to paste.
有人知道是否可以通过复制/粘贴而不是拖放方式将文件承诺提供给Finder?
Does anyone know if or how file promises can be provided to Finder through Copy/Paste instead of Drag-and-Drop?
推荐答案
看来,关键在于Finder要求文件实际存在于磁盘上,才能为文件URL启用粘贴操作.这一细节排除了答应用于复制/粘贴的可能性-至少在Finder中有效.
It appears that the key piece here is that Finder requires that the file actually be present on disk for the paste action to be enabled for a file URL. This one detail rules out the possibility of promises working for copy/paste -- at least with Finder.
因此,正确的解决方案需要虚拟化的文件系统(如FUSE),以便可以在文件系统级别上实现并兑现承诺.因此,可以将临时零长度文件的集合写入磁盘,并将实际的文件URL添加到粘贴板.这满足了Finder必须启用粘贴的要求.然后,在执行粘贴操作时,将从虚拟文件系统中读取文件数据,该文件系统又可以从远程系统中检索实际数据.Finder 并不聪明.该副本甚至将具有内置的进度条!
The correct solution therefore requires a virtualized file system (like FUSE) so that the promises can be made and fulfilled at the filesystem level. Thus a collection of temporary zero-length files can be written to disk, and actual file URLs be added to the pasteboard. This fulfills the requirements that Finder has to enable paste. Then when a paste action is made, the file data is read from the virtualized file system which can in turn retrieve the actual data from the remote system. Finder is none the wiser. The copy will even have a built in progress bar!
看来,Microsoft的Mac RDP客户端大多数都是以这种方式工作的,尽管我只能让它复制零长度的文件,所以这听起来很难做到正确.
It appears that Microsoft's Mac RDP client mostly works this way, although I was only ever able to get it to copy zero length files so this may be harder to get right than it sounds.
这篇关于如何将NSPasteboard与kPasteboardTypeFileURLPromise一起使用以进行复制/粘贴?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!