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はプロセス1をペーストボード サーバーの mach ポートに登録しません。mach_port_names最初に、ペーストボード サーバーのマッハ ポート ( ?)を取得する方法を見つける必要があります。また、ユーザーセッション間の直接通信は禁止されており2、それ以外の通信は制限されています。あなたのプログラムがペーストボード サーバーに接続する権利を持っているかどうかはわかりません。

Apple イベントを使用してクリップボードを文字列として取得および設定する例の最初のショットを次に示します。エラー処理は最小限か存在しません (私がどのように感じているかはわかりません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。返信を調べるには、AEDebugReceivesosascript または Script Editor.app を使用するときに環境変数を設定することもできます。

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

参考文献:

  1. 「ユーザー・セッションの構成」
  2. 「ログイン セッション間での通信」
  3. Mach Kernel Interface、特に:
  4. CFMessagePort リファレンス(マッハ ポート ラッパー):
  5. Apple Events プログラミングガイド
  6. Apple Event Manager リファレンス
  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 Snow Leopard の場合:

pbcopy マック
(出典:hillrippers.ch

Ubuntu 9.04 の場合:

Ubuntu の pbpaste
(出典:hillrippers.ch

于 2009-10-27T15:19:38.667 に答える
0

SnowLeopard では SSH 経由で PasteboardCreate を使用してペーストボードにアクセスできますが、Leopard や Tiger ではアクセスできません。

pbcopy と pbpaste は、プレーン テキスト、RTF、および EPS のみを扱うため、ペーストボードの完全な同期にはおそらく使用したくないでしょう。たとえば、画像をコピーして pbpaste で書き出そうとしても、何も出力されません。

両方のコンピューターのユーザーのセッションでアプリを実行していると仮定すると、ペーストボード データをファイルにシリアル化し、SSH 経由で転送し、リモート側のアプリから読み取り、ペーストボード データをリモート ペーストボードに置くことができます。 . ただし、ペーストボードのシリアル化を正しく行うのは難しい場合があり、OS とアーキテクチャ間でペーストボード データをどのように移植できるかはわかりません。

于 2009-10-28T20:47:39.720 に答える