Archive for 7月, 2013

2013/07/31 指定アプリケーションがオープン可能なファイル種別をリストアップ v2

必要に迫られて、少々場当たり的に書いた、「指定アプリが扱えるファイルのタイプとファイル拡張子のリストをタブ区切りテキストで取得するAppleScript」のバージョンアップ版です。

由緒正しき「作り捨てScript」(あんまり用途がないので保存するのすら惜しいレベル)なので、まさかバージョンアップすることなどないと思っていたのですが……いろいろと指摘があり、処理がいまいちな点を書き換えてみました。

 Info.plistをコピーしてから読み込み → 直接読み込み
 ぼんやりとエラー対策していた → Recordを文字列化して指定ラベルの値があるかどうか事前にチェック

直してみて気付いた点は、System Eventsでバンドル内のInfo.plistファイルをPOSIX pathで直接指定できるものの、この際にパスを「quoted form of」でクォートするとエラーになるということです(10.8)。この発見が、本バージョンで唯一の収穫ということに。

スクリプト名:指定アプリケーションがオープン可能なファイル種別をリストアップ v2
–指定アプリのInfo.plistからCFBundleTypeNameとCFBundleTypeExtensionsの情報をタブ区切りテキストで取得するツール v2

script spd
  property aList : {}
  
property aText : “”
end script

–初期化
set aList of spd to {}
set aText of spd to “”

–処理対象アプリケーションの選択
set anApp to choose application with prompt “Doc Typesを取り出す対象のアプリケーションを選択”

–処理対象のアプリケーションの名称を取得
try
  tell anApp
    launch –起動してみる(めっちゃ重要)
    
set aName to name –名称取得
  end tell
on error
  display dialog “プロセス起動も名称取得もできなかったので処理終了”
  
return
end try

–起動したアプリのプロセス特定 → ファイルパスの特定
tell application “System Events”
  set aProc to every process whose name is aName
  
if length of aProc = 0 then
    display dialog “No Hit”
    
return
  end if
  
  
set aaProc to contents of first item of aProc
  
tell aaProc
    set apPath to application file –Path to application file as alias
  end tell
end tell

–指定アプリケーションのバンドル内のInfo.plistのパスを取得
set apPathStr to POSIX path of apPath
set aInfoPath to apPathStr & “Contents/Info.plist”

tell application “System Events”
  set vRec to value of property list file aInfoPath –★【重要】 ここで、”quoted form of”を付けるとエラーになるので注意!!!★
  
  
try
    set dtypeList to CFBundleDocumentTypes of vRec
  on error
    display dialog “とくに、特定のファイルタイプのオープンをサポートしているアプリケーションではないようです”
    
return
  end try
  
end tell

repeat with i in dtypeList
  
  
set j to contents of i
  
  
set tmpStr to recToString(j) of recToStrKit
  
set tmpStr to tmpStr as string
  
  
if tmpStr contains “CFBundleTypeName” then
    –常識的なものへの対処
    
set aName to CFBundleTypeName of j
    
  else if tmpStr contains “CFBundleTypeOSTypes” then
    –Illustrator対策
    
set aaNames to CFBundleTypeOSTypes of j
    
set aName to retArrowText(aaNames, “, “) of me
    
  else if tmpStr contains “LSItemContentTypes” then
    –Excel対策
    
set aaNames to LSItemContentTypes of j
    
set aName to retArrowText(aaNames, “, “) of me
    
  end if
  
  
  
try
    set extName to CFBundleTypeExtensions of j
  on error
    set extName to {“”}
  end try
  
  
if length of extName > 1 then
    set extStr to retArrowText(extName, “, “) of me
  else
    set extStr to contents of first item of extName
  end if
  
  
–拡張子の指定のあるものだけをレポート対象とする
  
if extStr is not equal to “” then
    set aText of spd to aText of spd & aName & tab & extStr & return
  end if
  
end repeat

–あとかたづけ
set aList of spd to {}

return contents of aText of spd

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

script recToStrKit
  
  
–エラートラップを使って、わざとエラーを発生させ、エラーメッセージからレコードをstringに変換する
  
on recToString(aRec)
    
    
–レコードを無理矢理stringにcastして、エラーメッセージを取得する
    
