Archive for 2月, 2016

2016/02/28 OS X 10.11ですでに利用可能になっていた日本語音声コマンド呼び出し

OS X 10.12になると、OS XでもSiriが利用可能になるなどの「噂」が聞こえてきています。使えれば便利ですが、使えないと困るというほどでもありません。

音声認識操作についていえば、Apple WatchがMacに直接BluetoothなりWiFiでつながって、Macの外部マイク的な役割を果たしてくれるか、Bluetoothヘッドセットを音声認識用に併用できないと一定レベルの実用性を確保しづらいところです。

OS Xに搭載されている音声認識コマンド自体について、現状(OS X 10.11)ではどうなのか? ちょっと確認してみました。

確認してみたところ、OS X 10.11上ですでに日本語で各種音声コマンドが呼び出せるようになっていることを見つけました。

v1.png
▲システム環境設定

v2.png
▲アクセシビリティ>音声入力。「次のキーワードで音声入力を有効にする」にチェックを入れないと、メニューバーに音声コマンド用のメニューエクストラ(マイクのアイコン)が表示されない

v3.png
▲「高度なコマンドを有効」はデフォルトではオフになっている。「メニューバーにアクセシビリティの状況を表示」もデフォルトでオフ。メニュー表示させておいたほうが便利

v5.png
▲音声コマンドの制御メニューアイテム

v6.png
▲とりあえず「キーワードなしで聞き取り」をメニューから実行すると、音声認識パレットが表示される

v7.png
▲音声入力コマンドパレット。音声認識コマンド一覧を表示。音声認識コマンド「コマンドを表示」で表示、「コマンドを隠す」で消去

AppleScriptでコマンドを追加するには、AppleScriptでアプレットを記述し、「システム環境設定」で追加可能。

v8.png

「+」をクリックするとユーザーによる音声認識コマンドを追加。

v9.png

AppleScriptアプレットを「Finder項目を開く…」で指定して実行させる

Spotlight検索や辞書検索については、この音声入力コマンドでフリーキーワードを指定できるようになっており、あなどれないレベルに達していることがわかります。ただ、複数のアプリケーションを操作して実現するような複雑で高度なAppleScriptを実行できるかどうかは、実際に確認してみないとわかりません。

ただ、GUIのメニュー階層を音声認識でナビゲートするのは、実際に作って使ってみるとかーーなりかったるいのと、1つの音声コマンドに類義語(エイリアスみたいなもの)を定義できないと実用性が下がります、、、、

Siriのキモは人間が間違った音声入力を行っても事前に想定したシナリオどおりに処理する柔軟なシナリオ制御能力。「可変パラメータ」+「固定コマンド」の組み合わせという高度な処理を行っているので、当初はOS側が用意したコマンドしか実行できない可能性も考えられます。

2016/02/28 Safariの履歴を読んでトップ10をテキストで出力する

SafariのHistory.plistを読み込んで、アクセス回数のトップ10をテキスト出力するAppleScriptです。

Safari 9.1+OS X 10.11環境を前提としています。plistの内容については、Safariのバージョンごとに変更が加わってもおかしくないので、メジャーバージョンアップ時には動作確認する必要があることでしょう。

他のアプリケーションの.plistファイルにアクセスするのはかなり野蛮な処理ですが(Sandbox環境では許可されない)、場合によっては有用なこともあるでしょう。

ちなみに、Scriptの実行例はサブマシン(MacBook Air 2011)で実行したものです。

AppleScript名:Safariの履歴を読んでトップ10をテキストで出力する
– Created 2016-02-27 by Takaaki Naganoya
– Piyomaru Software 2016
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set libPath to (POSIX path of (path to library folder from user domain)) & “Safari/History.plist”
set aRec to retDictFromPlist(libPath) of me
set bRecList to aRec’s valueForKeyPath:“WebHistoryDates”

set bArray to sortRecListByLabel(bRecList, “visitCount”, false) of me
set outStr to “”
set aCount to 0

repeat with i from 0 to 100
  set anItem to (bArray’s objectAtIndex:i)
  
  
set aURL to (anItem’s valueForKeyPath:“”) as string
  
set aTitle to (anItem’s valueForKeyPath:“title”) as string
  
set aDispTItle to (anItem’s valueForKeyPath:“displayTitle”) as string
  
set aVisitCount to (anItem’s valueForKeyPath:“visitCount”) as string
  
set redirectURLs to (anItem’s valueForKeyPath:“redirectURLs”) as list
  
set lastVisitedDate to (anItem’s valueForKeyPath:“lastVisitedDate”) as string
  
  
if aURL does not start with “http://piyocast.com” then –自分のところのサイト関連を除外
    set aStr to ((aCount + 1) as string) & “:(” & (aVisitCount as string) & “)” & aTitle & return
    
set outStr to outStr & aStr
    
    
set aCount to aCount + 1
    
if aCount = 10 then exit repeat
    
  end if
  
  
end repeat

return outStr

(*
–>  ”1:(7657)radiko.jp
2:(608)Apple
3:(416)ソフトバンクWi-Fiスポット
4:(156)公式Apple Store(日本)- iPad Air、MacBook Pro、ほかにもたくさん
5:(125)Yahoo! JAPAN
6:(108)Mac整備済製品 - Apple Store (Japan)
7:(54)Apple-Style \”アップルなBlogをリンク\”
8:(44)PC Watch
9:(31)Facebook
10:(28)アップル - Mac Pro

*)

–Read plist
on retDictFromPlist(aPath as text)
  set thePath to current application’s NSString’s stringWithString:aPath
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theDict to current application’s NSDictionary’s dictionaryWithContentsOfFile:thePath
  
return theDict
end retDictFromPlist

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList, aLabelStr, ascendF)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set sortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF
  
set sortDescArray to current application’s NSArray’s arrayWithObjects:sortDesc
  
set sortedArray to aArray’s sortedArrayUsingDescriptors:sortDescArray
  
return sortedArray
end sortRecListByLabel

★Click Here to Open This Script 

2016/02/24 通貨換算処理を行う

通貨換算処理を行うAppleScriptです。

通貨換算処理はOS側で持っていてよさそうな処理ですが、なんにもない(電卓には入っていますが)ので自分で組むことになります。

calculator.png

calculator2.png

たまたま、

クジラ外国為替確認API
http://api.aoikujira.com/kawase/

からCSVでデータをダウンロードしていますが、JSONでもなんでもOKなわけで、、、、さらに、ここのデータは、

XCurrencies
http://xurrency.com/currencies

を参考にしているようです。ただ、本質的には、

INTERNATIONAL MONETALY FUND
http://www.imf.org/

のデータを使うべきなはずで、、、更新間隔などの関係でOS上の電卓.appと同じ結果にはなりません(小数点以下で)。

とりあえず、テスト的に作成してみましたが・・・処理中にレートが変動した場合に対処することを考えると、通貨レートのデータについては処理開始時に一度だけダウンロードして保持しておくことが望ましいと考えます。

# 電卓.appの結果と完全に合わせるためにはYahoo!のサービスを使う必要が、、

AppleScript名:通貨換算処理を行う
– Created 2016-02-24 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

load framework

—指定の通貨で1ドル(US Dollar)に対してのレートを取得
set yenRes to getTargetCurrency(“JPY”) of me
–>  111.95734
set euroRes to getTargetCurrency(“EUR”) of me
–>  0.90814

–サービスがサポートしている通貨名をすべて返す
set curList to getAvailableCurrencyNames() of me
–>  {”ARS”, “UYU”, “ANG”, “CAD”, “CUP”, “GTQ”, “KYD”, “CRC”, “COP”, “JMD”, “CLP”, “DOP”, “TTD”, “NIO”, “HTG”, “PAB”, “BSD”, “BMD”, “PYG”, “BBD”, “BRL”, “VEF”, “BZD”, “PEN”, “BOB”, “HNL”, “MXN”, “XCD”, “XPF”, “INR”, “IDR”, “AUD”, “KHR”, “SGD”, “LKR”, “SCR”, “THB”, “NZD”, “NPR”, “PKR”, “BDT”, “FJD”, “PHP”, “BND”, “VND”, “MOP”, “MYR”, “MMK”, “LAK”, “CNY”, “TWD”, “JPY”, “KRW”, “HKD”, “ISK”, “ALL”, “GBP”, “UAH”, “HRK”, “CHF”, “SEK”, “RSD”, “CZK”, “DKK”, “NOK”, “HUF”, “BGN”, “BYR”, “PLN”, “MDL”, “EUR”, “RON”, “RUB”, “AZN”, “AED”, “AMD”, “YER”, “ILS”, “IQD”, “IRR”, “UZS”, “OMR”, “KZT”, “QAR”, “KWD”, “GEL”, “SAR”, “TMT”, “TRY”, “BHD”, “JOD”, “LBP”}

