通过SSH登录时是否可以访问Mac OS X粘贴板?

时间:2009-08-03 20:39:00

标签: pasteboard

我们有以下代码段。

OSStatus createErr = PasteboardCreate(kPasteboardClipboard, &m_pboard);
if (createErr != noErr) {
    LOG((CLOG_DEBUG "failed to create clipboard reference: error %i" createErr));
}

这个编译很好,但是从SSH调用时无法运行。这是因为SSH终端中没有可用的粘贴板。但是,这里的想法是在计算机之间共享剪贴板。

从桌面终端运行时,这很好用。但是当从SSH运行时,PasteboardCreate返回-4960(aka,coreFoundationUnknownErr)。我假设解决此问题的唯一方法是在与粘贴板相同的环境中运行应用程序,但这可能吗?

4 个答案:

答案 0 :(得分:3)

我尝试在AppleScript中使用它,它工作(即使通过SSH调用)。我的脚本如下:

#!/usr/bin/osascript

on run
    tell application "Finder"
        display dialog (get the clipboard)
    end tell
end run

这绝对不是一个理想的解决方案,但是如果你弄清楚AppleScript是如何做到的,那么它可以帮助你自己实现它。

答案 1 :(得分:3)

直接访问粘贴板看起来是不行的。首先,使用粘贴板服务器的mach端口启动won't register the processes1。您首先需要找到一种方法来获取粘贴板服务器的马赫端口(mach_port_names?)。此外,用户会话之间的直接通信是prohibited2,其他通信是有限的。我不确定您的程序是否有权连接到粘贴板服务器。

以下是关于使用Apple事件获取& amp;将剪贴板设置为字符串。错误处理很少到不存在(我不确定我对require_noerr的看法)。如果您要在运行期间多次获取/设置剪贴板数据,则可以保存Apple事件,并在复制到剪贴板时使用AECreateDesc& AEPutParamDesc或(可能)AEBuildParametersAEVTBuilder可能有用。

NSString* paste() {
    NSString *content;

    AppleEvent paste, reply = { typeNull, 0L };
    AEBuildError buildError = { typeNull, 0L };
    AEDesc clipDesc = { typeNull, 0L };

    OSErr err;

    err = AEBuildAppleEvent(kAEJons, kAEGetClipboard, 
                            typeApplicationBundleID, "com.apple.finder", strlen("com.apple.finder"), 
                            kAutoGenerateReturnID, kAnyTransactionID,
                            &paste, &buildError,
                            ""
        );
    require_noerr(err, paste_end);
    err = AESendMessage(&paste, &reply, kAEWaitReply, kAEDefaultTimeout);
    err = AEGetParamDesc(&reply, keyDirectObject, typeUTF8Text, &clipDesc);
    require_noerr(err, pastErr_getReply);

    Size dataSize = AEGetDescDataSize(&clipDesc);
    char* clipData = malloc(dataSize);
    if (clipData) {
        err = AEGetDescData(&clipDesc, clipData, dataSize);
        if (noErr == err) {
            content = [NSString stringWithCString:clipData encoding:NSUTF8StringEncoding];
        } else {}
        free(clipData);
    }

    AEDisposeDesc(&clipDesc);
pastErr_getReply:
    AEDisposeDesc(&reply);
pasteErr_sending:
    AEDisposeDesc(&paste);
paste_end:
    return content;
}

OSStatus copy(NSString* clip) {
    AppleEvent copy, reply = { typeNull, 0L };
    AEBuildError buildError = { typeNull, 0L };

    OSErr err = AEBuildAppleEvent(kAEJons, kAESetClipboard, 
                                  typeApplicationBundleID, "com.apple.finder", strlen("com.apple.finder"), 
                                  kAutoGenerateReturnID, kAnyTransactionID,
                                  &copy, &buildError,
                                  "'----':utf8(@)",
                                  AEPARAMSTR([clip UTF8String])
                                  /*
                                    "'----':obj {form: enum(prop), want: type(@), seld: type(@), from: null()}"
                                    "data:utf8(@)",
                                    AEPARAM(typeUTF8Text),
                                    AEPARAM(pClipboard),
                                    AEPARAMSTR([clip UTF8String])
                                  */
        );
    if (aeBuildSyntaxNoErr != buildError.fError) {
        return err;
    }
    AESendMessage(&copy, &reply, kAENoReply, kAEDefaultTimeout);
    AEDisposeDesc(&reply);
    AEDisposeDesc(&copy);
    return noErr;
}

我将离开上面的Core Foundation方法,但您可能希望使用NSAppleEventDescriptor从Apple Event回复中提取剪贴板内容。

    err = AESendMessage(&paste, &reply, kAEWaitReply, kAEDefaultTimeout);
require_noerr(err, pasteErr_sending);
    // nsReply takes ownership of reply
    NSAppleEventDescriptor *nsReply = [[NSAppleEventDescriptor alloc] initWithAEDescNoCopy:&reply];
    content = [[nsReply descriptorAtIndex:1] stringValue];
    [nsReply release];

pasteErr_sending:
    AEDisposeDesc(&paste);
paste_end:
    return content;
}

NSAppleEventDescriptor在调试器中比AEDesc更容易检查。要检查回复,您还可以在使用osascript或Script Editor.app时设置AEDebugReceives环境变量:

AEDebugReceives=1 osascript -e 'tell application "Finder" to get the clipboard'

参考文献:

  1. "Configuring User Sessions"
  2. "Communicating Across Login Sessions"
  3. Mach Kernel Interface,特别是:
  4. CFMessagePort Reference(马赫端口包装器):
  5. Apple Events Programming Guide
  6. Apple Event Manager Reference
  7. AEBuild*, AEPrint* and Friends
  8. CocoaDev上的
  9. AEBuildAppleEvent
  10. Mac OS X Debugging Magic(适用于AEDebugSends和其他AEDebug *环境变量)

答案 2 :(得分:1)

查看pbpaste(获取剪贴板的内容)和pbcopy(将内容复制到剪贴板)。工作正常,也通过SSH。 :)

在Mac OS X Snow Leopard上:

pbcopy Mac
(来源:hillrippers.ch

在Ubuntu 9.04上:

pbpaste Ubuntu
(来源:hillrippers.ch

答案 3 :(得分:0)

您可以通过SnowLeopard上的SSH使用PasteboardCreate访问粘贴板,但不能访问Leopard或Tiger。

您可能不希望将pbcopy和pbpaste用于完整的粘贴板同步,因为这些只处理纯文本,RTF和EPS。例如,如果您复制图像然后尝试使用pbpaste写出来,那么您将无法获得输出。

假设您在两台计算机上的用户会话中都运行了应用程序,您可以将粘贴板数据序列化为文件,通过SSH传输,从远程端的应用程序读取,然后将粘贴板数据放入远程粘贴板。但是,正确地获得粘贴板序列化可能会非常棘手,我不确定操作系统和架构之间的可移植粘贴板数据是多少。