1

我们有以下片段。

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(又名 coreFoundationUnknownErr)。我认为解决此问题的唯一方法是在与粘贴板相同的环境中运行应用程序,但这可能吗?

4

4 回答 4

4

直接访问粘贴板看起来是不行的。首先,launchd不会使用粘贴板服务器的 mach 端口注册进程1 。您首先需要找到一种方法来获取粘贴板服务器的 mach 端口(mach_port_names?)。此外,禁止用户会话之间的直接通信2,并且限制其他通信。我不确定您的程序是否有权连接到粘贴板服务器。

这是使用 Apple 事件获取剪贴板并将剪贴板设置为字符串的说明性示例的第一个镜头。错误处理很少甚至不存在(我不确定我的感受require_noerr)。如果您要在运行期间多次获取/设置剪贴板数据,您可以保存 Apple 事件,并在复制到剪贴板时使用AECreateDesc&AEPutParamDesc或 (maybe) 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;
}

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

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

参考:

  1. “配置用户会话”
  2. “跨登录会话进行通信”
  3. Mach 内核接口,尤其是:
  4. CFMessagePort 参考(mach 端口包装器):
  5. Apple 事件编程指南
  6. Apple 事件管理器参考
  7. AEBuild*、AEPrint* 和朋友
  8. CocoaDev上的 AEBuildAppleEvent
  9. Mac OS X Debugging Magic(用于 AEDebugSends 和其他 AEDebug* 环境变量)
于 2009-10-28T18:44:00.000 回答
3

我尝试在 AppleScript 中执行此操作,并且它有效(即使通过 SSH 调用)。我的脚本如下:

#!/usr/bin/osascript

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

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

于 2009-10-25T12:54:27.743 回答
1

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

在 Mac OS X 雪豹上:

pbcopy Mac
(来源:hillrippers.ch

在 Ubuntu 9.04 上:

pbpaste Ubuntu
(来源:hillrippers.ch

于 2009-10-27T15:19:38.667 回答
0

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

您可能不想使用 pbcopy 和 pbpaste 进行完整的粘贴板同步,因为它们只处理纯文本、RTF 和 EPS。例如,如果您复制图像然后尝试使用 pbpaste 将其写出,您将不会得到任何输出。

假设您在两台计算机上的用户会话中运行了一个应用程序,您可以将粘贴板数据序列化到一个文件中,通过 SSH 传输它,从远程端的应用程序中读取它,然后将粘贴板数据放在远程粘贴板上. 但是,正确进行粘贴板序列化可能会很棘手,而且我不确定在操作系统和架构之间的可移植粘贴板数据如何。

于 2009-10-28T20:47:39.720 回答