–指定通貨Aの指定数値が指定通貨Bではいくらになるか?
set convedRes1 to convertCurrency(1, “EUR”, “JPY”) of me
–>  123.282027000242
set convedRes2 to convertCurrency(1, “JPY”, “EUR”) of me
–>  0.008111482463
set convedRes3 to convertCurrency(10000, “JPY”, “USD”) of me
–>  89.319735534981 –1万円(Yen)で89米ドル(US Dollar)

–指定通貨Aから指定通貨Bに換算、USDの指定可能
on convertCurrency(aNum as number, aCurName as string, bCurName as string)
  –Exclude Same Rate
  
if aCurName is equal to bCurName then return 1
  
  
set curList to getAvailableCurrencyNames() of me
  
if aCurName is in curList and bCurName is in curList then
    –Normal conversion    
    
set aCurrency to getTargetCurrency(aCurName) of me
    
set bCurrency to getTargetCurrency(bCurName) of me
    
return (bCurrency / aCurrency) * aNum
  else
    –USD conversion
    
if aCurName = “USD” then
      set aRes to (bCurName is in curList)
      
if aRes = false then return false
      
set bCurrency to getTargetCurrency(bCurName) of me
      
return (bCurrency / 1) * aNum
    else if bCurName = “USD” then
      set aRes to (aCurName is in curList)
      
if aRes = false then return false
      
set aCurrency to getTargetCurrency(aCurName) of me
      
return (1 / aCurrency) * aNum
    else
      –Error (The currency is not available)
      
return false
    end if
  end if
end convertCurrency

on getAvailableCurrencyNames()
  set a to downloadDataFromWeb(“http://api.aoikujira.com/kawase/csv/usd”, 30) of me
  
set theData to (current application’s SMSForder’s arrayFromCSV:a commaIs:“,”) as list
  
set curList to contents of items 7 thru -1 of theData
  
set curNameList to {}
  
repeat with i in curList
    set the end of curNameList to (contents of item 1 of i)
  end repeat
  
return curNameList
end getAvailableCurrencyNames

on getTargetCurrency(targetCurrency as string)
  set a to downloadDataFromWeb(“http://api.aoikujira.com/kawase/csv/usd”, 30) of me
  
set theData to current application’s SMSForder’s arrayFromCSV:a commaIs:“,”
  
set aRes to searchInListByIndexItem(theData, 1, targetCurrency) of me
  
set aRate to (contents of item 2 of aRes) as real
  
return aRate
end getTargetCurrency

on downloadDataFromWeb(aURL as string, timeOutSec as number)
  set aURL to current application’s |NSURL|’s alloc()’s initWithString:aURL
  
set aReq to current application’s NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeOutSec
  
set urlRes to (current application’s NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
  
  
if urlRes = missing value then
    return false –Download Error
  else
    set aVal to (current application’s NSString’s alloc()’s initWithData:urlRes encoding:(current application’s NSUTF8StringEncoding))
    
return aVal
  end if
end downloadDataFromWeb

on searchInListByIndexItem(aList as list, itemNum as integer, hitData as string)
  set setKey to current application’s NSMutableSet’s setWithArray:aList
  
  
if itemNum < 1 then return {}
  
set aPredicateStr to (“SELF[” & (itemNum - 1) as string) & “] == ’” & hitData & “’”
  
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicateStr
  
set aRes to (setKey’s filteredSetUsingPredicate:aPredicate)
  
set bRes to aRes’s allObjects()
  
  
set cRes to bRes as list
  
  
if cRes is not equal to {} then
    set cRes to contents of first item of cRes
  end if
  
  
return cRes
end searchInListByIndexItem

★Click Here to Open This Script 

2016/02/22 YouTubeへのムービーアップロードのじっけん

Matthias Gansrigler氏がGithubで公開している「ESSVideoShare-for-OS-X-Lion」を用いて、YouTubeへのムービーのアップロードを行うAppleScriptです。同プロジェクトをGithubからダウンロードしてXcodeでビルドし、生成された「ESSVideoShare.framework」を~/Library/Frameworksにコピーしてください。

本AppleScriptには、いくつか実行のための前提条件があります。

Googleのアカウント(=YouTubeのアカウント)を持っていること

Google APIのうち、YouTube DATA APIをオンにして、API Keyを取得すること

Googleのアカウント情報ページにアクセスして「安全性の低いアプリの許可」を「有効」にすること

yt13.png

yt0.png

以上を行ったのちに、掲載AppleScriptの、

set yourTubeAPIKey to “XXxxXxXXXxXxX-XxXXxXXXxxxxXXXXxXxXXxXXX”

のところを自分で取得したAPI Keyに置き換えて実行してください。

yt1.png
▲AppleScriptを実行してムービーを指定したあと、このダイアログが表示される。表示されない場合にはScript Editorの裏側に表示されている(隠れている)。「Sign In」をクリックしても再度本ダイアログが表示される場合には、Googleアカウントの「安全性の低いアプリの許可」が無効になっている

yt2.png
▲ムービーのタイトルや説明などを入力するウィンドウが表示される。本当は、これをあらかじめ一括で指定したかったので、これだとちょっとダルい

yt3.png
▲確認画面

yt4.png
▲アップロード中のプログレス表示

yt5.png
▲アップロードが終了したところ

yt11.png
▲アップロード前のムービー一覧表示(件数が45件)

yt12.png
▲アップロード後のムービー一覧表示(件数が46件に増えている)

なお、AppleScriptの実行を終えたら、Googleアカウントの「安全性の低いアプリの許可」を「無効」に戻しておくことを強くおすすめします。

AppleScript名:YouTubeへのアップロードのじっけん
– Created 2016-02-22 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ESSVideoShare” –https://github.com/eternalstorms/ESSVideoShare-for-OS-X-Lion

set yourTubeAPIKey to “XXxxXxXXXxXxX-XxXXxXXXxxxxXXXXxXxXXxXXX”
set youTube to current application’s ESSYouTube’s alloc()’s initWithDelegate:me developerKey:yourTubeAPIKey

set aPath to POSIX path of (choose file)

set urlToVideoOnHardDisk to current application’s |NSURL|’s fileURLWithPath:aPath
youTube’s uploadVideoAtURL:urlToVideoOnHardDisk

on ESSYouTubeNeedsWindowToAttachTo:aYouTubeReq
  
end ESSYouTubeNeedsWindowToAttachTo:

on ESSYouTubeDidFinish:aYouTubeReq
  log “ESSYouTubeDidFinish”
end ESSYouTubeDidFinish:

★Click Here to Open This Script 

2016/02/22 Cocoaオブジェクトのクラス名を文字列で取得 v2

Cocoaオブジェクトのクラス名をAppleScriptから文字列で取得する実験です。

v1から改良を行い、文字列からクラス名のオブジェクト(インスタンス)を生成したあと、isKindOfClassでクラスの照合を行うようにしてみました。ただ、完璧な処理を目指したものではなく、試作品レベルです。

Objective-Cの記述例を探してみたものの、こういう処理を行うためにはObjective-Cのランタイムの機能を呼び出すなど、AppleScriptでは利用できないものばかりだったので、地道に照合してみました。

Foundationで扱うクラスに限定して照合するかどうかは処理内容次第ですが、だいたい目指すところはクリアーできたと思います。

AppleScript名:Cocoaオブジェクトのクラス名を文字列で取得 v2
– Created 2016-02-22 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

set aRes to getClassNameStringFromObject(current application’s NSNumber’s numberWithInt:103) of me
–>  ”NSNumber”

set bRes to getClassNameStringFromObject(current application’s NSString’s stringWithString:“ぴよぴよ”) of me
–>  ”NSString”

set cRes to getClassNameStringFromObject(current application’s NSArray’s arrayWithArray:{1, 2, 3}) of me
–>  ”NSArray”

on getClassNameStringFromObject(aObject)
  
  
–This Cocoa class name list is made for testing
  
set classList to {“NSString”, “NSArray”, “NSMutableArray”, “NSNumber”, “NSByteCountFormatter”, “NSCalendar”, “NSCharacterSet”, “NSCountedSet”, “NSSet”, “NSDictionary”, “NSMutableDictionary”, “NSAttributedString”, “NSDate”, “NSData”, “NSDataDetector”, “NSDateComponents”, “NSDateFormatter”, “NSDateIntervalFormatter”, “NSDecimalNumber “, “NSEnergyFormatter”, “NSError”, “NSEvent”, “NSIndexSet”, “NSLocaleIdentifier”, “NSMutableData”, “NSMutableAttributedString”, “NSMutableCharacterSet”, “NSMutableIndexSet”, “NSMutableSet”, “NSPredicate”, “NSPrintInfo”, “NSRange”, “NSScanner”, “NSSortDescriptor”, “NSTimer”, “NSTimeZone”, “NSURL”, “NSUnarchiver”, “NSURLConnection”, “NSURLRequest”, “NSUUID”, “NSWeekCalendarUnit”, “NSWorkspace”, “OSAScript”, “PDFDocument”, “PDFPage”, “WebView”}
  
  
repeat with i in classList
    set j to contents of i
    
set aClass to current application’s NSClassFromString(j)
    
set aRes to (aObject’s isKindOfClass:aClass) as boolean
    
if aRes = true then return j
  end repeat
  
  
return false
  
end getClassNameStringFromObject

★Click Here to Open This Script 

2016/02/19 Viewを作成してPNGで保存

View/Controlを作成して、View/Controlをデスクトップ上に画像として保存するAppleScriptです。

103bc611-92d0-45e0-b092-9caadc9439a1.png
▲本Scriptの出力結果

デバッグ用に作ったScriptです。各種ViewやControlをプログラム上から生成した際に、その内容をWindowのsubviewに指定して表示するというデバッグもありますが、それよりも手軽にビューの内容そのものをPNG画像として書き出してしまおうというものです。

Retina Display上で実行しても、得られるイメージはRetina Resolutionではないところが注意点でしょうか。

AppleScript名:ASOCで指定Viewを作成してPNGで保存
– Created 2016-02-19 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

–Get Desktop Path
set aDesktopPath to (current application’s NSProcessInfo’s processInfo()’s environment()’s objectForKey:(“HOME”))’s stringByAppendingString:“/Desktop/”

–Make Save Image Path
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.png”)

–Make a Control (View/Control)
set aButton to current application’s NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 180, 80))
aButton’s setButtonType:(current application’s NSMomentaryLightButton)
aButton’s setBezelStyle:(current application’s NSRoundedBezelStyle)
aButton’s setTitle:“Button Image Test”