try
      set a to aRec as string –ここでエラー発生
    on error aMes
      set a to aMes
    end try
    
    
–エラーメッセージ文字列から、元のレコードの情報を組み立てる
    
set b to trimStrFromTo(a, “{”, “}”)
    
set b to “{” & b & “}”
    
    
return b
    
  end recToString
  
  
  
on trimStrFromTo(aStr, fromStr, toStr)
    –fromStrは前から探す
    
if fromStr is not equal to “” then
      set sPos to (offset of fromStr in aStr) + 1
    else
      set sPos to 1
    end if
    
    
–toStrは後ろから探す
    
if toStr is not equal to “” then
      set b to (reverse of characters of aStr) as string
      
set ePos to (offset of toStr in b)
      
set ePos to ((length of aStr) - ePos)
    else
      set ePos to length of aStr
    end if
    
set aRes to text sPos thru ePos of aStr
    
    
return aRes
    
  end trimStrFromTo
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/07/31 レコードをstringに変換するkit

recordをstringに変換する、おなじみのAppleScriptです。初期のものは日本語環境でしか使えませんでしたが、最近のバージョンは日本語環境依存しなくなりました。せっかくなので、ルーチンのかたまり(便宜上、○○kitと呼んでいます)にして掲載しておきます。

そもそもAppleScriptにrecordをstringにする機能はないのですが、run scriptコマンドやerror trapを用いて、不可能を可能にする「変態技術」のうちのひとつです。まっさきにライブラリに突っ込んで、こんな大量のルーチンがゴロゴロしているという状況は解消したいところです。

スクリプト名:レコードをstringに変換するkit
set aRec to {aData:1, bData:2}
set aText to recToString(aRec) of recToStrKit
–> "{aData:1, bData:2}"

script recToStrKit
  
  
–エラートラップを使って、わざとエラーを発生させ、エラーメッセージからレコードをstringに変換する
  
on recToString(aRec)
    
    
–レコードを無理矢理stringにcastして、エラーメッセージを取得する
    
try
      set a to aRec as string –ここでエラー発生
    on error aMes
      set a to aMes
    end try
    
    
–エラーメッセージ文字列から、元のレコードの情報を組み立てる
    
set b to trimStrFromTo(a, "{", "}")
    
set b to "{" & b & "}"
    
    
return b
    
  end recToString
  
  
  
on trimStrFromTo(aStr, fromStr, toStr)
    –fromStrは前から探す
    
if fromStr is not equal to "" then
      set sPos to (offset of fromStr in aStr) + 1
    else
      set sPos to 1
    end if
    
    
–toStrは後ろから探す
    
if toStr is not equal to "" then
      set b to (reverse of characters of aStr) as string
      
set ePos to (offset of toStr in b)
      
set ePos to ((length of aStr) - ePos)
    else
      set ePos to length of aStr
    end if
    
set aRes to text sPos thru ePos of aStr
    
    
return aRes
    
  end trimStrFromTo
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/07/30 指定アプリケーションがオープン可能なファイル種別をリストアップ

必要に迫られて、少々場当たり的に書いた、「指定アプリが扱えるファイルのタイプとファイル拡張子のリストをタブ区切りテキストで取得するAppleScript」です。書くのに30分ぐらいしかかかっていないと思います。

指定アプリのInfo.plistを……バンドル内に存在する状態でオープンするのは無理なので、いちどテンポラリフォルダにコピーして、System Events経由で値の取得を行い、CFBundleDocumentTypesのエントリから、CFBundleTypeNameとCFBundleTypeExtensionsの情報をタブ区切りテキストで取得します。

ap1.png
▲処理対象のアプリケーションを選択して……

ap2.png
▲AppleScriptエディタの「結果」欄にデータ出力する

正直、Photoshopの情報だけリスト化することを目指して作ったので、どんなアプリに対してでも使えるようには作っていません。いえ、作っても意味がないというべきなのか、万能ツールはねらわずに「作り捨てツール」のレベルなのでそんなもんです。

■うまくデータを引き出せる例
Adobe Photoshop, Illustrator, InDesign, AppleScriptエディタ、Safari、連絡先(アドレスブック)など

■データを引き出せない例(エラーになる)
iTunes、Mail.app、Terminal.app

■そもそも書類をオープンするようになっていない例
AppleScript Runner、Automator Runner

