Archive for 9月, 2013

2013/09/29 Philips hueをコントロール

無線LAN経由でPhilips hueをコントロールして、hue LED電球の色を変えます。

色を変更するぐらいならとっても簡単にできるのですが、変更した色がhueに反映されるまでの時間が一定でないというか、リアルタイム性を極端に求められるような用途には使えません。

あと、実際に詳細に評価してみて感じたのですが……人間の目の問題だか、Philips hue側の発色特性の問題か分らない(たぶん前者)のですが、水色を指定しても人間の目には白く見えます。

スクリプト名:Hueをコントロール
–参照元:
—http://hackthehue.com
–Changing the Hue bulbs into Christmas colors

property startColor : “”
property beginTransisiton : “”
property yourHueIP : “”
property yourToken : “newdeveloper” –あらかじめ、Hue BridgeにGoogle Chromeでアクセスして(http://192.168.0.10/debug/clip.html)登録しておくこと
–Linkボタンというのは、Hue Bridge本体についている丸いボタンのこと
–設定関連は以下を参照のこと
–http://developers.meethue.com/gettingstarted.html

set yourHueIP to retHueBridgeIPAddress() of me
if yourHueIP = false then return

–turn the bulb on

set turnOn to the quoted form of “{\”on\”: true,\”bri\”: 254}”
do shell script “curl –request PUT –data “ & turnOn & ” http://” & yourHueIP & “/api/” & yourToken & “/lights/1/state/”
do shell script “curl –request PUT –data “ & turnOn & ” http://” & yourHueIP & “/api/” & yourToken & “/lights/2/state/”
do shell script “curl –request PUT –data “ & turnOn & ” http://” & yourHueIP & “/api/” & yourToken & “/lights/3/state/”

–on idle
repeat 10 times
  set startColor to “1400″
  
set beginTransition to “{\”hue\”: “ & startColor & “, \”sat\”: 254,\”bri\”: 254}”
  
set beginTransisiton to the quoted form of beginTransition
  
delay 0.5
  
do shell script “curl –request PUT –data “ & beginTransisiton & ” http://” & yourHueIP & “/api/” & yourToken & “/lights/1/state/”
  
do shell script “curl –request PUT –data “ & beginTransisiton & ” http://” & yourHueIP & “/api/” & yourToken & “/lights/2/state/”
  
do shell script “curl –request PUT –data “ & beginTransisiton & ” http://” & yourHueIP & “/api/” & yourToken & “/lights/3/state/”
  
delay 0.5
  
set endColor to “25000″
  
set beginTransition to “{\”hue\”: “ & endColor & “, \”sat\”: 254,\”bri\”: 254}”
  
set beginTransisiton to the quoted form of beginTransition
  
delay 0.5
  
do shell script “curl –request PUT –data “ & beginTransisiton & ” http://” & yourHueIP & “/api/” & yourToken & “/lights/1/state/”
  
do shell script “curl –request PUT –data “ & beginTransisiton & ” http://” & yourHueIP & “/api/” & yourToken & “/lights/2/state/”
  
do shell script “curl –request PUT –data “ & beginTransisiton & ” http://” & yourHueIP & “/api/” & yourToken & “/lights/3/state/”
  
delay 0.5
end repeat
–end idle

–HueのBridgeのIPアドレスを返す
on retHueBridgeIPAddress()
  set sText to “arp -na | grep \”at 0:17:88\”" –Normal
  
–set sText to “arp -na | grep \”at 1:17:88\”"–Error
  
try
    set aRes to do shell script sText
  on error
    return false
  end try
  
  
set bRes to trimStrFromTo(aRes, “(”, “)”) of me
  
return bRes
end retHueBridgeIPAddress

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

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

2013/09/29 Phillips hue日本国内発売記念 Philips hueのBridgeのIPアドレスを取得

ついに、2013年9月26日にPhilipsが日本国内でもhueの発売を開始しました(→ニュースリリース)。

Philips hueが何かといえば……無線LAN通信機能入りのLED電球で、コンピュータから色を自由に変えられます。オンラインのApple Store、およびApple Retail Storeで販売されています。

とりあえず、最初の人はスターターキット(bridge+LED電球3つ)を買うとよいでしょう。電球の規格が「E26」といっていますが、これはフツーの白熱球のソケットのサイズであり、日本国内でも(特殊な照明器具を買わなくても)使えます。ウチでも、白熱球をつけていた照明器具に、蛍光灯ランプに変えたあと……hueに差し替えて使っています。

hue LED電球単体で買うと、けっこう高い(7,000円ぐらいする)ので、「もう1つスターターセットを買えばいいや!」と考える人がいるようですが、スターターセット同梱のLED電球は同梱のbridgeと紐づけが行われているので、スターターセット同士の乗り入れはできないそうです。

3つ以上のhue LED電球を使いたい場合には単品のバルブを買い足す必要があります。

r0015644.jpg

r0015659.jpg

r0015660.jpg

r0015661.jpg

hueのLED電球(バルブ)はhue bridgeというステーションを介しコンピュータと通信を行います。hueとコンピュータの通信はオープン規格(ZigBee Alliance)にのっとっているので、資料もたくさんあります。

r0015656.jpg

電球の光を直接見ると、いまひとつ色が分らない感じですが……家の外から見ると、めちゃくちゃ光に色がついているように見えます。また、デジカメで撮影すると目でみるよりも派手に映ります。

img_1735.jpg

hueをコントロールするためにはhue bridgeのIPアドレスを取得する必要があるわけで……これがすべての基本中の基本です。掲載しているプログラムは、無線LANの環境下で……192.168.0.xxxのClass Cのネットワーク内で動作を検証しています。

hueについては、海外でユーザーが遊び倒しまくっていまして……実はAppleScriptから制御するための情報は(海外に)あふれ返っており、コントロールするのも簡単です。

この製品の難点は……hue bridgeのLEDが明るすぎて、寝室に置いているとまぶしくて迷惑、ということでしょうか。ウチでは、AirMacベースステーションの近くに、(まぶしくないように)裏面にひっくり返して置いています。

スクリプト名:HueのBridgeのIPアドレスを返す
set ipAdr to retHueBridgeIPAddress() of me
–> “192.168.0.10″

–HueのBridgeのIPアドレスを返す
on retHueBridgeIPAddress()
  set sText to “arp -na | grep \”at 0:17:88\”" –Normal
  
–set sText to “arp -na | grep \”at 1:17:88\”"–Error
  
  
try
    set aRes to do shell script sText
  on error
    return false
  end try
  
  
set bRes to trimStrFromTo(aRes, “(”, “)”) of me
  
return bRes
end retHueBridgeIPAddress

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

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

2013/09/24 AppleScriptObjCでCore Animation

AppleScriptObjCで、CoreAnimationを使用してLine(ほっそいNSBox)を360度回転させるサンプルです。

ani4.png
▲こういうひとたちです(Line=ほっそいNSBox)

AppleScriptObjCでCoreAnimationを利用する方法をいろいろ探していて、ようやくサンプルを見つけていじくっていました。一番大変だったのは、Viewに対するCore Animationの有効設定をXcode上で行う方法を見つけること。

ani2.png

ani3.png

これだけ(↑)。

XcodeのInterface Builderで「Core Animation Layer」にチェックを入れるだけ。これだけです。

AppleScriptObjCとCore Animationというと、月とスッポン、水と油ぐらい世界が違うもので……本当に探すのに苦労しました(結局、MacScripter.netにあったのを見つけられなかっただけでした、、)。

ani.png
▲反時計まわりに、おおよそ1回転まわります

ただ、360度回してみようとしているのですが、きっちり360度は回ってないですね(誤差として許容され得るものか、、、)。試行錯誤の最中です。

→ Xcodeプロジェクトのダウンロード(64KB)

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– vAnimation

– Created by Takaaki Naganoya on 2013/09/23.
– Copyright (c) 2013年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  
  property parent : class “NSObject”
  
property aTextField : missing value
  
  property arrow : missing value – IBOutlet for a long narrow NSBox
  
  on applicationWillFinishLaunching_(aNotification)
    – Insert code here to initialize your application before any files are opened
  end applicationWillFinishLaunching_
  
  on applicationShouldTerminate_(sender)
    – Insert code here to do any housekeeping before your application quits
    
return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  
  on awakeFromNib()
    –arrow’s layer()’s setAnchorPoint_({0.5, 0.5})
    
arrow’s layer()’s setAnchorPoint_({0.5, 1.0})
    
set xValue to (arrow’s layer()’s superlayer()’s |bounds|()’s |size|()’s width) / 2
    
    –set yValue to (arrow’s layer()’s superlayer()’s |bounds|()’s |size|()’s height) / 2
    
set yValue to (arrow’s layer()’s superlayer()’s |bounds|()’s |size|()’s height)
    
–arrow’s layer()’s setPosition_({xValue, yValue})
    
  end awakeFromNib
  
  
  on click_(sender)
    
    set ctx to current application’s NSAnimationContext’s currentContext()
    
–ctx’s setDuration_(0.1)
    
    repeat with i from 0 to 63 by 1
      
      set curI to (i / 10) as real
      
      aTextField’s setStringValue_(curI as string)
      
      arrow’s layer()’s setValue_forKeyPath_(curI, “transform.rotation”) – Rotation by degrees counterclockwise
      
      tell current application
        delay 0.1
      end tell
      
    end repeat
    
  end click_
  
end script

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

2013/09/24 数字の文字をローマ数字にエンコード v2

アラビア数字(1,2,3…)をローマ数字(I,II,III)にエンコードするAppleScriptを、分りやすく、読みやすく書き換えたものです。動作内容はほとんど変わりません。

分りやすく書くということは、当初のプログラムよりも冗長になるということです。また、コメントを見れば(プログラムの内容を忘れていたとしても)、すぐに内容を理解できるようにしておくことも重要です。

コメントが一切入っていないプログラムなんて、AppleScriptのプログラムでも、読む気はしません。海外の(英語圏の)ユーザーは、とかくAppleScriptのプログラムにコメントを入れないので、かえって表記が英語に近いだけに分りづらいものになりがちです。

プログラムを「読みやすく」するためには、だいたい以下のような作業を行います。

  ・圧縮表記(1行に複数の動作をまとめる)をやめる
  ・適切なコメントを入れる
  ・適切に改行を入れて、プログラムの処理内容のまとまりを表現する

実際にこれらの改修を行ってみました。これだけ読みやすくしておけば、プログラムの内容をメンテナンスしやすくなります。

また、エラー発生時の結果の返し方については完全に変更しました。このあたりは趣味の問題なのですが、error文でエラーを発生させるというのは、教育的な意味においては正しいやり方なのですが、巨大なプログラムを組んでいる場合には邪魔になります。

自分は、「明らかに間違った値」についてはfalseで値を返すとか、エラーフラグと結果をペアにして返す{true, “This is the result”} ことをよくやります。このほうが、プログラムも停まらないし、正しいが違うのか、その結果はどうなのかといった情報を一度に受け渡せます。

# 本リストはほぼ全行にコメントが入っていますが、「適切なコメント」量はもっとひかえめなものです

スクリプト名:数字の文字をローマ数字にエンコード v2
set rRes to arabic2roman(45)
–> “XLV”

–アラビ数字(1,2,3,4,5,6,7,8,9)からローマ数字(I,II,III,IV,V,VI,VII,VIII,IX)へのエンコード
–分りやすいように、圧縮記述されていたプログラムを展開して、コメントを付けてみた
on arabic2roman(n)
  
  
–ローカル変数であることを明示的に宣言しなくても大丈夫だが……
  
local r, i, n, nStr, aChar, strCount, aNum, bNum, aTmp
  
  
try
    –エラーチェック(が甘かったので修正)
    
if (n as integer) > 3999 or (n as integer) < 1 then
      return false –errorを発生させて処理が中断されるのは不本意なので、エラーの印としてfalseを返しておく
    end if
    
    
set r to “” –出力用の文字列を代入する変数
    
    
set strCount to length of (n as string) –文字数をかぞえる
    
set nStr to (n as string) –与えられた数値または数字の文字列を文字列にキャスト 45 -> “45″
    
    
    
–文字数分(=桁数分)ループする
    
repeat with i from 1 to strCount
      
      
set aChar to (item -i of nStr) –数字文字列を後方から前方へと1文字ずつ取り出す {”5″,”4″}
      
set aNum to aChar as integer –取り出した数字の文字1文字を数値にキャスト
      
set bNum to aNum + 1 –リスト内のアイテム番号は1から始まるが、数字(アラビア数字)は0からはじまるので、+1してリスト内のアイテム番号との調整を実施
      
      
–2DのListから、該当するローマ数字文字を抽出し、前方に連結する
      
set aTmp to item bNum of item i of ¬
        {{“”, “I”, “II”, “III”, “IV”, “V”, “VI”, “VII”, “VIII”, “IX”}, ¬
          {“”, “X”, “XX”, “XXX”, “XL”, “L”, “LX”, “LXX”, “LXXX”, “XC”}, ¬
          {
“”, “C”, “CC”, “CCC”, “CD”, “D”, “DC”, “DCC”, “DCCC”, “CM”}, ¬
          {
“”, “M”, “MM”, “MMM”}}
      
      
–上記2D Listの中身をアラビア数字で表現すると以下のようになる:
      
      
–{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},             —-1の位(=うしろから数えてアラビア数字の1文字目)
      
–{0, 10, 20, 30, 40, 50, 60, 70, 80, 90},         —10の位(=うしろから数えてアラビア数字の2文字目)
      
–{0, 100, 200, 300, 400, 500, 600, 700, 800, 900}, —100の位(=うしろから数えてアラビア数字の3文字目)
      
–{0, 1000, 2000, 3000}}              —1000の位(=うしろから数えてアラビア数字の4文字目)
      
      
–なお、ローマ数字では”0″は表記しないので、”0″の桁はヌル(”")で表現
      
      
set r to aTmp & r –2DListから検出した文字列を出力文字列の前方に連結
      
    end repeat
    
    
return r
    
  on error eMsg number eNum
    
    
return false –errorを発生させて処理が中断されるのは不本意なので、エラーの印としてfalseを返しておく
    
  end try
  
end arabic2roman

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

2013/09/23 アラビア数字文字列とローマ数字文字列の相互変換

アラビア数字(0,1,2,3,4,5…)とローマ数字(I, II, III, IV, V…..)の相互変換を行うAppleScriptです。海外のサブルーチンの紹介サイトに掲載されていました

B’zの25周年ライブの千秋楽に行ってきたら、みなさま「XXV」という文字の書かれたTシャツを着ている。つまり「XXV」という文字は、「25」のローマ数字表記なわけですが、アラビア数字とローマ数字の相互変換について興味を持ちました。

相互変換を行うプログラムが存在していないか確認してみたら……やはり、こういうのは海外(英語圏)の方がニーズがあるわけで、そのものズバリのものがAppleScriptで存在していました

HAS氏は、最近ちょっとMLでも見かけないですが……Apple ModとかAppScriptなどのプロジェクトで精力的に活動していた方です。AppleのCarbon Apple Event Manager廃止ショック以降、見かけないのですが……最近はどうしているのでしょうか?(と、日本語で書いても意味がない、、、)

プログラムについては、問題なく日本語環境でも動いていることを確認していますが、肝心のプログラムの中身が、「短く書く」ことを重視されているためか、ちょっと見ただけではまったく内容を把握できません。

内容を即座に把握できないと、OS側のバグのあおりをくらって書き直しを行う場合に、発生箇所の特定にとても困ります。

AppleScriptを覚えたての頃は、短く書くのがカッコいいと思っていましたが……いろいろ経験を積むと……理解しやすく、メンテナンスしやすく書くのが一番よいと思います。

ちなみに、ローマ数字は1〜3999までを表記することしかできないので、プログラム中ではそれに合わせてレンジ外のチェックを行っているようです。

スクリプト名:数字の文字をローマ数字にエンコード
–© 2003 HAS (http://applemods.sourceforge.net)

set rRes to arabic2roman(“45″)
–> “XLV”

on arabic2roman(n)
  – Piero Garzotto (http://scriptbuilders.net/files/romannumerals1.0.html)
  
local r, i, n
  
try
    if (n as integer) > 3999 then error “Max number is 3999″ number 1
    
set r to “”
    
repeat with i from 1 to (count (n as string))
      set r to item (((item -i of (n as string)) as integer) + 1) of item i of ¬
        {{“”, “I”, “II”, “III”, “IV”, “V”, “VI”, “VII”, “VIII”, “IX”}, ¬
          {“”, “X”, “XX”, “XXX”, “XL”, “L”, “LX”, “LXX”, “LXXX”, “XC”}, ¬
          {
“”, “C”, “CC”, “CCC”, “CD”, “D”, “DC”, “DCC”, “DCCC”, “CM”}, ¬
          {
“”, “M”, “MM”, “MMM”}} & r
    end repeat
    
return r
  on error eMsg number eNum
    error “Can’t arabic2roman: “ & eMsg number eNum
  end try
end arabic2roman

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

スクリプト名:ローマ数字を数字にデコード
–© 2003 HAS (http://applemods.sourceforge.net)

set aRes to roman2arabic(“XXV”)
–> 25

on roman2arabic(str)
  – Piero Garzotto (http://scriptbuilders.net/files/romannumerals1.0.html)
  
local str, r, i
  
set r to 0
  
repeat with i from 1 to count str
    set r to r + (item (offset of (item i of str) in “mdclxvi”) of ¬
      {1000, 500, 100, 50, 10, 5, 1}) * (((((offset of ¬
      (
item (i + 1) of (str & “@”)) in “mdclxvi@”) (offset of ¬
      (
item i of str) in “mdclxvi”)) as integer) * 2) - 1)
  end repeat
  
return r
end roman2arabic

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

2013/09/22 GarageBandをAppleScriptからコントロール

GarageBandは、「一応」AppleScript用語辞書を持っており、AppleScriptからコントロールできます。

GarageBandで音声の編集を行っていると、煩雑な作業に対してはAppleScriptで自動化したくなります。

しかし、GarageBandがAppleScriptに提供している主な機能は、再生や巻き戻し、早送りといったプレイバック系の機能が中心であり、編集時に役立つ機能や、iTunesへの書き出し時にさまざまな条件を変更して複数回行うといったものではありません。

最悪の場合には、GUI Scriptingを併用して強制的にコントロールすることも可能ですが、GarageBandの予想外の挙動により途中で中断されてしまう可能性もあるため、なんともいえないところです。

というわけで、「まっとうなAppleScriptのアプローチ」から、調べてみたサンプルをいくつか掲載しておきます。ただ、本当に基礎的な調査ができる程度なので期待しないでください。

スクリプト名:GarageBandのアプリ情報を取得する
tell application “GarageBand”
  properties
  
–> {name:”GarageBand”, frontmost:false, class:application, version:”6.0.5″}
end tell

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

スクリプト名:GarageBandでdocument(song)にアクセス
tell application “GarageBand”
  count every song –documentと書くと”song”と差し替えられる
  
tell song 1
    count every track
    
–> 3
  end tell
end tell

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

song(document)は複数オープンできませんし、songのpropertiesも取得できません。AppleScript用語辞書には書いてあるのに、その通りには動かないようです。ただ、GarageBandに対して誰もそんな真面目にAppleScriptの機能を調査するとはAppleの連中も思っていないようなので、こういう状態なのでしょう。

propertiesではアクセスできませんが、個別の属性値を調べるとある程度は調査できます。

スクリプト名:GarageBandでsongの属性に個別にアクセス
tell application “GarageBand”
  tell song 1
    set aName to name
    
–> “keiko_All_utairi.band”
    
    
set aPath to path
    
–> “/Users/maro/Music/GarageBand/Podcasting/utairi/keiko_All_utairi.band”
    
    
set aCPUload to CPU load
    
–> 2
    
    
set aCycleMode to cycle mode
    
–> false
    
    
set aMasterVol to master volume
    
–> 0.708661437035
    
    
set aTempo to tempo
    
–> error “GarageBand でエラーが起きました:AppleEvent のハンドラで誤りが起きました。” number -10000
    
    
set aClass to class
    
–> error “GarageBand でエラーが起きました:AppleEvent のハンドラで誤りが起きました。” number -10000
    
  end tell
end tell

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

「ダメなアプリの証明」ともいうべき、「見えないWindowのプロパティが取得できてしまう」状態でもあります。見えない(機能的に関係ない)Windowが見えてしまうのは、どうかと思います。

スクリプト名:GarageBandでWindowのプロパティにアクセス
tell application “GarageBand”
  set wCount to count every window –Windowの枚数を数えると、見えないウィンドウの情報も返ってくる
  
repeat with i from 1 to wCount
    properties of window i
    
    
(*
      get properties of window 1
    –> {zoomed:false, miniaturized:false, name:”My Song 3_18.band”, floating:false, modal:false, document:document “My Song 3_18.band”, miniaturizable:true, class:window, closeable:false, resizable:true, zoomable:true, visible:true, id:4308, bounds:{27, 39, 2003, 982}, titled:false, index:1}
  get properties of window 2
    –> {zoomed:false, miniaturized:false, name:”Apogee One”, floating:false, modal:false, document:missing value, miniaturizable:false, class:window, closeable:false, resizable:false, zoomable:false, visible:false, id:4261, bounds:{550, 434, 898, 913}, titled:false, index:2}
  get properties of window 3
    –> {zoomed:false, miniaturized:false, name:”Apogee Duet”, floating:false, modal:false, document:missing value, miniaturizable:false, class:window, closeable:false, resizable:false, zoomable:false, visible:false, id:4262, bounds:{1284, 28, 1697, 677}, titled:false, index:3}
  get properties of window 4
    –> {zoomed:true, miniaturized:false, name:”Apogee GiO”, floating:false, modal:false, document:missing value, miniaturizable:false, class:window, closeable:false, resizable:false, zoomable:false, visible:false, id:4263, bounds:{550, 438, 898, 766}, titled:false, index:4}
  get properties of window 5
    –> {zoomed:false, miniaturized:false, name:”GarageBand”, floating:false, modal:false, document:missing value, miniaturizable:true, class:window, closeable:true, resizable:true, zoomable:true, visible:false, id:4265, bounds:{528, 205, 1475, 731}, titled:true, index:5}
    *)

  end repeat
  
end tell

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

2013/09/20 本Blogの過去記事表示がおかしくなっていました→復旧

本日、本Blogの過去記事(/archives以下)へのアクセスがおかしくなっていました。

不気味なぐらいスパムコメントが少ないと思っていたら、なんと過去記事にアクセスできなくなっていたとは……

理由は不明ですが、管理画面で過去記事の表示方法を何度か切り換えてみたところ、現在は復旧しています。

なんだろう、、、、

2013/09/18 PowerMateをAppleScriptからコントロール

GriffinTechnologyのボリウム型USBデバイス「PowerMate」をAppleScriptからコントロールするサンプルです。

r0015872.JPG

登場から10年以上経過していますが、いまだにGriffin Technologyでは販売を継続しているようで、コンピュータの周辺機器としては異例の長寿商品。わが家では引き出しのコヤシと化して久しく、Web上で調べものをしていていまだに現役商品であることを知って腰を抜かしたぐらいです。おそらく、blink(1)などの類似LEDデバイスがたくさん世に出てきても、PowerMateは生き残ることでしょう。

GriffinTechnologyでは、Mac OS X 10.6以降用のOS向けにPowerMateドライバ3.0をリリースしており、これはドライバと言っているものの……普通のアプリケーションです。

そのため、このPowerMateアプリを終了させるとコントロールできなくなります。

power1.png
▲昔、GriffinTechnologyが配布していたツールの末裔に見える……

PowerMateアプリ側で、回転、押すなどのアクションに対して、キーストロークの設定やAppleScriptの実行などを指定できるようになっていますが、このPowerMateアプリ自体がScriptableになっており、このPowerMateアプリにAppleScriptから命令することで、状態を取得したり設定できます。

PowerMateアプリ3.0では、複数のPowerMateデバイスが接続されている場合でもそれぞれのPowerMateデバイスを識別して命令できるようになっています。

スクリプト名:PowerMateで接続されているデバイス一覧を取得する
tell application "PowerMate"
  set aList to every device
  
–> {device id "14100000" of application "PowerMate"}
end tell

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

スクリプト名:PowerMateデバイスの状態を取得する
tell application “PowerMate”
  tell device 1
    properties
  end tell
end tell
–> {class:device, id:”14100000″, brightness:0.1, should pulse:false, pulse rate:0.0, name:”PowerMate 1″}

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

スクリプト名:PowerMateデバイスの名前を変更する
tell application “PowerMate”
  tell device 1
    set name to “Piyomaru PowerMate”
    
properties
    
–> {class:device, id:”14100000″, brightness:0.1, should pulse:false, pulse rate:0.0, name:”Piyomaru PowerMate”}
  end tell
end tell

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

スクリプト名:PowerMateデバイスの点滅設定を変更
tell application “PowerMate”
  tell device 1
    set should pulse to true
    
set pulse rate to 0.1 –0.0が遅くて1.0が一番高速
    
properties
    
–> {class:device, id:”14100000″, brightness:0.1, should pulse:true, pulse rate:0.1, name:”Piyomaru PowerMate”}
  end tell
end tell

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

スクリプト名:PowerMateを強制的に点滅させる
–Griffin TechnologyからPowerMate 3.0Driverをダウンロードする必要アリ

tell application “PowerMate”
  set aPowerMate to device 1 –複数のPowerMateデバイスの接続をサポートしているもよう
  
  
tell aPowerMate
    repeat 10 times
      
      
repeat with i from 1 to 10
        set brightness to (i / 10)
        
delay 0.1
      end repeat
      
      
repeat with i from 10 to 1 by -1
        set brightness to (i / 10)
        
delay 0.1
      end repeat
      
    end repeat
  end tell
  
end tell

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

2013/09/16 AppleScriptObjCで位置情報を取得

AppleScriptObjCでLocationManagerを利用して、現在位置の情報を取得するサンプルです。

あまりよく理解していないのですが、MacScripterの議論を参考に、不必要なコードを除去して最低限の機能だけ利用できればと考えて整理したものです。

こうした位置情報を取得する機能はAppleScript/AppleScriptObjCのプログラムでも、気軽に使いたいところです。

ただ、「気軽に利用できる」のと「気軽に配布できる」の間にはずいぶんと距離があります。利用するだけなら、そうした機能をAppleScriptに提供するソフトウェアが存在していますが……配布するとなると、それを一緒に配布するわけにもいきませんし、その程度の機能で「有償ソフトウェア」といわれても困ります。

位置情報の取得まわりは、かなり高機能なAPIが揃っているのが見て取れるのですが、緯度経度情報から住所情報に変換する「逆住所ジオコーダー」(reverse geocoder)がiOSにしか見当たらないため、直接GoogleのAPIを使うほかないのかと考えていますが……10.9になったらさっくりMac OS Xからも逆住所ジオコーダーを使えそうな気が……。

loc1.png
▲Xcodeプロジェクトをビルドして実行すると、位置情報を使用してよいかダイアログが表示される

loc2.png
▲緯度、経度の情報と誤差情報が表示される

loc3.png
▲「Open In Browser」ボタンをクリックすると、Google Map(日本語版)で取得位置の確認が行える

→ Xcodeプロジェクトのダウンロード(42KB)

AppleScriptObjCファイル名:coreLocationASOCAppDelegate.applescript

– coreLocationASOCAppDelegate.applescript
– coreLocationASOC

– Created by Takaaki Naganoya on 10/09/15.
– Copyright 2010 Takaaki Naganoya. All rights reserved.

–http://macscripter.net/viewtopic.php?id=32763&p=3

script coreLocationASOCAppDelegate
  
  property parent : class “NSObject”
  
  property CLLocation : class “CLLocation”
  
property CLLocationManager : class “CLLocationManager”
  
  property NSString : class “NSString”
  
property nsurl : class “NSURL”
  
property NSDate : class “NSDate”
  
property NSWorkspace : class “NSWorkspace”
  
property NSBundle : class “NSBundle”
  
  property locationManager : missing value
  
  property locationText : missing value
  
property accuracyText : missing value
  
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    set locationManager to CLLocationManager’s alloc()’s init()
    
    locationManager’s setDesiredAccuracy_(current application’s kCLLocationAccuracyHundredMeters)
    
locationManager’s setDelegate_(me)
    
locationManager’s startUpdatingLocation()
    
  end applicationWillFinishLaunching_
  
  
  on locationManager_didFailWithError_(locationManager, myError)
    
    set errorString to NSString’s stringWithFormat_(“Location manager failed with error: %@”, myError’s localizedDescription())
    
webView’s mainFrame()’s loadHTMLString_baseURL_(errorString, missing value)
    
locationText’s setStringValue_(“No Data Available”)
    
accuracyText’s setStringValue_(“”)
    
  end locationManager_didFailWithError_
  
  
  on locationManager_didUpdateToLocation_fromLocation_(locationManager, newLocation, oldLocation)
    
    set latitude to newLocation’s coordinate’s pointValue()’s x
    
set longitude to newLocation’s coordinate’s pointValue()’s y
    
    locationText’s setStringValue_(NSString’s stringWithFormat_(“%@, %@”, latitude, longitude))
    
accuracyText’s setStringValue_(NSString’s stringWithFormat_(“%@”, newLocation’s horizontalAccuracy()))
    
    locationManager’s stopUpdatingLocation()
    
    
  end locationManager_didUpdateToLocation_fromLocation_
  
  
  on clicked_(sender)
    set aTag to tag of sender
    
set aTag to aTag as integer
    
    if aTag = 100 then
      tell current application to quit
    else if aTag = 200 then
      openInDefaultBrowser_(sender)
    end if
    
  end clicked_
  
  
  
  on applicationShouldTerminate_(sender)
    locationManager’s stopUpdatingLocation()
    
return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  
  
  –Webブラウザで現在の緯度、経度情報を元にGoogle Mapを表示
  
on openInDefaultBrowser_(sender) –Connected to a button in IB
    
    set currentLocation to locationManager’s location()
    
    if currentLocation is not missing value then
      set lat to currentLocation’s coordinate’s pointValue()’s x
      
set lon to currentLocation’s coordinate’s pointValue()’s y
      
set latRange to latitudeRangeForLocation_(currentLocation)
      
set lonRange to longitudeRangeForLocation_(currentLocation)
    else
      set lat to 37.76
      
set lon to -122.434
      
set latRange to 0.15
      
set lonRange to 0.15
    end if
    
    set browserURL to nsurl’s URLWithString_(NSString’s stringWithFormat_(“http://maps.google.co.jp/maps?ll=%@,%@&spn=%@,%@”, lat, lon, latRange, lonRange))
    
    NSWorkspace’s sharedWorkspace’s openURL_(browserURL)
    
  end openInDefaultBrowser_
  
  
  
  
  on latitudeRangeForLocation_(aLocation)
    
    set M to 6.367E+6 –approximate average meridional radius of curvature of earth
    
set metersToLatitude to 1.0 / ((3.1416 / 180.0) * M)
    
set accuracyToWindowScale to 2.0
    
    return (aLocation’s horizontalAccuracy()) * metersToLatitude * accuracyToWindowScale
    
  end latitudeRangeForLocation_
  
  on longitudeRangeForLocation_(aLocation)
    
    set latRange to latitudeRangeForLocation_(aLocation)
    
return latRange * (getCos_((aLocation’s coordinate’s pointValue()’s x) * 3.1416 / 180.0))
    
  end longitudeRangeForLocation_
  
  
  on getCos_(x)
    return (1 - x ^ 2 / 2 + x ^ 4 / 24 - x ^ 6 / 720 + x ^ 8 / 40320)
  end getCos_
  
end script

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

2013/09/14 Radikoで選局 v3

SafariでRadiko.jpをオープンして現在の地域で選局可能なラジオ局の一覧を取得し、一覧から選択したあとに、指定したラジオ局をオープンするAppleScriptです。

半年に一度ぐらい、コントロール対策なのか、あまり意味のなさそうなWeb改修が行われ、それに対応したものです。ほかには、番組表のローディング時に行うアニメーション表現が増えたので、時間待ちの値を増やしています。

# サイトの微変更ではなく、Safariからの見え方が変わったということかもしれません。少なくとも、10.8上では従来のプログラムではコントロールできていませんでした

GUI Scripting経由でSafariにアクセスしているので、システム環境設定からあらかじめ「アクセシビリティ」から「補助装置にアクセスできるようにする」にチェックを入れておくか、Script実行時にパスワードを入力すると設定を変更します。

自作のAppleScriptObjCのアプリケーション「radiRec」に組み込んで動作を確認しました。AppleScriptObjCのプロジェクトに入れても問題ありません。

OS X 10.8.5+Safari 6.1、場所は東京都内で動作確認してあります(他のエリアではチェックしていません)。

スクリプト名:Radikoで選局 v3
property waitSec : 10 –Safariのページローディングを待つ時間(秒)

–GUI Scriptingの確認
repeat 3 times
  tell application “System Events”
    set aRes to UI elements enabled
  end tell
  
  
if aRes = false then
    display dialog “GUI Scriptingをオンにしてください。” buttons {“OK”} default button 1
    
tell application “System Events”
      activate
      
set UI elements enabled to true
    end tell
  end if
end repeat
if aRes = false then return

set aList to getRadioStationList() of me
–> {”TBSラジオ”, “文化放送”, “ニッポン放送”, “ラジオNIKKEI第1″, “ラジオNIKKEI第2″, “InterFM”, “TOKYO FM”, “J-WAVE”, “ラジオ日本”, “bayfm78″, “NACK5″, “FMヨコハマ”, “放送大学”}

tell current application
  activate
  
set aRes to choose from list aList
end tell

set aaRes to first item of aRes

selectRadioStation(aaRes) of me –選曲

–SafariでRadikoの選局を行う
on selectRadioStation(aStation)
  activate application “Safari”
  
  
tell application “Safari”
    close every document
    
    
tell document 1
      tell current tab
        open location “http://radiko.jp”
      end tell
    end tell
  end tell
  
  
delay waitSec
  
  
tell application “System Events”
    tell process “Safari”
      tell list 1 of UI element 1 of scroll area 1 of group 1 of group 1 of group 2 of window 1
        set gList to every group
        
        
set uList to {}
        
        
repeat with i in gList
          tell i
            tell group 1 –ここ、1階層増えた
              set a to UI element 1
              
set statName to title of a
              
set the end of uList to statName
              
if statName = aStation then
                
                
click a
                
              end if
            end tell
          end tell
        end repeat
        
      end tell
    end tell
  end tell
  
end selectRadioStation

–SafariでRadikoのラジオ局一覧を取得する
on getRadioStationList()
  activate application “Safari”
  
  
tell application “Safari”
    close every document
    
    
tell document 1
      tell current tab
        open location “http://radiko.jp”
      end tell
    end tell
  end tell
  
  
delay waitSec
  
  
tell application “System Events”
    tell process “Safari”
      tell list 1 of UI element 1 of scroll area 1 of group 1 of group 1 of group 2 of window 1
        set gList to every group
        
        
set uList to {}
        
        
repeat with i in gList
          tell i
            tell group 1 –ここ、1階層増えた
              set a to UI element 1
              
set statName to title of a
              
set the end of uList to statName
            end tell
          end tell
        end repeat
        
      end tell
    end tell
  end tell
  
  
return uList
  
end getRadioStationList

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

2013/09/13 OS X 10.8.5アップデートが登場

おそらく、10.8系の最終アップデートと思われるOS X 10.8.5アップデートがリリースされました。長らく、β版でバグの所在について確認してきましたが……直らないですね。

以前のバージョンで修正済みのバグ

write命令実行時のファイル書き込みテキストエンコーディングが10.8.3で修正された
http://piyocast.com/as/archives/2346

未解決、あるいはAppleが認識していないバグ

バグレポートは書いていますが、いかんせん「数」がそろわないとAppleはアクションを起こさないので、スルーされているようです。前者は、10.9でも直っていません。

Calendar(iCal)からリマインダーのカレンダーが見える上に区別ができない
http://piyocast.com/as/archives/2582

OS X 10.8のdateに強烈なバグ
http://piyocast.com/as/archives/2347

2013/09/10 Window内に縦に配置したNSBoxのサイズと位置を読み取ってサイズ変更

メインウィンドウ内に縦方向に配置した4つのNSBoxのサイズと位置を起動時に取得して、NSSegmentedControlのクリック内容を反映してメインウィンドウを縦方向にアニメーションしつつリサイズするAppleScriptObjCのサンプルです。

boxwin.png

さまざまな機能を提供するパーツをNSBoxでまとめておき、表示範囲をボタンのクリックによって動的に変更するという処理のための実験コードです。

リサイズ後にウィンドウの最小サイズ/最大サイズを設定して、大きさを変更できないようにしたいところです。

→ Xcodeプロジェクトのダウンロード(76KB)

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– boxSizeTest

– Created by Takaaki Naganoya on 2013/09/10.
– Copyright (c) 2013年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
  property aWin : missing value
  
  property box1 : missing value
  
property box2 : missing value
  
property box3 : missing value
  
property box4 : missing value
  
  
  
  property bSizeList : {}
  
property aWinWidth : 0
  
  property origY : 0
  
  on applicationWillFinishLaunching_(aNotification)
    
    getWinBoxInfoOnBoot()
    
  end applicationWillFinishLaunching_
  
  
  
  –起動時に(起動が完了する前に)ウィンドウのサイズ、位置、内部のNSBoxの情報などを取得して記憶しておく
  
on getWinBoxInfoOnBoot()
    
    set b0Size to aWin’s frame()
    
set b0Size to b0Size as record
    
set b0X1 to x of origin of b0Size
    
set b0Y1 to y of origin of b0Size
    
set b0X2 to width of |size| of b0Size
    
set b0Y2 to height of |size| of b0Size
    
    set my origY to b0Y1 + b0Y2
    
————————————————
    
set b1Size to box1’s frame()
    
set b1Size to b1Size as record
    
    set b1X1 to x of origin of b1Size
    
set b1Y1 to y of origin of b1Size
    
    set b1X2 to width of |size| of b1Size
    
set b1Y2 to height of |size| of b1Size
    
    set b1Y3 to (my origY) - b1Y1
    
————————————————
    
set b2Size to box2’s frame()
    
set b2Size to b2Size as record
    
    set b2X1 to x of origin of b2Size
    
set b2Y1 to y of origin of b2Size
    
    set b2X2 to width of |size| of b2Size
    
set b2Y2 to height of |size| of b2Size
    
    set b2Y3 to (my origY) - b2Y1
    
————————————————
    
set b3Size to box3’s frame()
    
set b3Size to b3Size as record
    
    set b3X1 to x of origin of b3Size
    
set b3Y1 to y of origin of b3Size
    
    set b3X2 to width of |size| of b3Size
    
set b3Y2 to height of |size| of b3Size
    
    set b3Y3 to (my origY) - b3Y1
    
————————————————
    
set b4Size to box4’s frame()
    
set b4Size to b4Size as record
    
    set b4X1 to x of origin of b4Size
    
set b4Y1 to y of origin of b4Size
    
    set b4X2 to width of |size| of b4Size
    
set b4Y2 to height of |size| of b4Size
    
    set b4Y3 to (my origY) - b4Y1
    
————————————————
    
set my bSizeList to {b1Y3, b2Y3, b3Y3, b4Y3}
    
set my aWinWidth to b0X1
    
  end getWinBoxInfoOnBoot
  
  
  on applicationShouldTerminate_(sender)
    return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  
  
  on clicked_(sender)
    
    –NSSegmentedControlの選択中のSegmentを求める
    
set aTag to (sender’s selectedSegment()) + 1
    
    
    set b0Size to aWin’s frame()
    
set b0Size to b0Size as record
    
    set b0X1 to x of origin of b0Size
    
set b0Y1 to y of origin of b0Size
    
    set b0X2 to width of |size| of b0Size
    
set b0Y2 to height of |size| of b0Size
    
    set curY to (contents of item aTag of my bSizeList) + 5 –”+5″は単に見た目を整えるための調整値
    
    set aSize to {{b0X1, b0Y1 + b0Y2 - curY}, {b0X2, curY}}
    
    aWin’s setFrame_display_animate_(aSize, true, true)
    
    
  end clicked_
  
end script

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

2013/09/09 AppleScriptObjCでNSBoxのタイトル文字の色を変更する

AppleScriptObjCで、NSBoxのタイトル文字の色を変更するサンプルです。

海外のBlogやMailing Listの過去ログを見たかぎりでは、「できない」という投稿が多かったのですが………単に色を指定しただけでは色は変わらず、タイトル文字の変更を行うと「色」+「タイトル」が変わるようです。

またひとつ、つまらないテクニックを見つけてしまいました……。

box1.png

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– boxTest

– Created by Takaaki Naganoya on 2013/09/09.
– Copyright (c) 2013年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
property aBox : missing value
  
  on applicationWillFinishLaunching_(aNotification)
    
    tell current application’s NSColorList to set AppleColors to colorListNamed_(“Apple”)
    
set redColor to AppleColors’s colorWithKey_(“Red”)
    
aBox’s setTitle_(“ぴよぴよ〜”)
    
aBox’s titleCell’s setTextColor_(redColor)
    
  end applicationWillFinishLaunching_
  
  on applicationShouldTerminate_(sender)
    – Insert code here to do any housekeeping before your application quits
    
return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
end script

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

2013/09/09 リスト中から重複項目をリストアップする v3

2Dのリスト中における重複項目をリストアップするAppleScriptです。前回掲載したバージョンには、重複項目が複数(3つ以上)存在した場合に、重複項目リストに同じ項目が複数入るというバグがあり、これを修正しました。

# コメント欄でのご指摘、ありがとうございます>edama2さん

スクリプト名:リスト中から重複項目をリストアップする v3
set aList to {{2014, 1, 1, 4}, {2014, 2, 11, 3}, {2014, 4, 29, 3}, {2014, 5, 3, 7}, {2014, 5, 5, 2}, {2014, 5, 4, 1}, {2014, 5, 5, 2}, {2014, 11, 3, 2}, {2014, 11, 24, 2}, {2014, 11, 23, 1}, {2014, 12, 23, 3}, {2014, 1, 13, 2}, {2014, 7, 21, 2}, {2014, 9, 15, 2}, {2014, 10, 13, 2}, {2014, 3, 21, 6}, {2014, 9, 23, 3}, {2014, 5, 5, 2}}

set aRes to detectDuplicates2(aList) of me
–> {{2014, 5, 5, 2}}

–リスト中から重複項目をリストアップする
on detectDuplicates2(aList)
  
  
set aCount to length of aList
  
  
set dList to {}
  
  
repeat aCount times
    set anItem to contents of (first item of aList)
    
set aList to rest of aList
    
    
if {anItem} is in aList then
      if {anItem} is not in dList then –ここを追加した (v3)
        set the end of dList to anItem
      end if
    end if
    
  end repeat
  
  
return dList
  
end detectDuplicates2

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

2013/09/08 リスト中から重複項目をリストアップする v2

2Dのリスト中における重複項目をリストアップするAppleScriptです。

1Dのリスト中における重複項目の検出ルーチンを2Dのリストにそのまま使ったら、うまく動きませんでした。1箇所直しただけですが、これで2Dリストに使えます。

スクリプト名:リスト中から重複項目をリストアップする v2
set aList to {{2014, 1, 1, 4}, {2014, 2, 11, 3}, {2014, 4, 29, 3}, {2014, 5, 3, 7}, {2014, 5, 5, 2}, {2014, 5, 4, 1}, {2014, 5, 5, 2}, {2014, 11, 3, 2}, {2014, 11, 24, 2}, {2014, 11, 23, 1}, {2014, 12, 23, 3}, {2014, 1, 13, 2}, {2014, 7, 21, 2}, {2014, 9, 15, 2}, {2014, 10, 13, 2}, {2014, 3, 21, 6}, {2014, 9, 23, 3}}

set aRes to detectDuplicates2(aList) of me
–> {{2014, 5, 5, 2}}

–リスト中から重複項目をリストアップする
on detectDuplicates2(aList)
  
  
set aCount to length of aList
  
  
set dList to {}
  
  
repeat aCount times
    set anItem to contents of (first item of aList)
    
set aList to rest of aList
    
    
if {anItem} is in aList then
      set the end of dList to anItem
    end if
    
  end repeat
  
  
return dList
  
end detectDuplicates2

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

2013/09/08 IRC Client「Colloguy」をAppleScriptでコントロール(3)

IRCクライアント「Colloguy」をAppleScriptからコントロールするシリーズの続きです。

サーバーに接続して、チャットルームにログイン、退出、チャットルーム中のユーザー情報の取得などをAppleScriptから行えるようになりました。

ログイン中のチャットルームに発言する処理を試してみましょう。

col9.png

col10.png

スクリプト名:Colloguyでメッセージ送信テスト
set sendM to ” testing “

tell application “Colloquy”
  tell front window
    tell active panel
      repeat 10 times
        set sendM to “(” & sendM & “)”
        
send message sendM
      end repeat
    end tell
  end tell
end tell

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

しかし、いろいろ試していますが、チャットルーム中の会話内容(message)を取得できていません。

Colloguyの「Chat Plug-in Suite」を見てみると、いろいろできそうではありますが、もうちょっと試行錯誤が必要なようです。

collo11.png

2013/09/08 IRC Client「Colloguy」をAppleScriptでコントロール(2)

IRCクライアント「Colloguy」をAppleScriptからコントロールするシリーズの続きです。

なんでもAppleScriptからできそうな雰囲気がありつつ、けっこうサポート機能がまばらなColloguyのコントロールをためしてみます。

初期設定、とくにサーバー登録をGUI側から手で行っておく必要があるので、済ませておきます。

col4.png

とりあえず、この「irc.livedoor.ne.jp」のサーバーにAppleScriptから接続してみましょう。そのためには、「irc.livedoor.ne.jp」のサーバーを登録してあるconnectionのIDを調べる必要があります。

簡単に「connect “irc.livedoor.ne.jp”」と実行すればつながるように作っておけばよいものを、アプリに登録してあるconnectをすべて調べて、その中に指定名称(server address)が合致するものがあるかどうかをすべて調査する必要があります。

スクリプト名:ColloquyでIRCの指定サーバーに接続
set cID to retIRCconnectionByName(“irc.livedoor.ne.jp”) of me
if cID = false then return

tell application “Colloquy”
  connect connection cID
end tell

–指定サーバーのConnection IDを取得する
on retIRCconnectionByName(aName)
  tell application “Colloquy”
    set cCount to count every connection
    
    
repeat with i from 1 to cCount
      tell connection i
        set aP to properties
        
set aSt to (server address of aP) as string
        
if aSt = aName then
          return i
        end if
      end tell
    end repeat
    
    
return false
    
  end tell
end retIRCconnectionByName

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

これを実行すると、

col5.png

画面上でも、コネクションが成立したことが確認できます。

次に、チャットルームへの参加。なぜか「#test」への参加が承認制(先にチャットルームを作成した人がそのように宣言したのだろうか)になっていたので、乱数で名前を指定してたぶんぶつからないはずのチャットルームを作って参加してみましょう。

col6.png

スクリプト名:Colloguyで指定のチャットルームに入室する
set cList to retActiveIRCconnection() of me
set cID to contents of first item of cList

set randDnum to random number from 10000 to 99999
set rStr to randDnum as string
set chatRoom to “#test” & rStr

tell application “Colloquy”
  try
    set aRes to join chat room chatRoom on connection cID
  end try
end tell

–activeなIRC connectionのIDを返す。なければヌルのリストが返る
on retActiveIRCconnection()
  tell application “Colloquy”
    set cCount to count every connection
    
set cList to {}
    
    
repeat with i from 1 to cCount
      tell connection i
        set aP to properties
        
set aSt to (status of aP) as string
        
if aSt = “connected” then
          set the end of cList to i
        end if
      end tell
    end repeat
    
    
return cList
    
  end tell
end retActiveIRCconnection

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

この状態で、接続したチャットルームから退室するAppleScriptのコマンドを探してみたのですが…………そういう命令はありません。GUI上からはできるのですが、AppleScriptにはそういう機能は解放されていません。

となると、特定のチャットルームから退出するのではなく、サーバーとのコネクションそのものを切断するしかありません。

col7.png

スクリプト名:Colloquyですべてのサーバーとのconnectionを切断する
tell application “Colloquy”
  disconnect every connection
end tell

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

コネクションを切断したままでは、チャットウィンドウが閉じないので明示的に命令してあげる必要があります。

スクリプト名:Colloguyですべてのウィンドウを閉じる
tell application “Colloquy”
  close every window
end tell

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

チャットルームの詳細な情報収集は行えます。

スクリプト名:ColloguyでIRCチャットルームのプロパティを取得する
tell application “Colloquy”
  tell connection 1
    tell chat room “#test”
      
      
properties
      
–> {URL:”irc://irc.livedoor.ne.jp/%23test”, encoding:UTF8, display name:”test”, date parted:missing value, date joined:date “2013年9月3日火曜日 19:12:57″, banned users:{}, id:”#test”, joined:true, attributes:{}, name:”#test”, class:chat room}
      
    end tell
  end tell
end tell

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

さらに、指定チャットルームに参加しているユーザーのプロパティを取得することも可能です。

col8.png

指定チャットサーバーのうち、ユーザーが多い方のチャットルーム情報を調べておいて(このあたり、AppleScriptからできないと意味なさそうですが)、プログラムで指定して自動ログインしてユーザー情報をすべて取得してみます。

スクリプト名:Colloguyでconnection IDとチャットルーム名で指定したチャットルームのユーザー情報をすべて収集する
set targRoom to “#そして輝くフリッグソウッ”

set cList to retActiveIRCconnection() of me
if cList = {} or cList = false then
  display dialog “No Connection”
  
return
end if
set cID to contents of first item of cList

tell application “Colloquy”
  try
    set aRes to join chat room targRoom on connection cID
  end try
end tell

delay 3

set aList to getDataListByConnectIDandChatRoom(cID, targRoom) of me
return aList

–connection IDとチャットルーム名で指定したチャットルームのユーザー情報をすべて収集する
on getDataListByConnectIDandChatRoom(cID, chatRoomName)
  
  
tell application “Colloquy”
    tell connection cID
      tell chat room chatRoomName
        set cList to every chat user
        
set resList to {}
        
        
repeat with i in cList
          set j to contents of i
          
          
tell j
            try
              set aName to name
              
set aName to aName as string
            on error
              set aName to “”
            end try
            
–> “maro”
            
            
try
              set rName to real name
              
set rName to rName as string
            on error
              set rName to “”
            end try
            
–> “Takaaki Naganoya”
            
            
try
              set dName to display name
              
set dName to dName as string
            on error
              set dName to “”
            end try
            
–> “maro”
            
            
try
              set uName to user name
              
set uName to uName as string
            on error
              set uName to “”
            end try
            
–> “maro”
            
            
try
              set anAddress to address
              
set anAddress to anAddress as string
            on error
              set anAddress to “”
            end try
            
–> “KDxxxxxxxxxxxxxxxx.ppp-bb.dion.ne.jp”
            
            
try
              set sAddress to server address
              
set sAddress to sAddress as string
            on error
              set sAddress to “”
            end try
            
–> “irc.livedoor.ne.jp”
            
            
try
              set iTime to idle time
            on error
              set iTime to 0
            end try
            
–> 232.0
            
            
try
              set uDate to date updated
              
set uDate to uDate as string
            on error
              set uDate to “”
            end try
            
–> date “2013年9月3日火曜日 17:33:42″
            
            
try
              set cDate to date connected
              
set cDate to cDate as string
            on error
              set cDate to “”
            end try
            
–> date “2013年9月3日火曜日 19:08:17″
            
            
try
              set dDate to date disconnected
              
set dDate to dDate as string
            on error
              set dDate to “”
            end try
            
            
try
              set aStatus to status
              
set aStatus to aStatus as string
            on error
              set aStatus to “”
            end try
            
–> available
            
            
try
              set aMes to away message
              
set aMes to aMes as string
            on error
              set aMes to “”
            end try
            
          end tell
          
          
set the end of resList to {aName, rName, dName, uName, anAddress, sAddress, iTime, uDate, cDate, dDate, aStatus, aMes}
          
        end repeat
      end tell
    end tell
  end tell
  
  
return resList
  
end getDataListByConnectIDandChatRoom

–activeなIRC connectionのIDを返す。なければヌルのリストが返る
on retActiveIRCconnection()
  tell application “Colloquy”
    
    
set cCount to count every connection
    
set cList to {}
    
    
repeat with i from 1 to cCount
      tell connection i
        set aP to properties
        
set aSt to (status of aP) as string
        
if aSt = “connected” then
          set the end of cList to i
        end if
      end tell
    end repeat
    
    
return cList
    
  end tell
end retActiveIRCconnection

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

ユーザー情報の属性値のうち、取得するとエラーになるものがいくつかあるので、慎重にエラートラップを仕掛けつつひとつずつ属性値を取得する必要があります(ちょっと前までのiTunesみたいだ、、、)。

2013/09/08 IRC Client「Colloguy」をAppleScriptでコントロール(1)

マンガ「王様達のヴァイキング」(さだやす著)を読んで、「そういえば、すごい昔にIRCってあったな。まだ残ってたのか」と思い出し、IRCをAppleScriptから攻めてみることにしました(大人の自由研究)。

IRCはインターネット上で利用できる文字ベースのチャットソフトおよびその仕組みのことで、1988年以来25年ぐらいの歴史があります。90年代のインターネットブームの際にちょこっと使った覚えがありますが、もうちょっとカジュアルな「ICQ」にユーザーが流れたりして(現在ではTwitterとか)あまり「旬」のアプリではない印象があります。世間的な認知度もそんなところでしょう。

IRCのインフラ自体は、現在も維持されているため、IRC clientのアプリを用意するなり、Terminal経由で接続すれば現在でも使えます。

Mac AppStore上で「IRC」をキーワードに検索すると、無料/有料のアプリが9件ほど見つかります。これらのうち、どれにも「AppleScript対応」の表記はなされていないので、昔から存在しているAppleScript対応のIRCクライアント「Colloguy」を久しぶりにダウンロード。

col1.png

ColloguyはIntel 64bit対応でOS X 10.8上でも問題なく動作します。昔から、ColloguyがAppleScript対応していることは知っていたのですが、オンラインドキュメントが絶望的によくなくて、読めば読むほど分らなくなる仕組みになっていました。

結論からいえば、ColloguyのScriptingにはかなり「慣れ」が必要です。慣れというよりも、Colloguyの「挙動」を理解しないとダメです。

まず、Colloguyは何でもAppleScriptからできるような顔つきをしていながら、サポート機能はけっこうまばらです。オープンソースで、悪く言えば「趣味で」作られているものなので、派手な機能はサポートしていますが地道な機能のサポートがよくないです。

端的にいえば、アカウントのセットアップなどへのサポートはないです。アプリケーションの初期設定(IRCサーバーの登録)などはユーザーがGUI側から済ませておく必要があります。

col3.png

また、できてよさそうなチャットルーム一覧の取得はサポートしていません。記述としては書けるのですが、値が返ってきません。

スクリプト名:Colloquyですべてのチャットルームをリストアップ(未遂)
tell application “Colloquy”
  tell connection 1
    set cList to every chat room
  end tell
end tell

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

また、特定のサーバーにアクセスしているユーザーの一覧とその情報を取得するようなAppleScriptを書いてみたものの、値が返ってくるケースと返ってこないケースがあり、再現性に乏しいため試行錯誤中です。

スクリプト名:ColloguyでactiveなIRC connectionのIDを返す
set cList to retActiveIRCconnection() of me
–> {1}

–activeなIRC connectionのIDを返す。なければヌルのリストが返る
on retActiveIRCconnection()
  tell application “Colloquy”
    set cCount to count every connection
    
set cList to {}
    
    
repeat with i from 1 to cCount
      tell connection i
        set aP to properties
        
set aSt to (status of aP) as string
        
if aSt = “connected” or aSt = “connecting” then
          set the end of cList to i
        end if
      end tell
    end repeat
    
    
return cList
    
  end tell
end retActiveIRCconnection

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

あと、IRCサーバーの運用ポリシーがコロコロ変わるのか、数日前まで自由にアクセスできていたチャットルーム「#test」が招待制に変わったりといまひとつ分りづらいところがあります。

col2.png

スクリプト名:Colloguyで指定のチャットルームに入室する
set cList to retActiveIRCconnection() of me
set cID to contents of first item of cList

tell application “Colloquy”
  try
    set aRes to join chat room “#test” on connection cID
  end try
end tell

–activeなIRC connectionのIDを返す。なければヌルのリストが返る
on retActiveIRCconnection()
  tell application “Colloquy”
    set cCount to count every connection
    
set cList to {}
    
    
repeat with i from 1 to cCount
      tell connection i
        set aP to properties
        
set aSt to (status of aP) as string
        
if aSt = “connected” then
          set the end of cList to i
        end if
      end tell
    end repeat
    
    
return cList
    
  end tell
end retActiveIRCconnection

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

2013/09/08 AppleScriptObjCで国民の祝日を計算

2013/09/06 ASOCでカレンダー作成・表示テスト

AppleScriptで作成したさまざまな部品を組み合わせて、AppleScriptObjCでカレンダー表示を行ってみました。

単に、NSMatrixの中にNSButtonを作っておいて、リストのカレンダーを順次流し込んでいます。

calt1.png
▲サンプルの画面

calt3.png
▲後日、Xcode上でデザインをブラッシュアップしたもの(作業途上)

出来上がりもたいしたことはなく、記述量も大したことはありませんが、割とdateの扱いで苦労しています。

ASOCでは、dateオブジェクトの扱いがややめんどうで、current applicationへのtellブロック内でしか正常に機能しませんし、ハンドラ間でdateオブジェクトの受け渡しを行うのはエラーの元になります。

そんなわけで、dateオブジェクトを裸のままで扱わず、局所的にdateオブジェクトを生成しては必要な情報を取り出すという、かなりめんどうな取扱いを行っています。

かといって、NSDateやNSCalendarを使うのも……たった曜日の情報を欲しいだけなのにどれだけ記述させたら気がすむんだと呆れるほどのプログラムになってしまうので、見送りました。いいフレームワークがあれば使わないでもないですが、OSバージョンが上がるたびにメンテナンスする必要があることを考えると、ASのdateオブジェクトを使ったほうが、まだ手軽です。

→ Xcodeプロジェクトのダウンロード(82KB)

2013/09/04 指定月のカレンダーを1D List(7 days x 6 weeks) で返す

指定月のカレンダーを1次元配列のリスト型変数に文字で格納するAppleScriptです。

カレンダーは7曜日×最大で6週になります(土曜日から始まる31日の月とか)ので、7×6=42の要素からなる1D Listを作成しています。

cal10.png

AppleScript名:指定月のカレンダーを1D List(7 days x 6 weeks) で返す
set tYear to 2013
set tMonth to 9

set aCalList to retListCalendar(tYear, tMonth) of me
–> {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "", "", "", "", "", "", "", "", "", "", "", ""}

–指定月のカレンダーを1D List(7 days x 6 weeks) で返す
on retListCalendar(tYear, tMonth)
  
  
set mLen to getMlenInternational(tYear, tMonth) of me
  
set aList to {}
  
  
set fDat to retDateOwithParam(tYear, tMonth, 1, 0, 0, 0) of me
  
tell current application
    set aOffset to (weekday of fDat) as number
  end tell
  
  
–header gap
  
repeat (aOffset - 1) times
    set the end of aList to ""
  end repeat
  
  
–calendar body
  
repeat with i from 1 to mLen
    set the end of aList to (i as string)
  end repeat
  
  
–footer gap
  
repeat (42 - aOffset - mLen + 1) times
    set the end of aList to ""
  end repeat
  
  
return aList
  
end retListCalendar

on getMlenInternational(aYear, aMonth)
  
  
set sDat to retDateOwithParam(aYear, aMonth, 1, 0, 0, 0) of me
  
  
if aMonth is not equal to 12 then
    set eDat to retDateOwithParam(aYear, aMonth + 1, 1, 0, 0, 0) of me
  else
    set eDat to retDateOwithParam(aYear + 1, 1, 1, 0, 0, 0) of me –2015/2/1改修
  end if
  
  
set eDat to eDat - 1
  
set mLen to day of eDat
  
  
return mLen
  
end getMlenInternational

–国際化対応 パラメータによるdateオブジェクト作成ルーチン
on retDateOwithParam(yearNum, monthNum, dateNum, hourNum, minuteNum, secondNum)
  tell current application
    set aDateO to current date
    
    
set year of aDateO to yearNum
    
set month of aDateO to monthNum
    
set day of aDateO to dateNum
    
set hours of aDateO to hourNum
    
set minutes of aDateO to minuteNum
    
set seconds of aDateO to secondNum
    
    
return aDateO
  end tell
end retDateOwithParam

★Click Here to Open This Script 

2013/09/04 国際化対応mLen

指定の月の長さ(日数)を求めるmLenの、国際化対応バージョンです。

年、月を指定すると、該当月の日数を返します。

→ 本ルーチンにはバグが発見されたため、v2を使ってください(2015/2/1)。

スクリプト名:国際化対応mLen
set mLen to getMlenInternational(2013, 9) of me
–> 30

on getMlenInternational(aYear, aMonth)
  
  
set sDat to retDateOwithParam(aYear, aMonth, 1, 0, 0, 0) of me
  
  
if aMonth is not equal to 12 then
    set eDat to retDateOwithParam(aYear, aMonth + 1, 1, 0, 0, 0) of me
  else
    set eDat to retDateOwithParam(aYear, 1, 1, 0, 0, 0) of me
  end if
  
  
set eDat to eDat - 1
  
set mLen to day of eDat
  
  
return mLen
  
end getMlenInternational

–国際化対応 パラメータによるdateオブジェクト作成ルーチン
on retDateOwithParam(yearNum, monthNum, dateNum, hourNum, minuteNum, secondNum)
  set aDateO to current date
  
  
set year of aDateO to yearNum
  
set month of aDateO to monthNum
  
set day of aDateO to dateNum
  
set hours of aDateO to hourNum
  
set minutes of aDateO to minuteNum
  
set seconds of aDateO to secondNum
  
  
return aDateO
  
end retDateOwithParam

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

2013/09/04 JavaScript OSAの終結を2013.6.22に発表

過去のMailing Listのアーカイブを探してみたところ、LateNight SoftwareのMark Alldritが去る2013年6月22日にJavaScript OSAのサポート終了を明言していたことが判明しました。

jsosa1.png

Mac OS Xが採用しているアプリケーション自動化のための機構「Open Scripting Architecture(以下、OSA)」では、AppleScript以外のOSA言語が利用できるようになっており、過去にいくつものOSA言語「Ruby OSA」「Shell OSA」「Tcl/tk OSA」「Perl OSA」などが存在していたことを確認しています。JavaScript OSAはそれらの中でも長年に渡って提供されてきたサードパーティOSA言語の代表格。

そんなJavaScript OSAサポート終了の直接の理由が、これに先立つ2009年10月16日、同社の看板商品「Script Debugger」に関するML「sd-talk」において説明されていました。

This is a 32-bit vs 64-bit issue. The same problem affects all of my
Scripting Additions as well (http://www.latenightsw.com/blog/?p=188).
The workaround is to make the Script Editor and your saved applets/
droplets run as 32-bit processes.

と答えていたように、32ビットから64ビットの移行が問題になったものと見られます。OS X 10.7以降では使用できなくなり、同社のWebサイト上からも削除されたことを確認しています。

この、64ビット移行を断念した理由については、

Sadly, JavaScript OSA is no longer supported. I had such high hopes for it, but it was not to be.

JavaScript OSAが同社のビジネスをすすめる手助けになっていなかった(利用者が多くなかった)ことが伺われます。JavaScript OSAをダウンロードして、試してみたけど最新のOSで動かないのはなぜ? と、質問が来て仕事のさまたげになっていたことも伺われます。

AppleScript以外のOSA言語でアプリケーションのコントロールを行おうとしても、AppleScriptよりも圧倒的に利用者が少なく、ノウハウの蓄積や情報交換が進んでいないため、処理系だけ提供されても実用性がなかったことでしょう(自分自身、そう感じていました)。

ほかにも、ruby-appscriptなどの開発を着手していた「appscript」チームが、OS X 10.7でCarbon AppleEvent ManagerがDeprecated扱いになったことにより開発を中止

同じころ、各種OSA言語処理コンポーネントを開発していたPhilip Akerも公開を中止しています(彼から直接、β版の各種OSA言語コンポーネントの提供を受けて、日本語環境下でのテストもしていたのに残念です)。

現在知り得るかぎり、使用可能なOSAコンポーネントはApple純正のAppleScript OSAと、LateNight SoftwareのScript Debugger 5 OSAの2つだけとなりました。

jsosa2.png

jsosa3.png

これらの動きは、Appleが進めるCarbonベースAPIのCocoa化(および64bit化)の中で起きたもので、Carbonベースで作られたものは大規模改修(それほどでもない気が、、、)が必要になり、アップデートが停まるものが見られます。最近目にしたものでは、URL Access Scriptingがそれに該当します(そんなに難しい機能には見えないのですが)。

ほかにも、Carbonベースで書かれたモジュールについては、バグが存在していても修正される見込みはありません。XML-RPCの機能にバグが見られたときも、それがCarbonベースであることから修正を拒否されました。

ただ、Carbonベースで修正されなくなったりなくなったりする機能も、ユーザー自身がAppleScriptObjCで記述することで、機能を維持できる可能性があります。

そしてどうやら、AppleScriptObjCというのは来るべき「Carbon-FreeなOS Xの世界」に先立ってOS内部の機能の多くをScripterに使わせるために作られた仕組みであるように思えるのです(ただ、iTunesなどでCarbonに深く依存しているうえに、他のプロ用アプリも同様なので、完全にCarbon-FreeなOSというものを実現できるとは思いません)。

サードパーティ製のOSA言語の提供については、実際にScript Debugger 5 OSA componentが存在しているわけで、開発すること自体は不可能ではないと思われます。その一方で、フリーで配布できるような手軽なものでもないことは想像に難くありません。

ただ……個人的には、JavaScript OSAがなくても困らないのですが、、、

2013/09/03 AppleScriptをバックグラウンドで実行

AppleScriptをバックグラウンドで実行させる方法はいくつかありますが、一番簡単なものを紹介しておきます。

とりあえず、日本語合成音声の「Kyoko」でカウントダウンさせるという、実に実用性も何もないScriptを用意してみました。

スクリプト名:sayLoop
repeat with i from 10 to 0 by -1
  say (i as string) using “Kyoko”
end repeat

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

AppleScriptでやるのはここまでです。あとは、このScriptをアプリケーション形式で保存。

アプリケーション形式で保存したということは、これが「アプリケーションバンドル」として保存されたことを意味します。

「アプリケーションバンドル」は、Finder上でアイコンを選択してコンテクストメニューから「パッケージの内容を表示」させると、その内部のファイルにアクセスできるようになります。

pack1.png

pack2.png

Mac OS Xアプリケーションではひとしく、その実行パラメータなどを記述してある「Info.plist」ファイルが存在することが見てとれます。これを、ダブルクリックしてオープン。

Xcodeがインストールしてあれば、XcodeのplistエディタによってInfo.plistがオープンされます。インストールしていない場合にはテキストエディタでオープンすることになります。

以下の画面はXcode 4.6のものですが、Info.plistに新たなエントリを作るべく「+」をクリック。
「Application is Background only」(LSBackGroundOnly)の属性を作成し、その値に「YES」を指定します。

pack3.png

普通のテキストエディタ(TextWrangler)でオープンすると以下のようになっています。

pack4.png

これで、Info.plistを保存してXcodeなりテキストエディタを終了して、sayLoopアプリをダブルクリックすると、Dockにも表示されずバックグラウンドで実行されることが確認できます。

2013/09/03 Menu ExtraをAppleScriptから操作

Menu ExtraをAppleScript(GUI Scripting)から操作する方法についてのまとめです。

menu1.png

Menu ExtraはSystemUIServerの管轄下にある

Menu Extraは、普通にGUI Scriptingで手の出せない場所にあります。だいたい、どのアプリケーションの管轄になっているのかが非常に分りにくいです。

ただし、現在(OS X 10.8)ではSystemUIServerの管轄下にあることが判明しています。以前に、「文字入力モードを制御」というサンプルを掲載しており、その操作方法を紹介しています。

Apple純正のMenu Extra以外は手が出ない

実際に、SystemUIServerに各Menu Extraの情報を問い合わせると……

スクリプト名:Menu Extraの情報を取得する
activate application “SystemUIServer”
tell application “System Events”
  tell process “SystemUIServer”
    tell menu bar 1
      set aList to properties of every menu bar item
    end tell
  end tell
end tell
–> {{description:”time machine”, orientation:missing value, position:{1632, 0}, class:menu bar item, role description:”menu extra”, accessibility description:”time machine”, focused:missing value, title:missing value, size:{30, 22}, value:missing value, help:missing value, enabled:true, maximum value:missing value, role:”AXMenuBarItem”, entire contents:{}, subrole:”AXMenuExtra”, selected:false, name:missing value, minimum value:missing value}, {description:”Messages”, orientation:missing value, position:{1662, 0}, class:menu bar item, role description:”menu extra”, accessibility description:”Messages”, focused:missing value, title:missing value, size:{32, 22}, value:missing value, help:missing value, enabled:true, maximum value:missing value, role:”AXMenuBarItem”, entire contents:{}, subrole:”AXMenuExtra”, selected:false, name:missing value, minimum value:missing value}, {description:”user”, orientation:missing value, position:{1694, 0}, class:menu bar item, role description:”menu extra”, accessibility description:”user”, focused:missing value, title:missing value, size:{30, 22}, value:missing value, help:missing value, enabled:true, maximum value:missing value, role:”AXMenuBarItem”, entire contents:{}, subrole:”AXMenuExtra”, selected:false, name:missing value, minimum value:missing value}, {description:”bluetooth”, orientation:missing value, position:{1724, 0}, class:menu bar item, role description:”menu extra”, accessibility description:”bluetooth”, focused:missing value, title:missing value, size:{30, 22}, value:missing value, help:missing value, enabled:true, maximum value:missing value, role:”AXMenuBarItem”, entire contents:{}, subrole:”AXMenuExtra”, selected:false, name:missing value, minimum value:missing value}, {description:”Wi-Fi、Extreme net_5G で 4 本のうち 4 本の信号。”, orientation:missing value, position:{1754, 0}, class:menu bar item, role description:”menu extra”, accessibility description:”Wi-Fi、Extreme net_5G で 4 本のうち 4 本の信号。”, focused:missing value, title:missing value, size:{30, 22}, value:missing value, help:missing value, enabled:true, maximum value:missing value, role:”AXMenuBarItem”, entire contents:{}, subrole:”AXMenuExtra”, selected:false, name:missing value, minimum value:missing value}, {description:”AppleScript”, orientation:missing value, position:{1784, 0}, class:menu bar item, role description:”menu extra”, accessibility description:”AppleScript”, focused:missing value, title:missing value, size:{30, 22}, value:missing value, help:missing value, enabled:true, maximum value:missing value, role:”AXMenuBarItem”, entire contents:{}, subrole:”AXMenuExtra”, selected:false, name:missing value, minimum value:missing value}, {description:”バッテリー: 86% 充電済み “, orientation:missing value, position:{1814, 0}, class:menu bar item, role description:”menu extra”, accessibility description:”バッテリー: 86% 充電済み “, focused:missing value, title:missing value, size:{62, 22}, value:missing value, help:missing value, enabled:true, maximum value:missing value, role:”AXMenuBarItem”, entire contents:{}, subrole:”AXMenuExtra”, selected:false, name:missing value, minimum value:missing value}, {description:”clock”, orientation:missing value, position:{1876, 0}, class:menu bar item, role description:”menu extra”, accessibility description:”clock”, focused:missing value, title:missing value, size:{30, 22}, value:”2013年9月3日 11:23″, help:missing value, enabled:true, maximum value:missing value, role:”AXMenuBarItem”, entire contents:{}, subrole:”AXMenuExtra”, selected:false, name:missing value, minimum value:missing value}, {description:”システムサウンド音量”, orientation:missing value, position:{1906, 0}, class:menu bar item, role description:”menu extra”, accessibility description:”システムサウンド音量”, focused:missing value, title:missing value, size:{30, 22}, value:missing value, help:missing value, enabled:true, maximum value:missing value, role:”AXMenuBarItem”, entire contents:{}, subrole:”AXMenuExtra”, selected:false, name:missing value, minimum value:missing value}, {description:”text input”, orientation:missing value, position:{1936, 0}, class:menu bar item, role description:”menu extra”, accessibility description:”text input”, focused:missing value, title:missing value, size:{30, 22}, value:”英字”, help:missing value, enabled:true, maximum value:missing value, role:”AXMenuBarItem”, entire contents:{}, subrole:”AXMenuExtra”, selected:false, name:missing value, minimum value:missing value}}

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

Apple純正のMenu Extraの情報しか返ってきません。

他のMenu Extraは各アプリケーションに直接問い合わせ

たとえば、Apple純正以外のMenu Extraは、バックグラウンド起動している(およびDockに非表示の)アプリケーションがメニューに表示させているものです。

たとえば、「AirServer」(これ自体はScriptableですが)のMenu Extraおよびそのメニュー内容を表示させるとこんな感じです。

menu2.png

これらのメニューを操作するためには、「AirServer」のプロセスに対してGUI Scripting経由でコントロールを行うことが必要になります。

ただ……実際にいろいろ試してみたのですが、これら(Apple非純正の)「Menu Extraっぽくメニューを表示するアプリケーション」の作り方(作られ方)がまちまちで、たとえば実際には表示されないWindowメニューの残骸が残っているものとか、オブジェクト階層を無視して強制的にメニューを表示させているものまで、さまざまです。

直接操作を行えたとしても、結果が(該当するMenu Extraのアイコンをクリックしないと)表示されないとか、かなり挙動が独特です。値は取得できるケースが多いのですが、クリック操作はなかなか難しいものがあります。

このような、Menu Extraを直接操作するという「野蛮な」処理は実際にはあまり行わない種類のものですが、もし行う必要が発生した場合に備えて、さらなる情報収集を行っておくべきでしょう。

2013/09/02 Transmitの接続状態をチェック

Transmitで何がしかのサーバーに接続している状態をチェックするAppleScriptです。

TransmitでFTP/SFTPなどのサーバーに接続している状態を確認します。接続できていればtrueを、接続していない場合にはfalseを返します。

スクリプト名:Transmitの接続状態をチェック
set aRes to chkConnection("www.piyocast.com", "/piyocast.com/public_html/as") of me
–> true

–Transmitの接続状態をチェック
on chkConnection(chkAddress, chkPath)
  
  
tell application "Transmit"
    set suppress errors to true –エラー時にダイアログを表示しない(ほんとかな?)
    
    
try
      set dCount to count every document
      
if dCount = 0 then
        return false
      else
        tell document 1
          tell current tab
            set rList to every file browser whose remote is true
            
            
if rList = {} then return false
            
            
set remoteBrowser to contents of first item of rList
            
            
tell remoteBrowser
              set aInfo to properties
            end tell
            
            
set tmpADR to address of aInfo
            
set tmpPath to root path of aInfo
            
            
if {tmpADR, tmpPath} = {chkAddress, chkPath} then
              return true
            else
              return false
            end if
          end tell
        end tell
      end if
    on error
      return false
    end try
  end tell
  
end chkConnection

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