–Save a View/Control as PNG
set aRes to saveViewAtPathAsPNG(aButton, savePath) of me
–>  true

–指定Viewを指定パスにPNG形式で保存
on saveViewAtPathAsPNG(aView, outPath)
  set aIMG to current application’s NSImage’s alloc()’s initWithData:(aView’s dataWithPDFInsideRect:(aView’s |bounds|()))
  
return saveNSImageAtPathAsPNG(aIMG, outPath) of me
end saveViewAtPathAsPNG

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsPNG(anImage, outPath)
  –画像のRaw画像を作成
  
set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
  
–書き出しファイルパス情報を作成
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
  
–書き出し
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
  
return aRes –成功ならtrue、失敗ならfalseが返る
end saveNSImageAtPathAsPNG

–ImageRepを指定パスにPNG形式で保存
on saveImageRepAtPathAsPNG(imageRep, outPath)
  –書き出しファイルパス情報を作成
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
  
–書き出し
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
  
return aRes –成功ならtrue、失敗ならfalseが返る
end saveImageRepAtPathAsPNG

★Click Here to Open This Script 

2016/02/19 ASOC上でのファイルパスの変換

AppleScriptObjC(以下、ASOC)上での各種パス形式の変換サンプルのAppleScriptです。

OS X 10.10以降ですべての作成/ランタイム環境でASOCの機能をサポートしたことにより、Pure AppleScript(Cocoa呼び出しなし)とASOC(Cocoa呼び出しあり)を分けること自体が無意味になったため、積極的にCocoaの機能を利用していこうということになりました。

ASOCは、「データを設定する機能はあるが、取得するための機能がない」といったAppleScriptの世界の直交性の低さをユーザー側で解消できる環境になりました。

・・・たとえば、AppleScript標準ではプリンター名を指定して印刷する機能はあっても、標準で出力可能なプリンター名一覧を取得する機能が存在していませんでした(shell script呼び出しCocoaの機能呼び出しで解決)。

また、AppleScript対応機能が不十分かつ不完全なアプリケーション(Calendar.appなど)の機能をアテにしないでFramework経由でデータにアクセスするといった解決方法も見られるようになってきました。

そんなわけで、Pure AppleScriptの世界と不可分になってきたASOCですが、在来型のPure AppleScriptよりも扱うパス情報の「型」が増えました。これらのパス情報を適切に扱い、かつ相互変換する必要性が増えてきたわけです。

以下に、現在ASOC上で扱っているパス情報のかずかずをご紹介します。


 Alias:AppleScript Nativeのパス形式。最もメジャーなもの。フォルダ階層は「:」で区切る。ドライブ名が最上位に位置付けられる。ファイル参照的なもので、いったん変数に入れて保持すると、名前が変わろうがパスが変わろうが同じファイル/フォルダを追跡する。実体が存在しないパス文字列をAliasに変換するとエラーになる

 File: Aliasとは別のAppleScript Nativeのパス形式。追跡機能はない。各種アプリケーションのAppleScript用語辞書にfileと書いてあっても実際にはaliasのことがほとんど(例外もいくつかある)。フォルダ階層は「:」で区切る。ドライブ名が最上位に位置付けられる。実体がないパス文字列をFileに変換可能

 POSIX path:Pure AppleScript/ASOC共通で使う。最近利用頻度が著しく上がった形式。一部のアプリケーションや、shell commandを扱うときに使う。Cocoaで一般的に扱うのはコレ。フォルダ階層は「/」で区切る。root(/)が最上位に位置付けられる。基本的に単なる文字列なので追跡機能はない。Pure AppleScriptではクォート処理(quoted form of)する必要があるものの、ASOCでCocoaのAPIに渡す場合には不要。

 POSIX file:AppleScript Nativeのパス形式。位置付けがめんどくさい。POSIX pathの文字列から生成したFileで、追跡機能はない。POSIX pathをAliasに変換する際にいったん経由する中間形式という認識。個人的には、極力、深入りしないようにしている

 URL:Cocoaで画像のオープンを行うときに使う。画像についていえばオープン時にはURL、保存時にはPOSIX pathを指定するのがとっても不思議。「file://」のプロトコルヘッダーが先頭につく。Alphabet+Numeric以外の文字はURLエンコードされる。。フォルダ階層は「/」で区切る。root(/)が最上位に位置付けられる。追跡機能はない

Pure AppleScriptではパス情報を基本的にAliasで扱います。一部の例外的なアプリケーションでPOSIX pathを要求されたりしますが基本的にはAliasです。

distiller.png
▲例外的に処理対象のファイルにPOSIX pathを要求する、AdobeのAcrobat Distiller。しかもpathにquoted form ofでクォート処理するとダメ。ダメな実装の見本

このあたり、各アプリケーションがどのようなパス情報を期待しているかは、各アプリケーションの用語辞書に書いてあります(書いてあっても実際に試すという作業が必要)。

複数のパス情報形式を扱うことが初心者に混乱を招くことがあるようですが、なんのことはないCocoaでもPOSIX pathとURLなどの複数のパス形式を扱っているため、複数のパス形式を処理ないし変換する必要があるのは、仕方のないことのようです。

なお、本サンプルはScript Editor上での記述・実行を念頭に置いたものであり、Xcode上でASOCを記述したときにまったく同様に動く保証のあるものではありません。Xcode上では極力Cocoaのデータ形式に変換するか文字列で保持するのがセオリーです。

AppleScript名:ファイルパスの変換(Alias→POSIX path→NSURL→POSIX path→file→Alias)
– Created 2016-02-19 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–Get Alias (AppleScript native file path format)
set anAlias to choose file
–>  alias “Macintosh HD:Users:me:Documents:……”

–Get POSIX path from Alias
set aPOSIX to POSIX path of anAlias
–>  ”/Users/me/Documents/……”

–Get NSURL from POSIX path
set aURL to current application’s |NSURL|’s fileURLWithPath:aPOSIX
–>  (NSURL) file:///Users/me/Documents/………%83%88%EF%BC%92.scptd/

–Get NSURL string
set bPath to aURL’s absoluteString()
–>  (NSString) “file:///Users/me/Documents/A….9C%EF%BC%89.scptd/”