Photoshopに対して大量の画像ファイルの一括変換を行わせるツールを作っていたときに、ドラッグ&ドロップで処理を受け付けるべきファイルと、受け付けるべきではない(画像以外の)ファイルの見通しを立てるために資料を作っていました。

ap4.png

PhotoshopのInfo.plistをXcodeでひらいて、Keynoteの表にコピペしていくという地味で根気の必要な作業です。

ap3.png

途中まで(手で)作っていたものの……

「Photoshopの100個以上もあるファイルタイプを全部コピペで資料化するのはイヤだ!」

と、ブチ切れ。方針転換してAppleScriptで書きました。実行したら一瞬で終了。

本ツールで作業量を圧倒的に減らすことができたものの、活躍する機会はあまりなさそうです。

スクリプト名:指定アプリケーションがオープン可能なファイル種別をリストアップ
–指定アプリのInfo.plistからCFBundleTypeNameとCFBundleTypeExtensionsの情報をタブ区切りテキストで取得するツール

script spd
  property aList : {}
  
property aText : “”
end script

–初期化
set aList of spd to {}
set aText of spd to “”

–処理対象アプリケーションの選択
set anApp to choose application with prompt “Doc Typesを取り出す対象のアプリケーションを選択”

–処理対象のアプリケーションの名称を取得
try
  tell anApp
    
    
launch –起動してみる(めっちゃ重要)
    
    
set aName to name –名称取得
    
  end tell
  
on error
  display dialog “プロセス起動も名称取得もできなかったので処理終了”
  
return
end try

–起動したアプリのプロセス特定 → ファイルパスの特定
tell application “System Events”
  set aProc to every process whose name is aName
  
if length of aProc is not equal to 1 then
    display dialog “No Hit”
    
return
  end if
  
  
set aaProc to contents of first item of aProc
  
tell aaProc
    set apPath to application file –Path to application file as alias
  end tell
end tell

–指定アプリケーションのバンドル内のInfo.plistのパスを取得
set apPathStr to POSIX path of apPath
set aConPath to quoted form of (apPathStr & “Contents/”)
set aifoPfetch to aConPath & “Info.plist”

set aRes to do shell script “ls “ & aifoPfetch
set shelList to paragraphs of aRes

if length of shelList > 1 then
  set shelRes to contents of first item of (choose from list shelList)
else
  set shelRes to contents of first item of shelList
end if

–デスクトップ上にコピーする際のファイルパスを生成
set aRandomName to (POSIX path of (path to temporary items from user domain)) & (do shell script “uuidgen”) & “.plist”

do shell script “cp “ & quoted form of shelRes & ” “ & quoted form of aRandomName

set aRandomAlias to (POSIX file aRandomName) as alias

tell application “System Events”
  set vRec to value of property list file (aRandomAlias as string)
  
try
    
    
set dtypeList to CFBundleDocumentTypes of vRec
    
  on error
    do shell script “rm “ & quoted form of aRandomName
    
display dialog “とくに、特定のファイルタイプのオープンをサポートしているアプリケーションではないようです”
    
return
  end try
end tell
–> {{CFBundleTypeExtensions:{”psd”, “pdd”}, CFBundleTypeOSTypes:{”8BPS”, “8BIM”}, CFBundleTypeName:”Adobe Photoshop file”, CFBundleTypeIconFile:”PS_PrimaryFileIcon.icns”, CFBundleTypeRole:”Editor”}………}

repeat with i in dtypeList
  try
    set aName to CFBundleTypeName of i
    
  on error
    –Illustrator対策
    
set aaNames to CFBundleTypeOSTypes of i
    
    
if length of aaNames > 1 then
      set aName to retArrowText(aaNames, “, “) of me
    else
      set aName to contents of first item of aaNames
    end if
    
  end try
  
  
  
try
    set extName to CFBundleTypeExtensions of i
  on error
    set extName to {“”}
  end try
  
  
if length of extName > 1 then
    set extStr to retArrowText(extName, “, “) of me
  else
    set extStr to contents of first item of extName
  end if
  
  
–拡張子の指定のあるものだけをレポート対象とする
  
if extStr is not equal to “” then
    set aText of spd to aText of spd & aName & tab & extStr & return
  end if
  
end repeat

