2009-08-03 74 views
1

我們接下來的代碼片段。當通過SSH登錄時可以訪問Mac OS X粘貼板嗎?

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)。我假設解決這個問題的唯一方法是在與粘貼板相同的環境中運行應用程序,但這可能嗎?

回答

3

訪問紙板直接看起來是一個不走。首先,使用紙板服務器的mach端口啓動won't register the processes1。您首先需要找到一種方法來獲取紙板服務器的馬赫端口(mach_port_names?)。此外,用戶會話之間的直接通信是prohibited2,其他通信有限。我不確定您的程序是否有權連接到粘貼板服務器。

下面是使用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; 
} 

我要離開的核心基礎之上的做法,但你可能會想使用NSAppleEventDescriptor提取從蘋果事件回覆剪貼板中的內容。

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或腳本編輯器時設置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(Mach端口包裝器):
  5. Apple Events Programming Guide
  6. Apple Event Manager Reference
  7. AEBuild*, AEPrint* and Friends
  8. AEBuildAppleEvent上CocoaDev
  9. Mac OS X Debugging Magic(用於AEDebugSends等是AEDebug *環境變量)在Leopard或虎
3

我試過的AppleScript做它,和它的工作(即使通過SSH調用)。我的腳本如下:

#!/usr/bin/osascript 

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

這絕對不是一個理想的解決方案,但也許如果你計算出的AppleScript是怎麼做的,然後它會幫你實現它自己。

+0

啊,很好。值得一看。 – 2009-10-25 16:54:28

+0

AppleScript使用Apple事件。它們很混亂,一些文檔很差。 – outis 2009-10-28 14:10:34

1

看看pbpaste(獲取剪貼板的內容)和pbcopy(將內容複製到剪貼板)。通過SSH也可以正常工作。 :)

在Mac OS X雪豹:

pbcopy Mac http://www.hillrippers.ch/temp/pbcopy.png

在Ubuntu 9.04:

pbpaste Ubuntu http://www.hillrippers.ch/temp/pbpaste.png

+0

他們似乎有同樣的問題。可能任何不是WindowServer後代的東西都不會被認爲是登錄會話的一部分,因此無法訪問粘貼板服務器,但這是一個瘋狂的猜測。需要更多的研究。 – outis 2009-10-28 14:13:08

+0

嗯,當我使用SSH從我的Linux機器連接到我的Mac時,它的工作原理與我在查看剪貼板或在本地使用`pbpaste`時的結果相同。在哪種情況下,您發現它不起作用? – Pascal 2009-10-28 14:28:45

0

您可以通過SSH與PasteboardCreate訪問雪豹剪貼板但不能。

您可能不希望將pbcopy和pbpaste用於完整的粘貼板同步,因爲這些只處理純文本,RTF和EPS。例如,如果您複製圖像,然後嘗試用pbpaste寫出圖像,則不會得到任何輸出。

假設您在兩臺計算機上都有用戶會話中運行的應用程序,可以將粘貼板數據序列化爲文件,通過SSH傳輸,從遠程端的應用程序讀取,然後將粘貼板數據在遠程粘貼板上。但是,獲得粘貼板序列化的權利可能會非常棘手,我不確定操作系統和體系結構之間的便攜式粘貼板數據是如何的。