–Get file path (POSIX path) NSString
set cPath to aURL’s |path|()
–>  (NSString) “/Users/me/Documents/……scptd”

–Get POSIX file path string from NSString
set dPath to cPath as string
–>  ”/Users/me/Documents/……..scptd”

–Get file from POSIX path
set aFile to POSIX file dPath
–>  file “Macintosh HD:Users:me:Documents:….scptd”

–Get Alias from file
set bAlias to aFile as alias
–>  alias “Macintosh HD:Users:me:Documents:….scptd”

★Click Here to Open This Script 

2016/02/16 FBEncryptorで文字列の暗号化、復号化(ASOC版)

xcatsanさんが公開されている「AES128暗号化ライブラリ FBEncryptor」を少々書き変えて(ARC対応&フレームワーク化。単なる作業レベル)作ったFBEncryptorKitを呼び出して文字列の暗号化、復号化を行うAppleScriptです。

以前にXcode上のAppleScriptObjCでこれを呼び出すものを書いてみましたが、通常のScript Editorで利用できるようにした方が応用が効くため、Cocoa Frameworkとして別途ビルドしてみました。

OS X 10.10以降用にビルドしたバイナリを用意しましたので、試したい方は(自己責任で)~/Library/Frameworksフォルダに入れて呼び出してください。

–> Download Binary

AppleScript名:FBEncryptorで文字列の暗号化、復号化
– Created 2016-02-16 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “FBEncryptorKit” –https://github.com/dev5tec/FBEncryptor

set aStr to “ABCDEFあいうえお
かきくけこGHIJKLMN”

set aKey to “piyomaru”

–Encryption
set aEnc to current application’s FBEncryptorAES’s encryptBase64String:aStr keyString:aKey separateLines:true
–>  (NSString) “N0/E5FB97DY+qOFtfKK9CCsAMKznyej94Ons1lC90V/9vMJIaBw5R+mbaxaTm711″

–Decription
set aDec to current application’s FBEncryptorAES’s decryptBase64String:aEnc keyString:aKey
(*
(NSString) “ABCDEFあいうえお
かきくけこGHIJKLMN”
*)

★Click Here to Open This Script 

2016/02/15 接続中のディスプレイのうちRetinaのものが存在するかどうかをチェック

実行中のMacに接続されている(本体ディスプレイも含む)複数のディスプレイにRetina Displayが存在するかどうかをチェックするAppleScriptです。

AppleScript名:接続中のディスプレイのうちRetinaのものが存在するかどうかをチェック
– Created 2016-02-14 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

set rRes to detectRetinaDisplay() of me
–>  false –Retina Display is not present or closed
–>  true –Retina Display is present

on detectRetinaDisplay()
  set dispList to current application’s NSScreen’s screens()
  
set retinaF to false
  
  
repeat with i in dispList
    set j to contents of i
    
set aDepth to j’s backingScaleFactor()
    
if aDepth > 1.0 then
      set retinaF to true
    end if
  end repeat
  
  
return retinaF
end detectRetinaDisplay

★Click Here to Open This Script 

2016/02/14 メイン画面がRetina Displayか否かを取得

実行しているコンピュータのメイン画面がRetina Displayかどうかを取得するAppleScriptです。

AppleScript名:メイン画面がRetina Displayか否かを取得
– Created 2016-02-14 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

set aRes to current application’s NSScreen’s mainScreen()’s backingScaleFactor()
–>  2.0 –(Retina)
–>  1.0 –(Not Retina)

★Click Here to Open This Script 

2016/02/13 文字列で与えたシェルコマンドを実行する

文字列で指定したシェルコマンド(例:pwd)をNSTaskで実行して結果を返すAppleScriptです。

do shell scriptとほぼ同じ内容で、実行途中に出力される文字列などについては無視して、結果だけ返しています。

AppleScript名:文字列で与えたシェルコマンドを実行する
– Created 2016-02-13 by Takaaki Naganoya
– 2016 Piyomaru Software
–以下を参照:
–http://stackoverflow.com/questions/412562/execute-a-terminal-command-from-a-cocoa-app
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aRes to (runCommandString(“pwd”) of me) as string
–>  ”/”

set bRes to (runCommandString(“cd & ls -la”) of me) as string

set cRes to (runCommandStringAtJapaneseEnv(“cd & ls -la”) of me) as string

–Lock Screen
–runCommandAtPath(”/System/Library/CoreServices/Menu Extras/User.menu/Contents/Resources/CGSession”, “-suspend”) of me

–文字列で与えたシェルコマンドを実行する
on runCommandString(commandStr as string)
  set aPipe to current application’s NSPipe’s pipe()
  
set aTask to current application’s NSTask’s alloc()’s init()
  
aTask’s setLaunchPath:“/bin/sh”
  
aTask’s setArguments:{“-c”, current application’s NSString’s stringWithFormat_(“%@”, commandStr)} –stringWithFormatはASOCに書き換え時の要注意点
  
aTask’s setStandardOutput:aPipe
  
set aFile to aPipe’s fileHandleForReading()
  
aTask’s |launch|()
  
return current application’s NSString’s alloc()’s initWithData:(aFile’s readDataToEndOfFile()) encoding:(current application’s NSUTF8StringEncoding)
end runCommandString

–日本語環境で、文字列で与えたシェルコマンドを実行する。結果に日本語文字列を含む出力を取得して返す
on runCommandStringAtJapaneseEnv(commandStr as string)
  set jComStr to “export LANG=en_US.UTF-8;” & commandStr
  
set jRes to runCommandString(jComStr) of me
  
return jRes
end runCommandStringAtJapaneseEnv

–指定したパスのシェルコマンドを実行する(結果などは取得しない)
on runCommandAtPath(commandPath as string, anArgument as string)
  set aTask to current application’s NSTask’s alloc()’s init()
  
aTask’s setLaunchPath:commandPath
  
aTask’s setArguments:(current application’s NSArray’s arrayWithObject:anArgument)
  
aTask’s |launch|()
end runCommandAtPath

★Click Here to Open This Script 

2016/02/13 Myriad Tables Libによる表インタフェースの表示

Shane StanleyによるAppleScript Libraries「Myriad Tables Lib」のバージョン1.0.0を試してみました。

同ライブラリをダウンロードして、「Myriad Tables Lib.scptd」を~/Libraries/Script Libraries」フォルダに入れると利用可能になります。

以前からいろいろTable ViewをAppleScript上で表示させたりしていましたが、それのデラックス版です。同ライブラリにはAppleScript用語辞書やドキュメントもついているため、手軽に表インタフェースを表示できます。

table1.png

table3.png
▲ヘッダー行をクリックすると当該セルをキーとしたソートを行う

table4.png
▲ヘッダー行を再度クリックすると当該セルをキーとした逆順ソートを行う

table5.png
▲popup menuの表示も可能

table6.png
▲選択+入力が可能なcombo boxの表示も可能

AppleScriptによるワークフローにこうした表インタフェースをつけることの意味は、処理前のデータの確認(CSVファイルなど)、処理範囲の指定(選択範囲のみ処理するとか)、処理後の結果確認などを手軽に行えるというあたりにあります。

# テーブル内容のしぼりこみ表示が行えるとなおよいでしょう

データ処理を行う対象を指定するためだけにExcelが必要、といった話がよくありましたが、こうしたGUI部品をAppleScriptから手軽に(Xcodeを使わずに)必要な部分だけ呼び出せることにはメリットがあります。

table2.png
▲フルオプション指定時

いろいろとオプションを指定すると、行番号や選択範囲の削除/新規作成、カスタムビューの追加表示(accessory view)なども行えます。accessory viewについては、とりあえずNSImageViewを表示してみましたが、これに「飾り」以上の意味づけがあるのかどうかが気になります。

同梱のSampleを見てみたら、オプションのチェックボックスの値を取得していました。そういう使い方ができるもよう。ただし、accessory viewに指定できるビューの最大サイズに制限があるため、ここに巨大なWebViewを表示するとかMKMapViewを表示するのは苦しい。

この表インタフェース上ですべてのデータ入力を行ってもらうといった使い方は向いていないので(不可能ではないものの、途中でScriptがクラッシュしたときに途中のworkファイルが保存されていない)、あくまで内容確認、処理範囲選択などの用途に活用するとよいのではないでしょうか。

AppleScript名:かんたんなテーブルの表示
– Created 2016-02-07 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use script “Myriad Tables Lib”

set x to {a:1.4} – 未サポートクラス(record)は表示できないが、無視される
set theHeads to {“名”, “姓”, “インデックス”, “チェックボックス”, “スコア”, “日付”} –ヘッダー
set theDate to current date