–あとかたづけ
do shell script “rm “ & quoted form of aRandomName
set aList of spd to {}

return contents of aText of spd

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/07/19 Desktopのプロパティを取得、設定

海外のMLをのぞいていたら、System Events経由でDesktopのプロパティを取得できることを(いまさらながらに)見つけました。その内容のまとめです。

Classic Mac OSの時代からMac OS Xの時代に切り替わったあたりから、それまでFinderに所属していた命令やオブジェクトが、続々とSystem Eventsに移管されてきました。電源オフやスリープなどの命令が入っている「Power Suites」ももともとはFinderに所属しており、まだFinderの用語辞書にその痕跡が残っていますが、いつか完全にFinderから消える日がくることでしょう。

とりあえず、Desktopのプロパティの取得を試してみました。

スクリプト名:Desktopのプロパティを取得
tell application “System Events”
  set dCount to count every desktop
  
  
repeat with i from 1 to dCount
    tell desktop i
      properties
    end tell
  end repeat
  
end tell

–> {display name:”W2442″, id:458588002, change interval:1800.0, name:”W2442″, picture:file “Cherry:Library:Desktop Pictures:Bahamas Aerial.jpg”, class:desktop, pictures folder:file “Cherry:Users:maro:Pictures:”, translucent menu bar:true, random order:false, picture rotation:0}

–> {display name:”カラー LCD”, id:69731200, change interval:1800.0, name:”カラー LCD”, picture:file “Cherry:Library:Desktop Pictures:Grass Blades.jpg”, class:desktop, pictures folder:file “Cherry:Library:Desktop Pictures:”, translucent menu bar:true, random order:false, picture rotation:0}

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

Desktopの数というのは、つまりモニターの数を意味しています。

desktop1.png

詳細な情報を取得できるため、なかなか面白いところです。「change interval」という、見慣れない属性がありますが、これはデスクトップピクチャの変更間隔です。1800秒ということは、30分ですね。

もちろん、取得だけでなく設定も行えます。current desktopというのが、primary desktopのようで……つまり、メニューバーが存在しているメインの画面です。「translucent menu bar」という属性(メニューバーの透過表示の制御)があり、これがr/wできるので試してみました。

実行するたびに、メニューバーが透過/非透過と切り替わります。

Mac OS X 10.4.11ではSystem Eventsにdesktopオブジェクトの定義そのものが存在せず、10.5.8ではdesktopオブジェクトは存在するものの、「translucent menu bar」の属性が存在していませんでした。10.6以降の環境で動作することを確認しています。

スクリプト名:メニューバーの透過を切り替える
tell application “System Events”
  tell current desktop –Primary Desktopのこと
    properties
    
–> {display name:”W2442″, id:458588002, change interval:1800.0, name:”W2442″, picture:file “Cherry:Library:Desktop Pictures:Bahamas Aerial.jpg”, class:desktop, pictures folder:file “Cherry:Users:maro:Pictures:”, translucent menu bar:true, random order:false, picture rotation:0}
    
    
set transF to translucent menu bar
    
set transF to not transF –論理を反転
    
set translucent menu bar to transF
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/07/17 Photoshop CS6で複数の画像に対して1枚目の選択範囲を適用して切り抜き実行

Photoshop上で複数の画像(同じサイズ)をオープンしておき、最初にオープンした画像の上で任意の範囲を選択しておくと、その選択範囲でオープン中のすべての画像の切り抜きを行うAppleScriptです。

Photoshop CS6上でテスト&実行してみましたが、とくにそれほどバージョン依存はしていないものと思われます。

ps1.png

mj21.png

mj3.png

画面のスナップショットなど、同一ウィンドウ上の操作内容を説明するためにウィンドウごとスナップショットを(Command-Shift-4で)撮っておくことがままあります。ただ、ウィンドウ全体をそのまま載せるのはいまひとつ。操作箇所など同じ部分を切り抜いておきたいところです。

そのために、選択範囲そのものをコピーする機能がPhotoshopにはあるのですが、それとて画像の枚数が増えるとかったるくてやっていられません。

そこで、さっくり作ってみました。作るのに5分もかかっていませんが、案外役に立つと思います。

スクリプト名:Photoshop CS6で複数の画像に対して1枚目の選択範囲を適用して切り抜き実行
–同一の選択範囲で複数画像を切り抜く
tell application id “com.adobe.photoshop” –バージョン依存しないようにアプリケーション名称ではなくバンドルIDで指定
  set dCount to count every document
  
  
tell document 1
    set aSel to selection
    
try
      set {x1, y1, x2, y2} to bounds of selection
    on error
      display dialog “選択範囲が設定されていません。” buttons {“OK”} default button 1
      
return
    end try
    
    
crop bounds {x1, y1, x2, y2}
    
  end tell
  
  
  
–2枚目以降のピクチャを処理
  
repeat with i from 2 to dCount
    set current document to document i –指定ドキュメントを最前面に
    
    
tell document i
      crop bounds {x1, y1, x2, y2}
    end tell
  end repeat
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/07/17 MacJournal 6.0.7 Beta10で選択中のテキストの取得「だけ」可能に

Dan Schimpf Software(販売はMariner Software)のジャーナリングソフトウェア(日常の雑多なメモやWebページの内容をコピペして放り込んでおく記録ソフト)「MacJournal」は、いまや押しも押されもせぬ「定番ソフトウェア」の地位を築いたといえます。

mj4.png

ただ、AppleScript関連では疑問の残る実装もそこかしこに見られ、Beta段階のバージョンでは「なんでこの機能が使えなくなったんだ?」と思わされること幾度。

かなり頻繁にAppleScript用語辞書の書き換えを行われていますが、それだけ試行錯誤が多い(失敗も多い)といえます。

過去の(自分が知りうるかぎりの)MacJournalのアップデート履歴は以下のとおりで、赤いラベルを付けてあるのが「AppleScript用語辞書に有為な変更が加わった」バージョンです(マイナーバージョンアップするたびに、主要AppleScript対応アプリの用語辞書をHTML書き出しして、diffで差分比較を行っています)。

mj0.png

今回、最新のMacJournal 6.0.7 Beta10において、documentの属性として「selected text」という項目が機能するようになりました。これで、選択中のentry内の選択中のテキストを取得することができるようになりました。

mj1.png

ただし、ご覧のとおりこの属性は「r/o」(read only)に設定されています。

AppleScriptからは、各アプリのデータ構造にアクセスしたり、選択中の項目にアクセスしたりできることが望ましいのですが、「読むだけで書けない」というのはナンセンスです。

一応、Beta10の段階の機能を用いて、選択中のテキストの書き換えAppleScript(↓)は即座に書くことはできましたが……これは、selected textのcontentsを書き換え可能であれば、わざわざこんな長い記述を書かなくて済むものです。

mj2.png

この、テキストを選択した状態で本AppleScriptを実行すると……

mj3.png

のようになります。read onlyの「selected text」から文字情報を取得して、選択中のentryの全文のテキストから、selected textの文字の該当部分を置換して、selected entryにテキストを書き戻しました。

selected text(のcontents?)に書き込みができれば、わざわざこんなプログラムを書かなくて済むのですが、現状ではこんな遠回りかつアクロバティックな対応が必要になるという実例です。

スクリプト名:MacJOurnal 6.0.7beta10のselected textでread,writeを実行する実験
–MacJournal 6.0.7 Beta 10で追加された機能「selected text」をなんとかまともに使いこなすための不毛な努力

set repStr to “XXXXXXXXXX”

tell application “MacJournal”
  
  
–複数エントリーが選択されている状態であれば処理終了
  
set sList to selected entries
  
if length of sList is not equal to 1 then
    display dialog “Too many selected entry.” buttons {“OK”} default button 1
    
return
  end if
  
  
–選択中のテキストを取得
  
tell document 1
    set aStr to selected text –選択中のEntry中の選択中のテキストを取得できるようになった。だが、書き込みはできない。
  end tell
  
  
–選択中のEntryから本文テキストを取得して、上記のテキストを置換する試み。短すぎると(1文字とか)処理の精度が落ちる
  
tell selected entry
    set wholeText to plain text content
  end tell
  
  
set newText to repChar(wholeText, aStr, repStr) of me
  
  
–選択中のEntry本文テキストに書き戻す
  
tell selected entry
    set plain text content to newText
  end tell
  
  
–なぜかEntryにデータを再設定するとPlain Text状態が解除されるので、明示的にPlain Textに設定してみた
  