set someData to {{“長野谷”, “隆昌”, 1, true, 10000, theDate, x}, ¬
  {“長野谷”, “ぴよまる”, 2, true, -13.5, theDate, x}, ¬
  {
“長野谷”, “ぴよこ”, 3, false, 9.0, theDate + 40000, x}, ¬
  {
“長野谷”, “ぴよぴよ”, 4, false, 1.23456789E+7, theDate + 50000, x}, ¬
  {
“長野谷”, “ぴよきち”, 5, true, 133.4567, theDate + 30000, x}, ¬
  {
“長野谷”, “ぴよまろ”, 6, false, 22.0, theDate + 60000, x}}

–テーブルの各列のデータ表示形式はこのテンプレートをもとにしている
set theTemplate to {“”, “”, 1, true, 1, current date, missing value}

–Step1- 必須操作。最初にデータを作成する必要がある
set myTable to make new table with data someData ¬
  with title “テーブルサンプル” column headings theHeads ¬
  
with prompt “複数行選択可。 すべてのデータは編集可能です。” editable columns {} ¬
  
row template theTemplate ¬
  
with multiple selections allowed and empty selection allowed

–Step 2-テーブルの表示オプション(ハイライト表示、枠線表示など)。本Stepは省略可
modify table myTable highlighted rows {} ¬
  grid style grid both dashed between rows ¬
  
OK button name “OK” with OK button is default

–Step 3テーブル表示を行う
set theResult to (display table myTable)
–>  {rows selected:{1}, values selected:{{”長野谷”, “隆昌”, 1, true, 10000, date “2016年2月8日月曜日 18:13:07″, {a:1.4}}}, values returned:{{”長野谷”, “隆昌”, 1, true, 10000, date “2016年2月8日月曜日 18:13:07″, {a:1.4}}, {”長野谷”, “ぴよまる”, 2, true, -13.5, date “2016年2月8日月曜日 18:13:07″, {a:1.4}}, {”長野谷”, “ぴよこ”, 3, false, 9.0, date “2016年2月9日火曜日 5:19:47″, {a:1.4}}, {”長野谷”, “ぴよぴよ”, 4, false, 1.23456789E+7, date “2016年2月9日火曜日 8:06:27″, {a:1.4}}, {”長野谷”, “ぴよきち”, 5, true, 133.4567, date “2016年2月9日火曜日 2:33:07″, {a:1.4}}, {”長野谷”, “ぴよまろ”, 6, false, 22.0, date “2016年2月9日火曜日 10:53:07″, {a:1.4}}}, button number:1, gave up:false}

★Click Here to Open This Script 

2016/02/11 ファイルのMD5、SHA1、SHA512のハッシュ値を求める

github上でJoeKun氏が公開しているFileMD5Hashプロジェクト(Application)をFramework化したmd5Lib.frameworkを呼び出して、指定のファイルパスの各種ハッシュ値(MD5、SHA1、SHA512)を算出するAppleScriptです。

OS X 10.10以降用にビルドしたバイナリを用意しましたので、試したい方は(自己責任で)~/Library/Frameworksフォルダに入れて呼び出してください。

→ Download Binary

AppleScript名:ファイルのMD5、SHA1、SHA512のハッシュ値を求める
– Created 2016-02-11 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “md5Lib” –https://github.com/JoeKun/FileMD5Hash

set aPath to POSIX path of (choose file)

set a to (current application’s FileHash’s md5HashOfFileAtPath:aPath) as string
–>  ”329e854b9993405414c66faac0e80b86″

set b to (current application’s FileHash’s sha1HashOfFileAtPath:aPath) as string
–>  ”50847286df61f304d142c6a0351e39029f010fc2″

set c to (current application’s FileHash’s sha512HashOfFileAtPath:aPath) as string
–>  ”5132a7b477652db414521b36……..1a6ff240e861752c”

★Click Here to Open This Script 

2016/02/10 iTunesライブラリ内のメディアへのアクセス

iTunesのライブラリにアクセスして情報を取得するAppleScriptです。

AppleScriptでは一般的にiTunesに対して直接命令を実行して、選択中のトラックの情報を取得したり、さまざまな処理を行います。これが最も一般的です。

ただし、これだとスピードを稼げないため、外部にXML形式で保存されているiTunes Library(iTunes Music Library.xml)ファイルに直接アクセスして、一般的なXMLを扱うように処理する方法も存在しています。これも実際にASOCで試してみました。

iTunes 11以降がインストールされた環境では、iTunes Libraryへのアクセスフレームワーク「iTunesLibrary.framework」が利用でき、これを経由して間接的にiTunes Music Library.xmlにアクセスして情報の取得が行えます。本AppleScriptはこの方法を試してみたものです。

たいてい、AppleScriptでiTunesにアクセスして遅いのなんのと言われている場合には,力辰任△蝓iTunes登場直後から外部にXMLベースのライブラリ情報が書き出されていたことからも、大量のデータ取得には△諒法が推奨されてきたことが伺い知れます。それにもかかわらず、「わざわざ遅い方法を使って大量のデータを取得すると時間がかかる」というのは至極当然のことです。

ユーザーが選択したトラックの情報を取得するのであれば,鮖箸Δ里得策ですが、スピードを重視するのであれば△筬が、iTunes上でCD取り込みやMusic Storeからの楽曲購入に伴うデータ更新を考慮するのであればが適しているのではないかと思うものです。

AppleScript名:iTunesライブラリ内のメディアへのアクセス
– Created 2016-02-10 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “iTunesLibrary”

set library to current application’s ITLibrary’s libraryWithAPIVersion:“1.0″ |error|:(missing value)
if library is equal to missing value then return

set playLists to library’s allPlaylists()
set tracks to library’s allMediaItems()

set tracksTotal to tracks’s |count|()
log tracksTotal

repeat with i in tracks
  set j to contents of i
  
  set aTitle to j’s title()
  
set anArtist to j’s playCount()
  
end repeat

★Click Here to Open This Script 

2016/02/10 ASOCでゼロパディング v2

Cocoaの機能を用いて数値に対して指定桁数でゼロパディングを行ってstringで返すAppleScriptの改良版です。

出力指定桁と指定桁から算出される最大値のオーバーチェックを付加しました。

AppleScript名:ASOCでゼロパディング v2
– Created 2016-02-09 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aNum to 4
set aRes to retZeroPaddingText(aNum, 5) of me
–>  ”00004″–OK

set aNum to 12345678
set aRes to retZeroPaddingText(aNum, 5) of me
–>  ”"–range over

on retZeroPaddingText(aNum as integer, aDigitNum as integer)
  if aNum > (((10 ^ aDigitNum) as integer) - 1) then return “” –Range Check
  
set aFormatter to current application’s NSNumberFormatter’s alloc()’s init()
  
aFormatter’s setUsesGroupingSeparator:false
  
aFormatter’s setAllowsFloats:false
  
aFormatter’s setMaximumIntegerDigits:aDigitNum
  
aFormatter’s setMinimumIntegerDigits:aDigitNum
  
aFormatter’s setPaddingCharacter:“0″
  
set aStr to aFormatter’s stringFromNumber:(current application’s NSNumber’s numberWithFloat:aNum)
  
return aStr as string
end retZeroPaddingText

★Click Here to Open This Script 

2016/02/10 ISO8601ちっくな週カウント

Cocoaの機能を用いて指定日付が1年のうちの何週目にあたるか、一般常識的なカウントと、ISO8601で規定されている週カウントの両方で計算するAppleScriptです。

iso8601wc.png

ISO8601で規定している週番号では、1/1が木曜日から土曜日までの間にある場合には前年の12月の最終週の続きとして扱われます。aWNがiCalの画面上に表示される週番号、bWNがISO8601に則ってカウントした週番号です。

AppleScript名:ISO8601ちっくな週カウント
– Created 2016-02-10 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aNSDate to makeNSDate(2016, 1, 1) of me
set aCal to current application’s NSCalendar’s currentCalendar()
aCal’s setMinimumDaysInFirstWeek:1
set aWN to (aCal’s components:(current application’s NSWeekCalendarUnit) fromDate:aNSDate)’s week()

aCal’s setMinimumDaysInFirstWeek:4 –ISO8601 Week Count
set bWN to (aCal’s components:(current application’s NSWeekCalendarUnit) fromDate:aNSDate)’s week()

return {aWN, bWN}
–>  {1, 52}