convert to plain text selected entry –個人の用途に応じて、必ずしも必要というわけではない
  
end tell

–文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/07/12 ParallelesにゲストOSとしてインストールしたOS XをAppleScriptで制御

Parallels Desktop 8.0(以下、Parallels)には(それ以前からも?)ゲストOSにWindowsやLinuxだけでなく、Mac OS Xをインストールできることを思い出し、実験してみました。

ためしに、あまり稼働環境が残っていないOS X 10.7を検証用にインストールしてみることに。

Parallelsには、

  Mac OS X 10.5 Server, Mac OS X 10.6 Server, OS X 10.7, OS X 10.8

などのMac OS Xをインストール可能とのこと。ちなみに、まだリリースされていないOSはインストール時にはじかれてしまいました。

para20.png

インストール用アプリケーションのバンドル内に存在する、ディスクイメージ(InstallESD.dmg)をFinder上で抜き出して、Parallelesのバーチャルマシン作成元として同dmgファイルを指定。これで問題なくOS X 10.7をParallelsにインストールできました。

para21.png

画面左側のParallelsのウィンドウ内でOS X 10.7の仮想環境が稼働しています。

インストールしたての状態では、IPアドレスをホスト側(10.8.4)と異なる管理のものを使用する設定になっていたので、そのままでは通信できないと判断。

ネットワーク設定を変更して……

para22.png

仮想環境でも、192.168.0.xのClass CのIPアドレスで、ホスト側のIPアドレスと衝突しないものが割り振られていることを確認。

para23.png

こうなると、単にネットワーク上の別のマシンにアクセスする感覚で仮想環境にアクセスできます。

このように、LAN上の他のマシンをコントロールするのとまったく変わらない調子でAppleScriptから命令することができました(ユーザー名とパスワードをAppleScript中に直接書いていないのはわざとです)。

厳密にいえば、ゲストOS側のOS XにはApple IDとパスワードを入力しても認証が通らず……ということは、AppStore経由のアプリケーションをそのままインストールすることが(通常のやり方では)できないわけで、少々困ってしまうところです。

すぐには用途を思いつきませんが、時間的に余裕のあるときにテストしておけてよかったです。何かのときに使えるかもしれません。

スクリプト名:Parallels上のMacにリモートコントロール
tell application “Safari” of machine “eppc://192.168.0.11″
  make new document
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/07/12 オープン中のMacのPowerPointの書類をWindows XPのPowerPointでオープン

Mac上のOffice 2011のPowerPointでオープン中のPowerPoint書類を、Parallels 8.0上で動くWindows XP上のOffice 2003でオープンさせるAppleScriptです。

各個人の環境によって、ゲストOSのインストール名称が異なる可能性が高いので、若干の手直しは必要です。

ここでは、Windows XPを「Microsoft Windows XP(1)」の名前でインストール、起動してあります。

para13.png

ホームディレクトリの直下に、「Applications (Parallels)」フォルダがあり、

para7.png

その中にインストールしたゲストOSの名称にもとづいた各OS上のネイティブアプリにイベントを転送する専用のプロキシーアプリケーションが自動でインストールされます。

para3.png

この中にあるPowerPoint(へのイベントを伝達するだけのプロキシーアプリケーション)に、Mac OS XネイティブのOffice 2011のPowerPointでオープン中の書類のファイルパスを伝えれば、Windows上で同じ書類をオープンして、表示のされ方の違いなどを確認できます。

para1.png

para2.png

Microsoft Office以外でも、AdobeのCreative Suites/Creative Crowdなど各種マルチプラットフォーム展開しているアプリにおいて、実際の見え方の違いをその場で確認できると便利ではないでしょうか?

スクリプト名:オープン中のMacのPowerPointの書類をWindows XPのPowerPointでオープン
property aBundle : “” –バンドルID計算キャッシュ

set a to getPPTpath() of me –PPT書類のパスを取得
if a = false then return

–Windows XPのPowerPointアプリのプロキシーアプリを探す
set homePath to path to home folder from user domain
set homePathStr to homePath as string
set homeParallelsApps to homePathStr & “Applications (Parallels):”
set winXPappPath to homeParallelsApps & “Microsoft Windows XP (1) Applications:” –このあたり、ユーザーごとにフォルダ名が違うかも

if aBundle = “” then
  tell application “Finder”
    tell folder winXPappPath
      set fList to (every file whose name contains “Microsoft PowerPoint”) as alias list –ここで、不気味なほど時間がかかる
    end tell
  end tell
  
  
if fList = {} then
    display dialog “Windows XPのPowerPointが見つかりません”
    
return
  end if
  
set aPPTapp to contents of first item of fList
  
  
set infoF to info for aPPTapp
  
set aBundle to bundle identifier of infoF
end if

tell application “Finder”
  open file a using application file id aBundle
end tell

–オープン中の最前面のPowerPoint書類のフルパスの文字列を取得
on getPPTpath()
  tell application “Microsoft PowerPoint”
    set pCount to count every presentation
    
if pCount = 0 then return false
    
tell presentation 1
      –Documentのフルパスを取得する
      
set aPath to full name
      
return aPath
    end tell
  end tell
end getPPTpath

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/07/12 Safariでオープン中のURLを指定のWindowsのWebブラウザでオープン

Mac上のParallelsの上で動く、Windowsに対してイベントをAppleScriptから(Parallels経由で)投げて、Mac上のSafariで現在オープン中のURLをWindows 8.1Beta上のInternet Explorer 11で開いてみました。

調査したところ「Safariでオープン中のURLをIEでオープンする機能」はParallels Desktop 8(以下、Parallels)の標準機能で持っているらしいのですが、画面上で確認したかぎりでは見つけられませんでした。本Scriptでは、指定すればWindows上のChromeだろうがFireFoxだろうが対応できるので、標準機能よりも高度な処理に発展できます。

Paralles上でWindows 8.1Betaを起動した状態。この状態だと、

para10.png

ユーザーのホームディレクトリに「Applications(Parallels)」というフォルダが存在しており、

para7.png

さらに、その中に各ゲストOSのフォルダが存在。ここにWindows 8.1Betaのフォルダも存在しています。

この中に、各Windowsアプリケーションにイベントを転送するプロキシーアプリケーションが存在しています。もちろん、IE11も。

para11.png

ただし、ここで「Modern Internet Explorer」というWindows StoreアプリのIEも存在しており、これにイベントを投げてもWindows 8.1側でWebブラウザ表示にならない(タイル表示からInternet Explorerを選択すれば、オープンさせた内容を確認することは可能)ので、実用性がいまひとつでした。とっととWeb表示に切り替わってほしいので、Internet Explorerを指定しておきたいところです。

では、Finderに「Windows 8.1 Beta Applications」内の「Internet Explorer」ファイルを取得させればよいわけですが、ここにトンだ落とし穴が。

Finder上でこの「Internet Explorer」アプリの情報を調べてみると……

para12.png

Mac OS Xのローカライズドファイルネームの仕組みを使って、名前の指定を行っていることが分ります。その関係かどうか分りませんが、このディレクトリでAppleScriptからファイル名の収集を行うのにやたらと時間がかかります(MacBook Pro Retinaなのに、SSD上のデータなのに)。

この「Internet Explorer」の情報(Bundle ID)については、AppleScriptの初回実行時のみ取得するようにして、2回目以降はpropertyにキャッシュした内容を利用することにしました(処理速度向上のため)。こういう時間がかかる割に毎回同じ内容が返ってくるような処理結果はキャッシュしておくにかぎります。そういうのを毎回演算するのは、時間の無駄です。エラーが発生した場合にかぎって、再計算すればいいでしょう。

そして、「Internet Explorer」のBundle IDを取得して、open locationのイベントを投げます。すると、Parallelsを経由してWindows 8.1BetaのInternet Explorerにイベントが伝達され、Safariでオープン中のURLがWindows側に表示されます。

para8.png

このScriptを発展させて、指定URLを各バージョンのWindowsの各Webブラウザで一気に表示させるようなAppleScriptに仕上げると、かなり使い勝手がいいでしょう。仮想マシンはメモリーの許す限りいくつでも起動できるので、Windows XPとWindows 7とWinodws 8/8.1の仮想マシンを起動しておき、すべての対象OSのすべてのWebブラウザに一気にイベントを投げるという寸法です。

ただ、RAMが8GBの環境ではいささかつらく、最低でも16GBぐらいはほしいところです。