–Y,M,Dを指定してNSDateを作成
on makeNSDate(aYear as integer, aMonth as integer, aDay as integer)
  set aComp to current application’s NSDateComponents’s alloc()’s init()
  
aComp’s setDay:aDay
  
aComp’s setMonth:aMonth
  
aComp’s setYear:aYear
  
set aGrego to current application’s NSCalendar’s calendarWithIdentifier:(current application’s NSGregorianCalendar)
  
set aDate to aGrego’s dateFromComponents:aComp
  
return aDate
end makeNSDate

★Click Here to Open This Script 

2016/02/09 ASOCでゼロパディング

Cocoaの機能を用いて数値に対して指定桁数でゼロパディングを行ってstringで返すAppleScriptです。

Pure AppleScriptに対して実行速度の面でさほどメリットがあるわけではありません。単なる練習です。

AppleScript名:ASOCでゼロパディング
– Created 2016-02-09 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aNum to 40
set aRes to retZeroPaddingText(aNum, 5) of me
–>  ”00040″

on retZeroPaddingText(aNum as integer, aDigitNum as integer)
  set offsetFormatter to current application’s NSNumberFormatter’s alloc()’s init()
  
–offsetFormatter’s setNegativeFormat:”-#####”
  
–offsetFormatter’s setPositiveFormat:”#####”
  
offsetFormatter’s setUsesGroupingSeparator:false
  
offsetFormatter’s setAllowsFloats:false
  
offsetFormatter’s setMaximumIntegerDigits:aDigitNum
  
offsetFormatter’s setMinimumIntegerDigits:aDigitNum
  
offsetFormatter’s setPaddingCharacter:“0″
  
set aStr to offsetFormatter’s stringFromNumber:(current application’s NSNumber’s numberWithFloat:aNum)
  
return aStr as string
end retZeroPaddingText

★Click Here to Open This Script 

2016/02/09 コンピュータの画像を取得して表示

実行しているコンピュータのアイコン画像を取得してWindow表示するAppleScriptです。アイコンを取得するのがメインで、表示部分はオマケです。

Script Editor上で、ControlーCommandーRで実行してください。

icondisp.png
▲MacBookPro10,1上で実行したところ

icondisp2.png
▲Macmini7,1上で実行したところ

icondisp3.jpg
▲MacBookAir4,1上で実行したところ

AppleScript名:コンピュータの画像を取得して表示
– Created 2016-02-09 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

–Get Computer Icon
set anImage to current application’s NSImage’s imageNamed:(current application’s NSImageNameComputer)

–Load Image to NSImageView
set aRect to current application’s NSMakeRect(0, 0, 128, 128)
set aView to current application’s NSImageView’s alloc()’s initWithFrame:aRect
aView’s setImage:anImage

–Display with Window
set aWin to current application’s NSWindow’s alloc()’s init()
aWin’s setContentSize:(aView’s frame()’s |size|())
aWin’s setContentView:aView
aWin’s |center|()
aWin’s makeKeyAndOrderFront:(me)
delay 5
aWin’s |close|()

★Click Here to Open This Script 

2016/02/09 指定URLのJSONをダウンロードしてRecordに変換 v2.1

指定URLのJSONデータを取得して、結果をrecordに変換するAppleScriptです。AppleScript Libraries「BridgePlus」を利用するように変更してみました。

AppleScript名:指定URLのJSONをダウンロードしてRecordに変換 v2.1
– Created 2016-02-06 by Takaaki Naganoya
– Modified 2016-02-08 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus”

–東京電力電力供給状況API JSON URL(指定された日時の電力使用状況を返す)
set a to downloadAndParseJSON(“http://tepco-usage-api.appspot.com/2016/2/6/19.json”) of me
–>  {forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:”2012-02-05 08:30:00″, usage:3720, forecast_peak_updated:”2012-02-05 08:30:00″, day:6, usage_updated:”2016-02-06 11:05:05″, capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:19, entryfor:”2016-02-06 10:00:00″}

–東京電力電力供給状況API JSON URL(指定された日の毎時の電力使用状況を、配列として返す)
set b to downloadAndParseJSON(“http://tepco-usage-api.appspot.com/2016/2/6.json”) of me
–>  {{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:”2012-02-05 08:30:00″, usage:3081, forecast_peak_updated:”2012-02-05 08:30:00″, day:6, usage_updated:”2016-02-05 16:05:06″, capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:0, entryfor:”2016-02-05 15:00:00″}…….{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:”2012-02-05 08:30:00″, usage:3645, forecast_peak_updated:”2012-02-05 08:30:00″, day:6, usage_updated:”2016-02-06 12:05:07″, capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:20, entryfor:”2016-02-06 11:00:00″}}

–東京電力電力供給状況API JSON URL(指定された月の毎日毎時の電力使用状況を、配列として返す)
set c to downloadAndParseJSON(“http://tepco-usage-api.appspot.com/2016/2.json”) of me
–>  {{forecast_peak_period:18, forecast_peak_usage:4260, capacity_updated:”2012-01-31 23:30:00″, usage:2901, forecast_peak_updated:”2012-01-31 23:30:00″, day:1, usage_updated:”2016-01-31 16:05:04″, capacity:4641, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:0, entryfor:”2016-01-31 15:00:00″}……{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:”2012-02-05 08:30:00″, usage:3645, forecast_peak_updated:”2012-02-05 08:30:00″, day:6, usage_updated:”2016-02-06 12:05:07″, capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:20, entryfor:”2016-02-06 11:00:00″}}

on downloadAndParseJSON(aURL)
  set aRes to downloadDataFromWeb(aURL, 30) of me
  
if aRes = false then return false –download error
  
  
set jsonString to current application’s NSString’s stringWithString:aRes
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
set bRes to ASify from aJsonDict
  
return bRes
end downloadAndParseJSON

on downloadDataFromWeb(aURL, timeOutSec)
  set aURL to current application’s |NSURL|’s alloc()’s initWithString:aURL
  
set aReq to current application’s NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeOutSec
  
set urlRes to (current application’s NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
  
  
if urlRes = missing value then
    return false –Download Error
  else
    set aVal to (current application’s NSString’s alloc()’s initWithData:urlRes encoding:(current application’s NSUTF8StringEncoding))
    
return aVal
  end if
end downloadDataFromWeb

★Click Here to Open This Script 

2016/02/08 アプリケーションのBundle IDからアプリアイコンへのフルパスを取得する

指定のバンドルID(com.apple.Safariとか)からアプリケーションへのパスを取得し、アプリケーションのInfo.plistを読み込んでアイコンファイル名を取得。アプリケーションバンドル内のファイル名とタイプを指定して、アプリケーションアイコンへのフルパスを取得するAppleScriptです。

Pure AppleScriptで書くとけっこうめんどくさくて長くなる内容ですが、逆にCocoaの機能を使うと短く簡潔に書けます。

AppleScript名:アプリケーションのBundle IDからアプリアイコンへのフルパスを取得する
– Created 2016-02-08 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

set aBundleID to "com.apple.Safari"
set aPath to retAppIconPathFromBundleID(aBundleID) of me
–>  "/Applications/Safari.app/Contents/Resources/compass.icns"

–Bundle IDからアプリケーションアイコンのフルパスをPOSIX pathで返す
on retAppIconPathFromBundleID(aBundleID)
  –Bundle IDからアプリケーションへのパスを取得する
  
set appPath to current application’s NSWorkspace’s sharedWorkspace()’s absolutePathForAppBundleWithIdentifier:aBundleID
  
if appPath = missing value then return false
  
  
–Info.plistを読み込んで、iconのファイル名を取得
  
set aDict to (current application’s NSBundle’s bundleWithPath:appPath)’s infoDictionary()
  
set iconFile to aDict’s valueForKey:"CFBundleIconFile"
  
if iconFile = missing value then return false
  
  
–パスからバンドルを取得して、バンドル内の指定ファイルタイプのファイル名のパスを取得する
  
set aBundle to current application’s NSBundle’s bundleWithPath:appPath
  
set iconFullPath to aBundle’s pathForResource:iconFile ofType:"icns"
  
if iconFullPath = missing value then return false
  
  
return iconFullPath as string
end retAppIconPathFromBundleID

★Click Here to Open This Script 

2016/02/06 指定URLのJSONをダウンロードしてRecordに変換 v2

指定URLのJSONデータを取得して、結果をrecordに変換するAppleScriptです。結果をrecordとして返すAPIのほかrecordのlistで返すものもあるようなので、対応させてみました。

AppleScript名:指定URLのJSONをダウンロードしてRecordに変換 v2
– Created 2016-02-06 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

on run
  –東京電力電力供給状況API JSON URL(指定された日時の電力使用状況を返す)
  
set a to downloadAndParseJSON("http://tepco-usage-api.appspot.com/2016/2/6/19.json") of me
  
–>  {forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:"2012-02-05 08:30:00", usage:3720, forecast_peak_updated:"2012-02-05 08:30:00", day:6, usage_updated:"2016-02-06 11:05:05", capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:19, entryfor:"2016-02-06 10:00:00"}
  
  
–東京電力電力供給状況API JSON URL(指定された日の毎時の電力使用状況を、配列として返す)
  
set b to downloadAndParseJSON("http://tepco-usage-api.appspot.com/2016/2/6.json") of me
  
–>  {{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:"2012-02-05 08:30:00", usage:3081, forecast_peak_updated:"2012-02-05 08:30:00", day:6, usage_updated:"2016-02-05 16:05:06", capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:0, entryfor:"2016-02-05 15:00:00"}…….{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:"2012-02-05 08:30:00", usage:3645, forecast_peak_updated:"2012-02-05 08:30:00", day:6, usage_updated:"2016-02-06 12:05:07", capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:20, entryfor:"2016-02-06 11:00:00"}}
  
  
  
–東京電力電力供給状況API JSON URL(指定された月の毎日毎時の電力使用状況を、配列として返す)
  
set c to downloadAndParseJSON("http://tepco-usage-api.appspot.com/2016/2.json") of me
  
–>  {{forecast_peak_period:18, forecast_peak_usage:4260, capacity_updated:"2012-01-31 23:30:00", usage:2901, forecast_peak_updated:"2012-01-31 23:30:00", day:1, usage_updated:"2016-01-31 16:05:04", capacity:4641, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:0, entryfor:"2016-01-31 15:00:00"}……{forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:"2012-02-05 08:30:00", usage:3645, forecast_peak_updated:"2012-02-05 08:30:00", day:6, usage_updated:"2016-02-06 12:05:07", capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:20, entryfor:"2016-02-06 11:00:00"}}
  
end run

on downloadAndParseJSON(aURL)
  set aRes to downloadDataFromWeb(aURL, 30) of me
  
if aRes = false then return false –download error
  
  
set jsonString to current application’s NSString’s stringWithString:aRes
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
—-recordとして評価して返す
  
try
    set aRec to aJsonDict as record
  end try
  
—-recordのlistとして評価して返す
  
try
    set aRec to aJsonDict as list
  on error
    return false
  end try
  
—–
  
return aRec
  
end downloadAndParseJSON

on downloadDataFromWeb(aURL, timeOutSec)
  set aURL to current application’s |NSURL|’s alloc()’s initWithString:aURL
  
set aReq to current application’s NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeOutSec
  
set urlRes to (current application’s NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
  
  
if urlRes = missing value then
    return false –Download Error
  else
    set aVal to (current application’s NSString’s alloc()’s initWithData:urlRes encoding:(current application’s NSUTF8StringEncoding))
    
return aVal
  end if
end downloadDataFromWeb

★Click Here to Open This Script 

2016/02/06 指定URLのJSONをダウンロードしてRecordに変換

指定URLのJSONデータを取得して、結果をrecordに変換するAppleScriptです。

Web上でいろいろサンプルを見繕っていたら、シンプルな例がなかなか存在しないため(わざと複雑に書いてあるのはなぜなんだろう?)、自分で簡単な例を書いてみました。

呼び出しているJSONのサービスは、@ssciさんが提供されている東京電力の最新の電力使用状況を返すものです。返ってくるデータの詳細については、「APIの使い方」をご参照ください

AppleScript名:指定URLのJSONをダウンロードしてRecordに変換
– Created 2015-12-16 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

on run
  –東京電力電力供給状況API JSON URL(最新の電力使用状況を返す)
  
set a to downloadAndParseJSON(“http://tepco-usage-api.appspot.com/latest.json”) of me
  
return a
  
–>  {forecast_peak_period:18, forecast_peak_usage:3670, capacity_updated:”2012-02-05 08:30:00″, usage:3720, forecast_peak_updated:”2012-02-05 08:30:00″, day:6, usage_updated:”2016-02-06 11:05:05″, capacity:4484, saving:false, year:2016, month:2, capacity_peak_period:18, forecast:0, hour:19, entryfor:”2016-02-06 10:00:00″}
end run

on downloadAndParseJSON(aURL)
  set aRes to downloadDataFromWeb(aURL, 30) of me
  
if aRes = false then return false –download error
  
  
set jsonString to current application’s NSString’s stringWithString:aRes
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
try
    set aRec to aJsonDict as record
  on error
    set aRec to false
  end try
  
  
return aRec
end downloadAndParseJSON

on downloadDataFromWeb(aURL, timeOutSec)
  set aURL to current application’s |NSURL|’s alloc()’s initWithString:aURL
  
set aReq to current application’s NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:timeOutSec
  
set urlRes to (current application’s NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
  
  
if urlRes = missing value then
    return false –Download Error
  else
    set aVal to (current application’s NSString’s alloc()’s initWithData:urlRes encoding:(current application’s NSUTF8StringEncoding))
    
return aVal
  end if
end downloadDataFromWeb

★Click Here to Open This Script 

2016/02/03 OS X 10.12での変更予定

OS X 10.12ではいくつか重要な変更が予告されています。AppleScript関連で影響を受けそうなものをいくつかピックアップしてみましょう。

 ・Java SE 6のサポート廃止

Adobe CS6のインストールができなくなる(らしい)。

 ・Cocoa Garbage Collectionの廃止

について、つまりそれ以前にビルドされたAppleScript Studioアプリケーション(要GC)が動作しなくなる可能性がきわめて高いということになります。また、古いOSでアプリケーション書き出しを行ったAppleScriptアプレットについても、ソースが存在している場合には再書き出しの必要が出てくることでしょう。

一方、AppleScriptObjCアプリケーションでも、OS X 10.6で開発されたものはARC対応への設定を行い、再コンパイルを行う必要があることでしょう。

Intel x86-32bitバイナリのサポートが終了されるかどうか、というあたりも大きなテーマですが、明確な予告もなく32bitサポートを打ち切るのは危険なのでOS X 10.12では行わないと思われます(根拠なし)。

32bits.png

事実、OS X 10.11上でアクティビティモニタにより確認を行うと32bitで稼働しているプロセスがまだいくつかみられます。

2016/02/02 ASOCでScriptの終了時にCocoaオブジェクトをPurge

ASOCでCocoaのオブジェクトを呼び出すと、Script自体の保存が(再編集を行わないかぎり)できない状態に陥りますが、Script側でCocoaオブジェクトを明示的にPurgeする(ただ変数にヌルを代入するだけ)ことで、問題なく保存できるようになります。

プログラムというほどではなく、かんたんなライフハック的なものでしょうか。ちなみに、ASObjC Explorer 4ではこんなことは必要ありません。好きなときにSaveできます。

別のファイルのAppleScriptをload script命令で変数に読み込んで使うことがありますが、その場合にも終了時に変数に読み込んだscript objectをpurgeするというノウハウがあり、巨大なAppleScriptのプログラムを作成するときに必須のノウハウです。

2016-02-02-21_15_03.gif
▲Script Editor

2016-02-02-21_20_55.gif
▲ASObjC Explorer 4

QuickTime Playerで画面のムービーキャプチャを行い、「GIF Brewery」でQuickTimeムービーからアニメーションGIFに変換してみました。・・・1.7MB程度とけっこう巨大になってしまったので、ちょっとどうだか、、、

冒頭のいつもおなじみのヘッダー部についてはコピペでよそから持ってくるか、ASObjC Explorer 4のデフォルトのテンプレートをそのまま使うのが常なので、ムービー収録のためにわざわざ手打ちしていますが、打ち間違いが予想外に多く、、、、

AppleScript名:ASOCでScriptの終了時にCocoaオブジェクトをPurge
– Created 2016-02-02 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set a to current application’s NSArray’s arrayWithObjects:{1, 2, 3}
set a to “” –Purge Cocoa Object

★Click Here to Open This Script 

2016/02/01 AppleEvent Manager ReferenceがRetired扱いになっていたのは手違いによるもの

去る2016年1月20日、US Appleが主催する開発者メーリングリスト「AppleScript-Implementors ML」において、AppleScriptエンジニアリングチームのChris Nebelが明らかにしたことによると、同社のオンラインドキュメントのうち「AppleEvent Manager」に関するドキュメントが「Retired」扱いに区分されていたことは「手違いによるもの」であることが判明しました。

「AppleEvent ManagerはDeprecated扱いにはなっておらず、RetiredでもなければDeprecatedでもない。ドキュメント自体がRetired扱いを解除され、矛盾を解消できたことをここに報告する。AppleEvent Managerのドキュメントが、通常ライブラリ上に移動され、検索によって表示できることを確認している。」

→ Apple Event Manager Reference

なぜか美談っぽく発表されていますが、本質的には「ケアレスミス」なわけで・・・数年間Release Notesを更新していない時期があったりと、「ケアレス」すぎ・・・(ーー;

2016/02/01 指定の名称のフォントの見本を表示

指定のPostScript名称のフォントの見本をウィンドウ表示するAppleScriptです。

Script Editor上ではControl+Command+Rで実行する必要があります。

NSFont経由で指定フォントが含む文字セットを取得し、どの文字が含まれているのかをチェックしたい、という目的のために作成したものです。ウィンドウを作成して文字表示しているのは、あくまで「おまけ」です。

font1.png

NSFontにcoveredCharacterSet()で指定フォントが持っている文字セットを取得。この文字セットの中に含まれている文字を、1〜65535の数値で(文字を作ってチェックしたらダメで、数値)存在チェックしています。ここだけ、ループでいちいち調べているので時間がかかります(MacBook Pro Retina 2012で4秒ぐらい)。ここは、もうちょっとなんとかならないかと思っています。

また、OS標準のFont Book.appで調べたグリフ数とNSFont→NSCharacterSet経由で存在確認して得られるCharacter数は異なっているため、自分としてはちょっと肩透かしをくらいました。Font Book.appだと各フォントが含んでいる文字といった細かい情報が取得できないため、NSFont経由で調査してみたのですが・・・フォント内の各文字(コード)が実際にグリフを持っているかどうかは、文字セット中の文字を実際にレンダリングしてみないとダメそうな気配がしています(文字コードだけ宣言しておいて何も割り当てグリフがないというケースとか、同じ文字コードに複数のグリフが割り当てられているケースなど(「高」と「癲廖覆呂靴瓦世)など)、深入りするとトンでもないものがありそう)。

AppleScript中で指定している「TheLittleBirdFONT」は、手書き風日本語文字フォントの傑作「ことり文字ふぉんと」(自分が使っているのは大昔に無償配布されていたバージョン)です。OS標準でインストールされているわけではないため、動作チェックには他のものを指定したほうがよいでしょう。

font2.png

ことり文字ふぉんとの独特の特殊記号がどこに入っているかを忘れてしまったため、とりあえず文字セット中の文字をすべてことり文字ふぉんとで表示して「簡易フォント見本帖」のように使ってみたりもしました。

AppleScript名:ASOCでテキストビュー+ボタンを作成(フォント指定)
– Created 2016-02-01 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “Carbon” – AEInteractWithUser() is in Carbon

property windisp : false

set aFontName to “TheLittleBirdFONT”
set aWidth to 450
set aHeight to 600

if current application’s AEInteractWithUser(-1, missing value, missing value) is not equal to 0 then return

set aTitle to “テキストビューのじっけん/TextView Test” –Window Title
set aButtonMSG to “OK” –Button Title

–表示用テキストの作成
set aRes to checkExistenceOfFont(aFontName) of me
if aRes = false then
  display dialog “There is no < " & aFontName & “> font. Designate another one.” –No font
  
return
end if
set bRes to retDefinedCharactersInFont(aFontName) of me
set dispStr to listToStringUsingTextItemDelimiter(bRes, “, “) of me

dispTextView(aWidth, aHeight, aTitle, dispStr, aButtonMSG, 180, aFontName, 36) of me

on dispTextView(aWidth as integer, aHeight as integer, aTitle as text, dispStr, aButtonMSG as text, timeOutSecs as number, fontID, fontSize)
  
  
set aColor to current application’s NSColor’s colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:1.0
  
set (my windisp) to true
  
  
–Text View+Scroll Viewをつくる
  
set aScroll to current application’s NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
set aView to current application’s NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
aView’s setRichText:true
  
aView’s useAllLigatures:true
  
aView’s setTextColor:(current application’s NSColor’s yellowColor()) –cyanColor
  
aView’s setFont:(current application’s NSFont’s fontWithName:fontID |size|:fontSize) –ヒラギノ明朝Pro W3
  
aView’s setBackgroundColor:aColor
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
–Buttonをつくる
  
set bButton to (current application’s NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, 40)))
  
bButton’s setTitle:aButtonMSG
  
bButton’s setTarget:me
  
bButton’s setAction:(“clicked:”)
  
  
–SplitViewをつくる
  
set aSplitV to current application’s NSSplitView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aHeight, aWidth))
  
aSplitV’s setVertical:false
  
  
aSplitV’s addSubview:aScroll
  
aSplitV’s addSubview:bButton
  
aSplitV’s setNeedsDisplay:true
  
  
–WindowとWindow Controllerをつくる
  
set aWin to makeWinWithView(aSplitV, aWidth, aHeight, aTitle, 0.9)
  
aWin’s makeKeyAndOrderFront:(missing value)
  
set wController to current application’s NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
aWin’s makeFirstResponder:aView
  
aView’s setString:dispStr
  
wController’s showWindow:me
  
  
set aCount to timeOutSecs * 10 –timeout seconds * 10
  
repeat aCount times
    if (my windisp) = false then
      exit repeat
    end if
    
delay 0.1
    
set aCount to aCount - 1
  end repeat
  
  
my closeWin:aWin
  
end dispTextView

–Button Clicked Event Handler
on clicked:aSender
  set (my windisp) to false
end clicked:

–make Window for Input
on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle, alphaV)
  set aScreen to current application’s NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
set aBacking to current application’s NSTitledWindowMask –NSBorderlessWindowMask
  
set aDefer to current application’s NSBackingStoreBuffered
  
  
– Window
  
set aWin to current application’s NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
–aWin’s setBackgroundColor:(current application’s NSColor’s whiteColor())
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:false
  
aWin’s setLevel:(current application’s NSNormalWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setAlphaValue:alphaV –append
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
–aWin’s makeKeyAndOrderFront:(me)
  
  
– Set Custom View
  
aWin’s setContentView:aView
  
  
return aWin
  
end makeWinWithView

–close win
on closeWin:aWindow
  repeat with n from 10 to 1 by -1
    (aWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
aWindow’s |close|()
end closeWin:

–指定PostScript名称のフォントがコンピューター上に存在するかどうかチェック
on checkExistenceOfFont(fontName as string)
  if fontName = “” then return false
  
set aFont to current application’s NSFont’s fontWithName:fontName |size|:9.0
  
if aFont = missing value then
    return false
  else
    return true
  end if
end checkExistenceOfFont

–指定Postscript名称のフォントに定義されている文字数を数えて返す
on countDefinedCharactersInFont(fontName as string)
  
  
script spdF
    property aList : {}
  end script
  
  
set aFont to current application’s NSFont’s fontWithName:fontName |size|:9.0
  
if aFont = missing value then return false
  
  
set aSet to aFont’s coveredCharacterSet()
  
  
set aList of spdF to {}
  
  
repeat with i from 1 to 65535
    set aRes to (aSet’s characterIsMember:i) as boolean
    
if aRes = true then
      set the end of aList of spdF to (string id i)
    end if
  end repeat
  
  
return length of (aList of spdF)
  
end countDefinedCharactersInFont

–指定Postscript名称のフォントに定義されている文字を返す
on retDefinedCharactersInFont(fontName as string)
  
  
script spdG
    property aList : {}
  end script
  
  
set aFont to current application’s NSFont’s fontWithName:fontName |size|:24.0
  
set aSet to aFont’s coveredCharacterSet()
  
  
set aList of spdG to {}
  
  
repeat with i from 1 to 65535
    set aRes to (aSet’s characterIsMember:i) as boolean
    
if aRes = true then
      set the end of aList of spdG to (string id i)
    end if
  end repeat
  
  
return (aList of spdG)
  
end retDefinedCharactersInFont

on listToStringUsingTextItemDelimiter(sourceList, textItemDelimiter)
  set the CocoaArray to current application’s NSArray’s arrayWithArray:sourceList
  
set the CocoaString to CocoaArray’s componentsJoinedByString:textItemDelimiter
  
return (CocoaString as string)
end listToStringUsingTextItemDelimiter

★Click Here to Open This Script