スクリプト名:Safariでオープン中のURLをWin 8.1のIEでオープンする
property aBundle : “” –バンドルID計算キャッシュ

–Safariの最前面のウィンドウからURLを取得
tell application “Safari”
  set dCount to count every document
  
if dCount = 0 then return
  
  
tell document 1
    set aURL to URL
  end tell
  
  
if aURL = “bookmarks://” then return
  
if aURL = “topsites://” then return
  
end tell

–Windows XPのPowerPointアプリのプロキシーアプリを探す
set homePath to path to home folder from user domain
set homePathStr to homePath as string
set homeParallelsApps to homePathStr & “Applications (Parallels):”
set winXPappPath to homeParallelsApps & “Windows 8.1 Beta Applications:” –このあたり、ユーザーごとにフォルダ名が違うかも

if aBundle = “” then
  tell application “Finder”
    tell folder winXPappPath
      set fList to (every file whose name of it contains “Internet Explorer”) as alias list –ここで、不気味なほど時間がかかる
    end tell
  end tell
  
  
if fList = {} then
    display dialog “Windows 8.1のIEが見つかりません”
    
return
  end if
  
set aPPTapp to contents of first item of fList
  
  
set infoF to info for aPPTapp
  
set aBundle to bundle identifier of infoF
end if

–Windows上のWeb BrowserでURLをオープン
tell application id aBundle
  open location aURL
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/07/11 AppleScriptでWindowsアプリをコントロール

かなり限定された条件下ではありますが、AppleScriptからWindowsのアプリをコントロールできました。

仮想環境であるParallels Desktop 8.0(以下、Parallels)を用いて、1台のMac上でMac→Windowsの制御を行いました。なお、Parallelsの機能に依存しているため、同様の操作をVMWareやVirtual Box上でできるわけではありません。

(1)Mac上のParallelsの上で動く、Windowsに対してイベントを(Parallels経由で)投げて、Mac上のSafariで現在オープン中のURLをWindows 8.1Beta上のInternet Explorer 11、Chromeで開いてみました。

para8.png

(2)Mac上のOffice 2011上でオープン中のPowerPoint書類を、Parallels 8.0上で動くWindows XP上のOffice 2003でオープンさせました。

para1.png

para2.png

■種明かし:Parallels Desktopの異種OS統合機能を利用

Parallels上のWindowsで動いているアプリをMacのDockにアイコン表示する機能があります。Dock上に表示されているWindowsアプリケーションは、その仲介役のプロキシーアプリがユーザーのホームディレクトリの中の「Applications(Parallels)」内に自動作成されます。

para7.png

para3.png

para5.png

これを使います。

プロキシーアプリに対してFileのパスを渡すとWindowsアプリでFileをオープンしますし、URLのオープンイベントを渡せば、指定の(Windows側の)Webブラウザで指定のURLをオープンするという寸法です。

種明かしをしてしまえば「なーんだ」という内容ですが、これを発展させていくと面白いことになるのではないでしょうか?

■将来的にできたらいいなと思うこと(たわごと)

プロキシーアプリケーションのAppleScript対応機能を強化し(どうやって?)、Windows上のアプリの状態を取得したり、データを設定できたりすると面白いと思います。

ただ……WindowsでAppleScriptのような機能を実現する仕組みを探してはみたものの、Windows 7/8で標準装備のPowerShellは単にコマンドラインのインタフェースでしかないし、自動操作系の機能を提供するものの多くはキーボード操作を実行するとかVBA(Excelなどの一部のアプリのみ操作)を実行する程度で、AppleScriptで期待するような属性の取得とか設定を行えるものは見つかりませんでした。

もうちょっと、Windowsアプリの状態取得や自動制御ができるとよいのですが……。

2013/07/02 Servicesフォルダへのパスを求める

OS X 10.7で追加された「services」フォルダのパスを求める記述サンプルです。

スクリプト名:Servicesフォルダへのパスを求める
–OS X 10.7で追加になった「services folder」へのパスを求める記述

path to services folder from system domain
–> alias “Macintosh HD:System:Library:Services:”

path to services folder from user domain
–> alias “Macintosh HD:Users:me:Library:Services:”

path to services folder from local domain
–> alias “Macintosh HD:Library:Services:”

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に