Menu

Skip to content
AppleScriptの穴
  • Home
  • Products
  • Books
  • Docs
  • Events
  • Forum
  • About This Blog
  • License
  • 仕事依頼

AppleScriptの穴

Useful & Practical AppleScript archive. Click '★Click Here to Open This Script' Link to download each AppleScript

自然言語テキストから複数の日付情報を抽出

Posted on 1月 21, 2020 by Takaaki Naganoya

自然言語テキストから日付の情報(複数可)を抽出するAppleScriptです。

URLやメールアドレスの抽出では、複数のデータをNSDataDetectorで抽出するAppleScriptは書いてありましたが、日付情報の抽出を行うものはなかったので、書いておきました。

AppleScript名:自然言語テキストから複数の日付情報(複数)を抽出して日付のリストを返す.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/21
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set theDate to getDatesIn("本テキストには次の火曜日という日付情報を含んでいる。明日かもしれない。次の木曜日もそうだ。") of me
–> {date "2020年1月28日 火曜日 12:00:00", date "2020年1月22日 水曜日 12:00:00", date "2020年1月23日 木曜日 12:00:00"}

set theDate to getDatesIn("This text contains next Tuesday. The date may be tomorrow. Next Wednesday happen.") of me
–> {date "2020年1月28日 火曜日 12:00:00", date "2020年1月22日 水曜日 12:00:00", date "2020年1月29日 水曜日 12:00:00"}

on getDatesIn(aString)
  set anNSString to current application’s NSString’s stringWithString:aString
  
set theDetector to current application’s NSDataDetector’s dataDetectorWithTypes:(current application’s NSTextCheckingTypeDate) |error|:(missing value)
  
set theMatchs to theDetector’s matchesInString:anNSString options:0 range:{0, anNSString’s |length|()}
  
if theMatchs = missing value then error "No date found with String:" & aString
  
set dRes to theMatchs’s valueForKeyPath:"date"
  
return dRes as list
end getDatesIn

★Click Here to Open This Script 

AppleScript名:自然言語テキストから複数の日付情報(複数)を抽出して日付と当該箇所のリストを返す v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/21
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set theDate to getDatesAndOrigStringsIn("本テキストには次の火曜日という日付情報を含んでいる。明日かもしれない。次の木曜日もそうだ。") of me
–> {{originalStr:"次の火曜日", detectDate:date "2020年1月28日 火曜日 12:00:00"}, {originalStr:"明日", detectDate:date "2020年1月22日 水曜日 12:00:00"}, {originalStr:"次の木曜日", detectDate:date "2020年1月23日 木曜日 12:00:00"}}

set theDate to getDatesAndOrigStringsIn("This text contains next Tuesday. The date may be tomorrow. Next Wednesday happen.") of me
–> {{originalStr:"next Tuesday", detectDate:date "2020年1月28日 火曜日 12:00:00"}, {originalStr:"tomorrow", detectDate:date "2020年1月22日 水曜日 12:00:00"}, {originalStr:"Next Wednesday", detectDate:date "2020年1月29日 水曜日 12:00:00"}}

on getDatesAndOrigStringsIn(aString)
  set anNSString to current application’s NSString’s stringWithString:aString
  
set theDetector to current application’s NSDataDetector’s dataDetectorWithTypes:(current application’s NSTextCheckingTypeDate) |error|:(missing value)
  
set theMatchs to theDetector’s matchesInString:anNSString options:0 range:{0, anNSString’s |length|()}
  
if theMatchs = missing value then error "No date found with String:" & aString
  
set dRes to (theMatchs’s valueForKeyPath:"date") as list
  
set rRes to (theMatchs’s valueForKeyPath:"range") as list
  
  
set allRes to {}
  
set aLen to length of dRes
  
repeat with i from 1 to aLen
    set aSubStr to (anNSString’s substringWithRange:(item i of rRes))
    
set dDate to contents of item i of dRes
    
set the end of allRes to {originalStr:aSubStr as string, detectDate:dDate}
  end repeat
  
  
return allRes
end getDatesAndOrigStringsIn

★Click Here to Open This Script 

Posted in Calendar Natural Language Processing | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy NSDataDetector NSString | Leave a comment

Blogアーカイブ本 vol.6を販売開始

Posted on 1月 21, 2020 by Takaaki Naganoya

一部の本Blog愛読者の方々からのご要望にお応えして(慣用句)、ここにBlogアーカイブ本のVol.6(2015年)の発売をお知らせいたします。旧BlogのDBダンプからデータを取り出して、2015年11月分までしか残っていなかったので、旧Blogのアーカイブ本はこれが最終巻になります。

→ オンライン販売ページ
→ お試し版ダウンロードページ

本Blog「AppleScriptの穴」は、開設10年目を迎える直前の2018年1月末に、格安ホスティングサービス「Xserver」との間の手違いでDBがシャットダウンされ、そのままの形で公開し続けることができなくなってしまいました。

そこで、AppleScriptのプログラムによるFinder上のAppleScriptの自動HTML化、AppleScriptによるXML-RPC経由でのWordPressへの自動記事投入といったさまざまなソリューションを投下して、現在の登録記事数に復旧。自動記事投入による復旧を行なったために、当時の作業環境でオープンできない(OSバージョン依存、アプリケーション依存)Scriptについては掲載を見送っています。

 旧AppleScriptの穴:2008〜2018年 Mac OS X 10.4〜10.5の時代に開設
 現AppleScriptの穴:2018年〜   Cocoa APIを呼びまくる現在のスタイルが定着

自動投入可能なコンテンツを優先して掲載したため、旧Blogと現Blogでは掲載内容が大幅に変わっています。別物といってよいでしょう。

そのため、Cocoa APIを使用しない「オールドスタイルのAppleScript」(とくに昔のバージョンのアプリケーション依存)については再掲載が難しく、このBlogアーカイブ本シリーズにしか情報をまとめていません。

旧Blogアーカイブ本シリーズも、1年ごとに区切って記事をPDF化して6冊目。Vol.6は2015年1〜12月の1年分の内容をまとめています。全383ページ、2,000円。

ファイル形式はPDFで、キーワードによる全文検索や印刷が行えます。本文からリンクしているXcodeプロジェクトのダウンロードリンクも新たに現行Blogにアップロードしたアーカイブにリンクし直しています。

もちろん、各プログラムリスト末尾にURLリンクをそなえ、ワンクリックでプログラム内容をスクリプトエディタに転送可能です。

ほとんどの掲載プログラムについてコメントを行い、現時点(2020年時点)で評価してどうか、ということを追記しています。

AppleScriptの穴Blogアーカイブvol.6

ASObjCExtras ICU Transformのサンプル
(Free) ASObjCExtras Scripting Guide
Display情報の取得
2Dリストから、指定アイテムNoで、指定データが該当する最初のものを返す v3
指定したアプリケーションの各lproj内の各stringsファイルのパス一覧を取得する
2月1日が日曜日でうるう年ではないかチェック(ASOC)
カレンダー.app(旧称iCal)で選択中のイベントの情報を取得
起動中のプロセスの存在確認
起動中のプロセスの存在確認(ASOC)v2
Photoshop Action Setをインストールする
現在地点の緯度経度情報を取得する
CSVファイルをListにParseする(ASOC)
CSVファイルをListにParseする(ASOC) 2
errorのpartial resultとは?
レコードとレコードの連結
同スコアを考慮した順位決定
公開添削:サーバー上のファイル権限をローカルで書き換えて書き戻し
ASOCで基礎的な文字列比較
ASOCで基礎的な文字列比較 2
文字列同士が同じかチェック(大文字,小文字の差異を考慮したり無視したり)
Umlautを無視した文字列比較
ASOCで数値文字の比較
POSIX pathで与えられたパスの親フォルダを求める(末尾にスラッシュ添付)
DiskSpaceを求める
CocoaでDisk Free Space (Bytes) を求める
写真.app(Photos.app)のScript対応機能は未完成
OS X 10.10.3のdelayに(新たな)バグ? マウスカーソルの移動でdelayがキャンセルされる
Spotlight検索インデックスを再生成
2015/5
Mailで選択中のMessageの添付ファイルをデスクトップに保存
Mailで有効なmailアカウントの新規メール取得を強制的に有効にする
メモリー解放?
OS X 10.11, El Capitanが発表に
バージョン番号文字列からメジャーバージョンを取り出し数値として返す v4
SafariのWebViewへのGUI Scripting的な参照を取得する v2
URLByAppendingPathComponentのじっけん
指定のURLのYouTubeのムービーをOffLiberty経由でローカルにダウンロード
Finderで選択中の戦場の絆のリプレイムービーのファイル名を取得して対戦人数を集計する
JSON文字列とrecordの相互変換
ASOCでレコードのリストをユニーク化
ASOCでbase64エンコード、デコード
ASOCでバージョン番号文字列の正確な比較
ASOCでbase64エンコード、デコード v2
ASOCでNSStringをas stringでcastすると問題が出るバグの検証
指定の画像を別形式に変換する
現在のLocaleのIdentifier文字を取得する
ASOCで数値を指定桁でゼロパディング
指定の画像を別形式に変換する v2
指定の画像を別形式に変換する v3
フォルダアクションの操作
CPUの詳細な型番を取得する
使用中のMacの製品呼称を取得する
使用中のMacの製品呼称を取得する v2
ASOCで少数点以下の数値の切り上げ、切り下げ
ASOCでScript Editorの構文色分け情報を設定ファイルから取り出す v2
ASOCで少数点以下の数値の切り上げ、切り下げ v2
ASOCでRTFの内容を読み取って指定文字を置換してファイルに保存する
ASOCで与えられた画像ファイルがNSImageでハンドリング可能かを取得
ASOCで無線LANの各種情報を取得する
ASOCで無線LANの各種情報を取得する v2
ASOCで動的にWindowを作成
El Capitanの各Apple純正ツールのAppleScript用語辞書の変更度合い
ASOCで各種文字列からdate objectに変換 ほかNSDataDetectorの活用
NSDataDetectorを用いてテキストから各種データを抽出
MacのHardware UUIDを取得する
ASOCで性別と言語コードを指定してTTS voiceを取得 v2
ASOCでHostの情報を取得する
ASOCでNSLocaleのじっけん
100%クラッシュするNSCalendarの操作
NSTimeZoneのじっけん
ASOCでNSFont,NSFontManagerのじっけん
ASOCでプロセス関連のじっけん
ASOCでspotlight検索するじっけん
ASOCで文字を逆順に
ASOCでspotlight検索するじっけん v2
秒以下の時間待ちを検証
エラートラップのpartial result
メールアドレスの妥当性チェック
URLの妥当性チェック
URLからドメイン名を抽出
指定URLをロードしてtitleを取得
メーラーから取得したメールアドレスのうち純粋なアドレス部分を抽出 v2
現在実行中のプロセスの情報を取得
続・伏字文字列を作成する
指定URLのファイルをダウンロード
テキストの言語を推測する
与えられたテキストの言語を自動判別して対応する言語のTTS Voiceで読み上げ
マルチバイト文字の検出、の落とし穴
NSCountedSetでNSDictionaryの登場頻度集計
指定URLをロード WKWebView版
クリップボードの内容をRTFとPDFで書き出す
spotlightでタグを指定して検索
NSPredicateによる正規表現を利用した部分一致抽出
BridgePlus 1.2のframeworkの新機能テスト(1)
多国語OCR「FineReader OCR Pro」をAppleScriptでコントロール
指定フォルダのファイルパス一覧取得(拡張子指定つき)
続・指定フォルダのファイルパス一覧取得(拡張子指定つき)
文字エンコーディングを自動判別して日本語テキストファイル読み込み v1.2.1
マウスカーソルの強制移動とクリック
XML-RPCのテスト
数字以外を削除して返す
テキストとリストの変換
iWorkアプリがアップデート、AppleScript対応機能が強化される
PDFメディアサイズの取得(単位:Point)
指定ファイルに指定アイコン画像をつける
PDFの各種情報を取得する
指定ファイルのアイコン画像を取得する
アプレットのアイコンをDockに出さない
ASOCによるファイルの移動
Keynote 6.6のじっけん(3)〜表を作成してデータで埋める
指定フォルダ内のフォルダのみを取得する
Foundationのバージョンを取得する
NSErrorを生成する
Systemのアラートサウンド名称を取得して鳴らす v2
ムービーからオーディオのみ抽出してm4aで保存 v2
Safariと同じUser Agent文字列を組み立てる
Safariでアクセス中のページが設定しているCookieの値を求める
文字列のURLエンコード、デコード
iWorkアプリがアップデート。AppleScript関連の機能変更はなし
PEGKitのじっけん
Cocoaオブジェクトのクラス名を文字列で取得

Posted in PRODUCTS | Leave a comment

Numbersで書類Aのすべてのシートの表1を、書類Bの現在のシートの表1にまとめる

Posted on 1月 21, 2020 by Takaaki Naganoya

Numbersでオープン中の複数の書類があったときに、書類Aのすべてのシートの表1を、書類Bの現在のシートの表1にまとめるAppleScriptです。

さすがに、機械的な作業すぎて手で行う気にはなれなかったので、ありもののScriptを利用して作ってみました。

こういう用途のために作っておいたライブラリ「choose multiple list」を利用しています。


▲データ取得元


▲データ集約先


▲ダイアログで「データ取得元」と「データ集約先」を選択

BridgePlus内蔵のFrameworkがmacOS 10.14/10.15に邪魔されて認識されない環境では動かせないかもしれません。このあたり、SIP解除するしかないと思わせるものがあります。

ライブラリで複雑な選択を行えるUI部品を作っておいたおかげで、これだけ込み入った動作を行うAppleScriptを書きましたが、Cocoaの機能はほぼ使っていません(getDataFromNumbersDocは作り置きしておいた、頻出ルーチンなので使いまわしています)。choose multiple listライブラリは、こういう用途のために作っておいたものであり、まさにそのぴったりな用途であったといえるでしょう。

AppleScript名:書類Aのすべてのシートの表1を、書類Bの現在のシートの表1にまとめる.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/20
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.7" — High Sierra (10.13) or later
use framework "Foundation"
use scripting additions
use bPlus : script "BridgePlus"
use mulList : script "choose multiple list"

script spd
  property allData : {}
end script

set (allData of spd) to {}

set {aName, bName} to getTargetDocNames() of me

–「データ取得元」のNumbers書類のすべてのシートの表1から2D Listでデータ取得
tell application "Numbers"
  tell document aName
    set sList to name of every sheet
    
repeat with i in sList
      set tmp2DDat to getDataFromNumbersDoc(aName, i) of me
      
set (allData of spd) to (allData of spd) & tmp2DDat
    end repeat
  end tell
end tell

set aHeight to length of (allData of spd)
set aWidth to length of item 1 of (allData of spd)

–「データ集約先」のNumbers書類の現在のシートの表1にまとめた2D Listを展開する(巨大すぎると時間がかかるので、CSV書き出ししてオープンするなどの別の方法を採るべき)
tell application "Numbers"
  tell document bName
    tell active sheet
      set tRes to make new table with properties {row count:aHeight + 1, column count:aWidth}
    end tell
  end tell
end tell

fillCurrentTable(bName, (allData of spd)) of me

–Numbersの書類の現在のシートを、指定の2次元配列でfillする
on fillCurrentTable(docName, aList)
  set aLen to length of aList
  
set aWidth to length of first item of aList
  
  
tell application "Numbers"
    tell document docName
      tell active sheet
        tell table 1
          repeat with i from 1 to aLen
            tell row (i + 1)
              set aRowList to contents of item i of aList
              
repeat with ii from 1 to aWidth
                tell cell ii
                  set aTmpData to contents of item ii of aRowList
                  
ignoring application responses
                    set value to aTmpData
                  end ignoring
                end tell
              end repeat
            end tell
          end repeat
        end tell
      end tell
    end tell
  end tell
end fillCurrentTable

–Numbersでオープン中の書類の名称一覧からデータ取得元とデータ集約先の書類名をダイアログで選択
on getTargetDocNames()
  tell application "Numbers"
    set nList to name of every document
  end tell
  
  
set selList to {nList, nList}
  
set tList to {"データ取得元", "データ集約先"}
  
  
set {aRes, bRes} to choose multiple list selList main message "各Numbers書類の役割を選択してください" sub message "「データ取得元」のデータを順次、「データ集約先」の表1に連結します" with title lists tList height 140 width 400 return type item contents without allow same items
  
return {aRes, bRes}
end getTargetDocNames

–Numbersでオープン中の書類の選択中のシートの表1からデータを取得して2D Listに
on getDataFromNumbersDoc(aDocName, sheetName)
  
  
load framework
  
  
tell application "Numbers"
    if (count (every document)) = 0 then return false
    
    
tell document aDocName
      if (count (every sheet)) = 0 then return false
      
      
tell sheet sheetName
        tell table 1
          set colCount to column count
          
set rowCount to row count
          
set headerCount to header row count
          
set footerCount to footer row count
          
          
set dList to value of every cell of cell range
        end tell
      end tell
      
    end tell
  end tell
  
  
–Convert 1D List to 2D List
  
set bList to (current application’s SMSForder’s subarraysFrom:dList groupedBy:colCount |error|:(missing value)) as list
  
set sItem to 1 + headerCount
  
set eItem to rowCount – footerCount
  
set cList to items sItem thru eItem of bList
  
  
return cList
  
end getDataFromNumbersDoc

★Click Here to Open This Script 

Posted in dialog GUI list | Tagged 10.13savvy 10.14savvy 10.15savvy Numbers | Leave a comment

サーバーメンテナンスが行われます

Posted on 1月 20, 2020 by Takaaki Naganoya

2018年1月にDBをふっとばしてくれたホスティング業者「Xserver」をまだ使っているわけですが、日本標準時(JST)で2020年1月21日 AM2:00〜AM8:00ごろまで、データセンター内の回線増強にともない10分から60分程度、本サイトにアクセスできなくなる見通しです。

その間は、本サイトを通じて配布している各種AppleScriptライブラリのsdefに入れている画像やムービーなどが見えなくなります。

Posted in news | Leave a comment

BlogアーカイブのMarkdown書類をリネーム。親、親+1階層フォルダをMM, YYYYとみなして反映

Posted on 1月 19, 2020 by Takaaki Naganoya

Finderで選択中のファイルすべてに対して、親フォルダ名、親+1階層のフォルダ名を反映させたファイル名をつけるAppleScriptです。

Blogアーカイブ本を作るのに、こうした道具を作って使っています。一度書いておけば、2度目からは大幅に時間を短縮できます。最初のファイルから拡張子を取得してそれを後続のファイルすべてに適用するため、同一種類のファイルである必要があります。自分用のツールならではの手抜きといったところでしょうか。

AppleScript名:BlogアーカイブのMarkdown書類をリネーム。親、親+1階層フォルダをMM, YYYYとみなして反映 .scptd
— Created 2020-01-18 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

–選択ファイルを取得
tell application "Finder"
  set aSel to selection as alias list –Select documents to Rename
end tell

set aCount to 10 –start
set aStep to 10
set aDigit to 3

–パス情報を取得
set aFirst to first item of aSel
set aPOSIX to POSIX path of aFirst
set aPathStr to (current application’s NSString’s stringWithString:aPOSIX)
set aDateComList to aPathStr’s pathComponents() –ディレクトリごとにパス情報を分割してリスト化
set aExt to aPathStr’s pathExtension() –拡張子

set aYear to (item -3 of aDateComList) as string –親の親フォルダ名
set aMonth to (item -2 of aDateComList) as string –親フォルダ名

–リネーム(数百項目を超える場合にはFinderでは遅すぎるのでNSFileManagerで処理)
tell application "Finder"
  repeat with i in aSel
    set aTEXT to numToZeroPaddingStr(aCount, aDigit, "0") of me –3 digit
    
set aName to aYear & aMonth & aTEXT & "." & aExt
    
set name of i to aName
    
set aCount to aCount + aStep
  end repeat
end tell

–整数の値に指定桁数ゼロパディングして文字列で返す
on numToZeroPaddingStr(aNum as integer, aDigit as integer, paddingChar as text)
  set aNumForm to current application’s NSNumberFormatter’s alloc()’s init()
  
aNumForm’s setPaddingPosition:(current application’s NSNumberFormatterPadBeforePrefix)
  
aNumForm’s setPaddingCharacter:paddingChar
  
aNumForm’s setMinimumIntegerDigits:aDigit
  
  
set bNum to current application’s NSNumber’s numberWithInt:aNum
  
set aStr to aNumForm’s stringFromNumber:bNum
  
  
return aStr as text
end numToZeroPaddingStr

★Click Here to Open This Script 

Posted in file File path list Markdown Text | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy Finder NSNumber NSNumberFormatter NSNumberFormatterPadBeforePrefix NSString | Leave a comment

osascript系のAppleScriptランタイムを区別する

Posted on 1月 18, 2020 by Takaaki Naganoya

AppleScriptのランタイム環境が何であるかを区別できるようになりました。

それらのうち、/usr/bin/osascriptを呼び出しているランタイム環境について、さらに細分化して個別に識別するために、ランタイム環境そのものと親プロセスが何であるかをAppleScriptで調査してみました。

結論からいえば、親プロセスが「bash」ならTerminalからosascriptコマンドで起動されたと判断してよさそう。その他は、実行されたScriptの置かれているパスを求めて、macOS標準装備のScript Menuかアプリケーション内部のScript Menuかを見分けるぐらいでしょうか。

これを判定したプログラム自体は、別に技術的にすごいとか機密の塊とかいうことはなくて、「清書してなくて、きたない。無駄に長い。掲載されているプログラムを見ても何も感じない」ことから掲載していません。実験用のテストプログラムでも、ちょっと近年稀に見るぐらいひどい出来です。内容は、単にランタイムプログラムのプロセスIDを取得して、そのプロセスIDをもとにpsコマンドで親プロセスを求めて、コマンドからいろいろ情報を抜いてくるというだけのものです。

Script Menu

ランタイムのパラメータ:/usr/bin/osascript -P /Users/me/Library/Scripts/Finder/pTEST.scptd
親プロセス:/System/Library/Frameworks/Foundation.framework/Versions/C/XPCServices/com.apple.foundation.UserScriptService.xpc/Contents/MacOS/com.apple.foundation.UserScriptService

与えられているScriptが特定フォルダ(/Users/me/Library/Scripts/)以下にあるものかどうか、という識別は可能。ちょっと、根拠が弱そうです。

CotEditor内のScript Menu

ランタイムのパラメータ:/usr/bin/osascript -sd -T 14534 -P /Users/me/Library/Application Scripts/com.coteditor.CotEditor/010)M-pM^_M^MM^NM-pM^_M^SM^\AppleScriptM-cM^AM-(M-cM^AM^WM-cM^AM-&M-hM-'M-#M-iM^GM^H/0020)M-pM^_M^SM^\M-fM-'M^KM-fM^VM^GM-gM-"M-:M-hM-*M^MM-cM^AM^WM-cM^AM-&M-eM-.M^_M-hM-!M^LM-cM^AM^WM-cM^@M^AM-pM^_M^SM^DM-fM^VM-0M-hM-&M^OM-fM^[M-8M-iM-!M^^M-cM^AM-+M-gM-5M^PM-fM^^M^\M-cM^BM^RM-eM^GM-:M-eM^JM^[.@r.scpt
親プロセス:/System/Library/Frameworks/Foundation.framework/Versions/C/XPCServices/com.apple.foundation.UserScriptService.xpc/Contents/MacOS/com.apple.foundation.UserScriptService

親プロセスはScript Menuと同じですが、こちらも実行しているScriptのパスが/Users/me/Library/Application Scripts/com.coteditor.CotEditor/以下であること。これも、識別のための根拠が弱いです。

Terminal経由でosascriptコマンド実行

ランタイムのパラメータ:osascript /Users/me/Desktop/pTEST.scptd
親プロセス:-bash

これは、親プロセスが-bashであることから、明確に区別できます。Terminal.appではなくbashなんですね。

Terminal経由で/usr/bin/osascript(フルパス指定)でコマンド実行

ランタイムのパラメータ:/usr/bin/osascript /Users/me/Desktop/pTEST.scptd
親プロセス:-bash

フルパスで指定すると何か変わってくるかとも思いましたが、とくに変化はありませんでした。

Program AS Style runtime name Parent Process Name Script Path
Script Editor Script/Scriptd Script Editor
Script Editor Cocoa-AppleScript Applet CocoaApplet
Script Editor Applet applet
Script Debugger Script/Scriptd Script Debugger
Script Debugger Applet (Enhanced) FancyDroplet
ASOBjC Explorer 4 Script/Scriptd ASOBjC Explorer 4
Automator Workflow Automator
Automator Applet Application Stub
Script Menu Script/Scriptd osascript …com.apple.foundation.UserScriptService /Users/me/Library/Scripts/ ほか
CotEditor Script osascript …com.apple.foundation.UserScriptService /Users/me/Library/Application Scripts/com.coteditor.CotEditor/
Terminal.app (osascript) Script/Scriptd osascript bash
Posted in OSA shell script | Tagged 10.14savvy | Leave a comment

AppleScriptを実行中のランタイムプログラム名を取得する

Posted on 1月 18, 2020 by Takaaki Naganoya

AppleScriptのランタイムプログラム名(ランタイム名)を取得するAppleScriptです。AppleScript自身が「何によって」実行されているか、その実行プログラム名を取得するものです。

AppleScriptには何種類かランタイム環境が存在し、ランタイム環境ごとに若干の動作が変わってくることが知られています。

ランタイム環境ごとにどこが違うといえば、Finderからのselectionを取得できるとかできないとか(AppleScript Studioがこれに該当。もうありませんけれども)、GUI Scriptingの権限の認証を得られるとか得られないとか。ウィンドウを動的に生成して表示したときに最前面に表示できるとかできないとか(Script Menuがこれに該当)。明示的にメインスレッドで実行する機能がないとか(Script Debuggerがこれに該当)。そういうところです(ほかにもあるかもしれない)。

過去に作ったAppleScriptを確認していたところ、プロセス名を取得するだけの使えないプログラムだと思っていたものが、実は「ランタイムプログラムのプログラム名」を取得できるというスゲーものであることを再発見しました。

ながらく、ランタイムプログラム名をAppleScript側から取得する必要性を感じていたため、この機会に調べてみることに。プログラム自体は些細な(↓)ものです。

AppleScript名:ランタイム環境名の表示
— Created 2015-09-08 by Takaaki Naganoya
— 2015 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set procInfo to current application’s NSProcessInfo’s processInfo()
set aName to procInfo’s processName() as string
display dialog aName

★Click Here to Open This Script 

Script Editor上で実行


–> “Script Editor”

Script Debugger上で実行


–> “Script Debugger”

ASObjC Explorer 4上で実行


–> “ASObjC Explorer 4”

Automator上で実行


–> “Automator”
これには驚きました。特別のランタイムプログラムが使われているのか、それとも単に親プロセスとしてのAutomatorが返ってきているのかは不明ですが、識別できるということには意義がありそうです。

Script Menu上で実行


–> “osascript”
これは、よく知られていることなのでとくに驚きはありません。テストを実施したのはmacOS 10.14.6上で、Script Menuは「スクリプトメニュー」という別アプリケーション(/System/Library/CoreServices/ にある)に変更になったOSバージョンですが、ランタイムにosascriptを使い続けていることを確認することになりました(それ以前のOSと挙動が同じなのでそうだと思っていましたけれども)。

Folder Action上で実行




–> “osascript”
Folder Actionは、macOS標準搭載のフォルダ監視機能です。監視対象のフォルダにファイルが追加されたり、移動されたり、フォルダそのものがオープンしたりするとその対象ファイル/フォルダで指定のAppleScriptを実行します。よく、ドラッグ&ドロップで処理を受け付けたり、ネットワーク経由でファイルを受信した場合にAppleScriptを実行するような使われ方をします。
Folder Action Disptcherが実行しているとばかり思っていたのですが、実際に確認したらosascriptでした。ちなみに、Folder ActionはmacOS 10.11でフルに書き換えられてそれ以前とは別物になっています。以前は数秒に一度対象フォルダをチェックする方式でしたが、10.11以降はFSEventsを利用して随時監視対象フォルダへの変更を受け付けます。

Switch Control上で実行



–> “osascript”
障害者向けの機能としてmacOSに標準装備されている、フローティングパレットからAppleScriptを呼び出せる機能である「Switch Control」。手を使わずに操作したり、他のコントローラで操作するような標準的ではない使い方をサポートするための機構ですが、普通に普通の人が使っても役立ちます。 
Switch ControlでAppleScriptを実行する場合のランタイムプログラムはosascriptです。

CotEditor上で実行


–> “osascript”
これは、CotEditorのソースを読んで確認してありました。ここだけ割と手抜き実装ですが、それでも複数のOSA言語に対応できたりと機能的には悪くはありません。むしろ、osascript側のランタイム環境が他の環境よりも一段落ちることに問題が、、、、GUI Scriptingの権限を取得できないこととか、このCotEditorのメニューから実行するとREST APIが呼び出せないとか。同じosascript系でもScript Menuのほうが制約が少ないのは、おそらくアプリケーション自体に許可されている条件の違いによるものでしょう。

FileMaker Pro上でスクリプトステップ「AppleScriptを実行」を実行


–> “FileMaker Pro”
FileMaker Proはランタイムアプリケーションが廃止され、FileMaker Pro AdvancedもFileMaker Proに一本化されたので、v19以降はFileMaker Proは「FileMaker Pro」というランタイムのみでしょう。v19でもFileMaker Pro自体はSandbox化されていないため、微妙にセキュリティ上の制約が少ない=自由度の高いランタイム環境として残っていくことでしょう。

Script EditorからApplet書き出しして実行


–> “applet”
取得できたらいいなぐらいの気持ちで試してみたものの、これが識別できるのはうれしい誤算です。書き出したAppleScript Applet名は「Appletでランタイム名を取得」であったため、この「applet」というものとは異なります(ねんのため)。

AutomatorからApplet書き出しして実行


–> “Application Stub”
見たことのない名前が、、、、やっぱり、これも別ランタイムなんですね、、、、

Script DebuggerからApplet(Enhanced)で書き出しして実行


–> “FancyDroplet”
Appleの標準ランタイムとはあきらかに別物(Enhanced)なので、たぶん別の名前がついているだろうとは思っていましたが、そういう名前でしたか。名前が予想外だったので驚かされましたが、識別できることに意義があります。

Cocoa-AppleScript Appletを実行


–> “CocoaApplet”
Script Editor上で作成できる、通常のAppleScriptとXcode上で作成するCocoa-Applicationの中間的な性格を持つ「Cocoa-AppleScript Applet」でランタイムプログラム名を取得したらこうなりました。

もちろん、実行プログラム名はまったく別の「ランタイム名を表示するだけのCocoa-AppleScript Applet」というものです。

ショートカットで「AppleScriptを実行」アクションを実行


–> “MacHelper”

macOS 12で搭載されたショートカット.app(Shortcuts.app)および不可視プロセスのAppleScriptの補助専用アプリケーション「Shortcuts Events.app」上で、アクション「AppleScriptを実行」でAppleScriptを実行するときのランタイム名は、「MacHelper」です。意外なところで、ユーザーディレクトリ以下にインストールされたAppleScriptライブラリをこのMacHelper環境は認識します。

→ macOS 13上では、ショートカット.app(Shortcuts.app)およびShortcuts Events.app上のランタイム名が「ShortcutsMacHelper」に変更されました。

RedSweater Software「FastScripts」からAppleScriptを実行

red sweater softwareによるメニュー常駐型Script Menuソフトウェア「FastScripts」から実行したときのランタイム名は「FascScripts Script Runner」です。

Knurling Group「Service Station」からAppleScriptを実行

Knurling Groupによるコンテクストメニューのカスタマイズ・ソフトウェア「Service Station」から実行したときのランタイム名は「osascript」です。

ランタイム名が得られることで実現できること

これらのほか、各アプリケーション内でAppleScript呼び出し機能を有するもの(ファイルメーカー、Mail.appなど)でランタイムプログラム名を取得すると有益な情報が得られることでしょう。

これは、地球上にいる人類が観測衛星を打ち上げて「ここは銀河系だ」と観測できるぐらいすごいことなので、割と意義深いものです。実行中のAppleScriptが、「いま、何のプログラムによって自分自身が実行されている」かという情報を取得できます。

ランタイムプログラムの名称取得については、いくつかのAppleScript実行方法を試してみましたが、得られる名前に違いがないことを確認しています。

直接AppleScriptを動かす方法に加え、間接的にAppleScriptを動かす方法も試してみましたが、同じ結果が得られました。

つまり、動的にOSAScriptViewを生成して実行しようが、NSAppleScriptで実行しようが、AppleScriptの「run script」コマンドで実行しようが、取得されるランタイム名には差がありません。

これで、ランタイム環境のプロセスの親プロセスの情報が取得できると、Terminal.app上から起動したosascriptコマンドで呼び出したのか、Script Menu上から呼び出したのかという状況をAppleScript側で認識できることになることでしょう。

ランタイム環境を識別した上で、各環境で実行できない処理を行わないとか、ランタイム環境ごとに処理を分岐できるようになることでしょう。

ちょうど、Edama2さんと「ランタイム環境ごとに若干の挙動の違いが見られるし、利用できるCocoaの機能にも違いがあるから、ランタイム環境ごとに認識コードでも振ってみようか」などと相談していたので、渡りに船でした。

Posted in OSA | Tagged 10.13savvy 10.14savvy 10.15savvy Automator CotEditor Script Debugger Script Editor | Leave a comment

display drop dialog Script Library

Posted on 1月 16, 2020 by Takaaki Naganoya

指定UTIのファイルのFinderからのドラッグ&ドロップを受け付けるAppleScript Libraries「display drop dialog」をリリース、フリー配布いたします。

# 本ライブラリはEdama2さんのScriptに若干の改変を行い、sdefをつけてパラメータのエラー処理を行い、コードサインしてライブラリ化したものです

–> Download display drop dialog Script Library (To ~/Library/Script Libraries/)

本ライブラリは、指定UTIの書類のドラッグ&ドロップを受け付けるダイアログをAppleScriptから手軽に使えるようにするものです。macOS 10.14以降で動作します。

現在のAppleのTim Cook体制は、セキュリティ強化の美名のもとに「動かないコンピュータ」を目指し、各種機能を阻害する方向に進んでいます。

AppleScriptの世界はその中でも自由度が比較的高い状態にありますが、それでもmacOS 10.12以降では、AppleScriptドロップレットにFinderからドラッグ&ドロップしても、Finderの拡張属性(Xattr)がついたファイルは無視されたりと、なかなか困ります。

そこで、Finderからのドラッグ&ドロップ操作を通常の(Applet書き出ししていない)AppleScript、とくにScript Menuから呼び出す形式のAppleScriptで使えるようにすることを目的として本ライブラリを作成しました。

本ライブラリを用いることで、ドロップレットを作らなくても、Script Menuから呼び出した普通のAppleScriptにファイルのドラッグ&ドロップの受信機能を追加できます。セキュリティと機能性(ドラッグ&ドロップ)を両立させるため、すべてのScripterに欠かすことのできないライブラリになるものと期待しています。

本ライブラリのAppleScript用語辞書には実行イメージ(画面キャプチャ)およびサンプルScriptを入れてあり、実行時の様子やサンプルスクリプト(本Blogと同様のワンクリックで内容が転送されるリンクつき)を確認できるようになっています。

AppleScript名:accept AppleScript documents
use dropLib : script "display drop dialog"

set aMainMes to "Drop AppleScript"
set aSubMes to "Drag and Drop AppleScript files here"
set aUTI to "com.apple.applescript.script"
set execButtonTitle to "Execute"
set aRes to (display drop dialog aUTI main message aMainMes sub message aSubMes with initial folder "" OK button title execButtonTitle)
–> {alias "Machintosh HD:Users:me:Documents:display drop dialog:accept PNG images.scpt", alias "Machintosh HD:Users: me:Documentsaccept Markdown documents.scpt"}

★Click Here to Open This Script 

AppleScript名:accept Markdown documents
use dropLib : script "display drop dialog"

set aMainMes to "Drop Markdown Documents"
set aSubMes to "Drag and Drop Markdown documents here"
set aUTI to "net.daringfireball.markdown"
set execButtonTitle to "Execute"
set aRes to (display drop dialog aUTI main message aMainMes sub message aSubMes with initial folder "" OK button title execButtonTitle)
–> {alias "Machintosh HD:Users:me:Documents::–Book 11 「Blog Archives vol5 2013-2014」:2013:01:201301013.md", alias "Machintosh HD:Users:me:Documents::–Book 11 「Blog Archives vol5 2013-2014」:2013:01:201301012.md"}

★Click Here to Open This Script 

AppleScript名:accept PNG images with initial folder contents
use scripting additions
use dropLib : script "display drop dialog"

set aMainMes to "Drop PNG"
set aSubMes to "Drag and Drop png images here"
set aUTI to "public.png"
set execButtonTitle to "Execute"
set iFolder to path to pictures folder –At first, PNG files in this folder is displayed
set aRes to (display drop dialog aUTI main message aMainMes sub message aSubMes with initial folder iFolder OK button title execButtonTitle)
–> {alias "Machintosh HD:Users:me:Pictures:1015sedhelp2.png", alias "Machintosh HD:Users:me:Pictures:574G01.png", alias "Machintosh HD:Users:me:Pictures:macDown1.png", alias "Machintosh HD:Users:me:Pictures: 2017-09-27 19.33.53.png", alias "Machintosh HD:Users:me:Pictures:2018-11-01 10.54.06.png"

★Click Here to Open This Script 

Posted in dialog GUI PRODUCTS Script Libraries sdef | Tagged 10.14savvy 10.15savvy | Leave a comment

Microsoft Edgeが正式リリース

Posted on 1月 16, 2020 by Takaaki Naganoya

MicrosoftによるGoogle Chrome(オープンソース版のChromium)をベースにした(そのまま)Webブラウザ「Microsoft Edge」の正式版がリリースされました。

ChromiumはAppleScriptに対応しており、ベータ版である「Edge Canary」もChromiumと同様のAppleScript用語辞書を備えていました(A=B)。

正式版「Edge」のAppleScript用語辞書と「Edge Canary」の用語辞書とdiffをとってみたところ、内容が同じであることを確認できました(B=C)。

このため、Google Chromium用のAppleScriptとtell文のアプリケーション名だけ書き換えればEdge用のAppleScriptとして動かせることが期待できます(メニューやボタンを直接動かすGUI Sciriptingをのぞく)。


▲メニュー構成はけっこう違います

Posted in news | Tagged Microsoft Edge | Leave a comment

Blog アーカイブVol.5 rev1.1を公開

Posted on 1月 16, 2020 by Takaaki Naganoya

発売したばかりの「BlogアーカイブVol.5」ですが、画像のリンク抜けがあるとのご報告をいただき、すぐさま修正版をリリースしました。すでにお買い上げの方々におかれましても、再ダウンロードでダウンロードできるはずなので、おためしください。

本件については、画像リンクチェッカーAppleScriptの機能を強化。これまでも、Markdownタグでリンクした画像のリンク抜けについてはAppleScriptで自動チェックを行なっていたのですが、HTMLタグで入れた画像リンクについてはチェック対象外となっていました。

そこで、画像リンクチェッカー「指定ディレクトリ以下のMarkdown書類のリモート画像URLのリンク切れをチェック(Markdown、HTMLタグ両方)」を作成し、自動でMarkdown/HTMLタグで記述された画像リンクチェックを実施。

5か所ほど画像リンク抜けが見つかったので、その点を修正したRev. 1.1をアップロードしました。

表紙と奥付のリビジョン表記が1.0から1.1になっています。

原稿(Pages&Markdown書類)→PDF書き出し→PDF結合→TOC作成 と、ワークフローをAppleScriptで自動化しており、こうしたツールを作ってきたからこそ、たった1人で執筆、編集、発行(販売)を行えるようになっている次第です。

なお、画像リンク抜け以外の箇所はほとんど変わっていませんので、現時点でお手もとにあるPDFで不満のない場合にはそのままでもけっこうです。

Posted in Books PRODUCTS | Leave a comment

Numbersでオープン中の最前面の書類のすべてのシートの表1の行数合計を計算する

Posted on 1月 15, 2020 by Takaaki Naganoya

Numbersでオープン中の最前面の書類のすべてのシートの表1の行数の合計を計算するAppleScriptです。

Blogアーカイブ本作成のために書いたものです。

この記事数をカウントするために使いました。

AppleScript名:Numbersでオープン中の最前面の書類のすべてのシートの表1の行数合計を計算する
set aCount to 0

tell application "Numbers"
  tell front document
    set sList to every sheet
    
repeat with i in sList
      tell i
        try
          set tmpC to count every row of table 1
          
set aCount to aCount + tmpC
        end try
      end tell
    end repeat
  end tell
end tell

return aCount

★Click Here to Open This Script 

Posted in Number | Tagged 10.13savvy 10.14savvy 10.15savvy Numbers | Leave a comment

アラートダイアログ上にTable Viewを表示 v9_アイコンを表示、Finderからのドラッグ&ドロップ

Posted on 1月 15, 2020 by Takaaki Naganoya

Edama2さんからの投稿Scriptです。アラートダイアログ中に各種GUI部品を詰め込む「箱庭インタフェース」シリーズ。テーブルビューを表示して、Finderからのアプリケーションのドラッグ&ドロップを受け付けるAppleScriptです。

–> Download Editable & Executable Script Bundle Document

カスタムクラスの作り方がわかったので、懲りずにTable Viewネタです。
Thanks  Shane Stanley!

アプリケーションフォルダ直下のアプリを、NSValueTransformerを使ってコラムにローカライズ名とアイコンを表示するのと、finderからのドラッグ&ドロップでアイテムの追加です。
追加時に重複チェックをしているので試す時はユーティリティフォルダか別の場所にあるアプリで試してください。

本Scriptは自分も作りたいと思いつつも調査が進んでいなかったものですが、TableViewでFinderからのドラッグ&ドロップを受け付けます。

これを鍛えて再利用しやすい部品に育てることで、ドロップレットの代替品にできると思っています。macOS 10.12以降、Finder上のファイルをAppleScriptドロップレットにドラッグ&ドロップで処理させても、OS側がダウンロードファイルにつけた拡張属性(Xattr)「com.apple.quarantine」がついているとドロップレット側で処理できなかったりします(回避方法はありますけれども)。

このドロップレットという仕組みを使わずに、同様にドラッグ&ドロップによる処理を手軽にできる代替インタフェースとしてこのようなものを考えていた次第です。自分で作らなくてもEdama2さんが作ってくださったので助かりました、、、、

AppleScript名:アラートダイアログ上にTable Viewを表示 v9_アイコンを表示、Finderからのドラッグ&ドロップ
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppleScriptObjC"
use scripting additions

on run
  my main()
end run
on main()
  # Script Bundle内のResourcesフォルダを求める
  
set resourcePath to POSIX path of (path to me) & "Contents/Resources/"
  
set theBundle to current application’s NSBundle’s bundleWithPath:resourcePath
  
theBundle’s loadAppleScriptObjectiveCScripts()
  
  
#
  
set aFolder to path to applications folder
  
set aPath to aFolder’s POSIX path
  
set aURL to current application’s NSURL’s fileURLWithPath:aPath
  
  
# 指定フォルダの直下のファイルを取得
  
set filePaths to current application’s NSFileManager’s defaultManager’s ¬
    contentsOfDirectoryAtURL:aURL ¬
      includingPropertiesForKeys:{current application’s NSURLNameKey} ¬
      
options:(current application’s NSDirectoryEnumerationSkipsHiddenFiles) ¬
      
|error|:(missing value)
  
  
set filePaths to filePaths as list
  
set thisFileType to "com.apple.application-bundle"
  
  
set fileURLs to {}
  
repeat with anItem in filePaths
    
    
set aPath to anItem’s contents’s POSIX path
    
set aURL to (current application’s NSURL’s fileURLWithPath:aPath)
    
    
set {aResult, aUTI, aError} to (aURL’s getResourceValue:(reference) ¬
      forKey:(current application’s NSURLTypeIdentifierKey) ¬
      
|error|:(reference))
    
    
if (aUTI as text) is thisFileType then
      set fileURLs’s end to aURL
    end if
  end repeat
  
  
set optionRec to {fileURLs:fileURLs, fileType:thisFileType}
  
  
set aMainMes to "アプリケーションの選択"
  
set aSubMes to "適切なものを以下からえらんでください"
  
set dateObj to my chooseItemByTableView(aMainMes, aSubMes, optionRec)
end main

# アラートダイアログでtableviewを表示
on chooseItemByTableView(aMainMes, aSubMes, optionRec)
  ### set up view
  
set {theView, makeObj} to my makeContentView(optionRec)
  
  
set paramObj to {myMessage:aMainMes, mySubMessage:aSubMes, setView:theView, myOption:makeObj}
  
my performSelectorOnMainThread:"raizeAlert:" withObject:paramObj waitUntilDone:true
  
  
if (my _retrieve_data) is missing value then error number -128
  
return (my _retrieve_data)
end chooseItemByTableView

## retrieve date
on raizeAlert:paramObj
  set mesText to paramObj’s myMessage
  
set infoText to paramObj’s mySubMessage
  
set theView to paramObj’s setView
  
set aTableObj to paramObj’s myOption
  
  
global _retrieve_data
  
set _retrieve_data to missing value
  
  
### set up alert
  
tell current application’s NSAlert’s new()
    setMessageText_(mesText)
    
setInformativeText_(infoText)
    
addButtonWithTitle_("OK")
    
addButtonWithTitle_("Cancel")
    
setAccessoryView_(theView)
    
tell |window|()
      setInitialFirstResponder_(theView)
    end tell
    
#### show alert in modal loop
    
if runModal() is (current application’s NSAlertSecondButtonReturn) then return
  end tell
  
  
### retrieve date
  
set aIndexSet to aTableObj’s selectedRowIndexes()
  
  
set chooseItems to ((aTableObj’s dataSource())’s arrangedObjects()’s objectsAtIndexes:aIndexSet) as list
  
set _retrieve_data to {}
  
repeat with anItem in chooseItems
    set _retrieve_data’s end to anItem’s fileURL
  end repeat
end raizeAlert:

## ContentView を作成
on makeContentView(paramObj)
  ## 準備
  
set fileURLs to (paramObj’s fileURLs) as list
  
set thisFileType to (paramObj’s fileType) as text
  
  
set keyrec to {column1:"Name"}
  
set keyDict to (current application’s NSDictionary’s dictionaryWithDictionary:keyrec)
  
  
set theDataSource to current application’s YKZArrayController’s new()
  
  
## NSTableView
  
tell current application’s NSTableView’s alloc()
    tell initWithFrame_(current application’s CGRectZero)
      setAllowsEmptySelection_(false)
      
setAllowsMultipleSelection_(true)
      
setDataSource_(theDataSource)
      
setDelegate_(theDataSource)
      
setDoubleAction_("doubleAction:")
      
setGridStyleMask_(current application’s NSTableViewSolidVerticalGridLineMask)
      
setSelectionHighlightStyle_(current application’s NSTableViewSelectionHighlightStyleRegular)
      
setTarget_(theDataSource)
      
setUsesAlternatingRowBackgroundColors_(true)
      
      
set thisRowHeight to rowHeight() as integer
      
set theDataSource’s _table_view to it
    end tell
  end tell
  
  
# data sourceに追加
  
tell (theDataSource)
    awakeFromNib()
    
set its _file_type to thisFileType
    
    
repeat with aURL in fileURLs
      addObject_({fileURL:aURL})
    end repeat
    
    
setSelectionIndex_(0)
  end tell
  
  
## NSTableColumn
  
### Columnの並び順を指定する
  
set viewWidth to 320
  
set columnsCount to keyDict’s |count|()
  
repeat with colNum from 1 to columnsCount
    
    
set keyName to "column" & colNum as text
    
set aTitle to (keyDict’s objectForKey:keyName)
    
    
tell (current application’s NSTableColumn’s alloc()’s initWithIdentifier:(colNum as text))
      tell headerCell()
        setStringValue_(aTitle)
        
set thisHeaderHeight to cellSize()’s height
      end tell
      
      
### Columnの横幅を指定
      
setWidth_(viewWidth)
      
      
### バインディングのオプション
      
— ソートを無効にする
      
set anObj to (current application’s NSNumber’s numberWithBool:false)
      
set aKey to current application’s NSCreatesSortDescriptorBindingOption
      
set bOptions to (current application’s NSDictionary’s dictionaryWithObject:anObj forKey:aKey)
      
      
### 表示内容をNSArrayControllerにバインディング
      
bind_toObject_withKeyPath_options_(current application’s NSValueBinding, theDataSource, "arrangedObjects", bOptions)
      
      (
theDataSource’s _table_view’s addTableColumn:it)
    end tell
    
  end repeat
  
  
## NSScrollView
  
### Viewの高さを計算
  
set rowCount to 12 –> 行数を固定
  
set viewHeight to (thisRowHeight + 2) * rowCount + thisHeaderHeight –> 2を足さないと高さが合わない
  
set vSize to current application’s NSMakeRect(0, 0, viewWidth, viewHeight)
  
  
### Viewを作成
  
tell current application’s NSScrollView’s alloc()
    tell initWithFrame_(vSize)
      setBorderType_(current application’s NSBezelBorder)
      
setDocumentView_(theDataSource’s _table_view)
      
–setHasHorizontalScroller_(true)
      
setHasVerticalScroller_(true)
      
set aScroll to it
    end tell
  end tell
  
  
return {aScroll, theDataSource’s _table_view}
end makeContentView

★Click Here to Open This Script 

AppleScript名:subClasses
#MARK: – NSValueTransformer
script YKZURLToIcon
  property parent : class "NSValueTransformer"
  
property allowsReverseTransformation : false –>逆変換
  
property transformedValueClass : a reference to current application’s NSImage –>クラス
  
  
#変換処理
  
on transformedValue:fileURL
    if fileURL is missing value then return
    
    
set appPath to fileURL’s |path|()
    
set iconImage to current application’s NSWorkspace’s sharedWorkspace’s iconForFile:appPath
    
return iconImage
  end transformedValue:
end script

script YKZURLToDisplayedName
  property parent : class "NSValueTransformer"
  
property allowsReverseTransformation : false –>逆変換
  
property transformedValueClass : a reference to current application’s NSString –>クラス
  
  
#変換処理
  
on transformedValue:fileURL
    if fileURL is missing value then return
    
    
set appPath to fileURL’s |path|()
    
set displayedName to current application’s NSFileManager’s defaultManager’s displayNameAtPath:appPath
    
return displayedName
  end transformedValue:
end script

#MARK: – Array Controller
script YKZArrayController
  property parent : class "NSArrayController"
  
  
#MARK: IBOutlets
  
property _table_view : missing value
  
#MARK:
  
property _data_type : do shell script "uuidgen"
  
property _file_type : ""
  
  
on awakeFromNib()
    –log "YKZArrayController – awakeFromNib"
    
tell _table_view
      registerForDraggedTypes_({current application’s NSFilenamesPboardType, _data_type})
      
setDraggingSourceOperationMask_forLocal_(current application’s NSDragOperationCopy, false)
    end tell
    
    
#Transformerの登録
    
set tNames to {}
    
set tNames’s end to "YKZURLToIcon"
    
set tNames’s end to "YKZURLToDisplayedName"
    
repeat with aTransformer in tNames
      set theTransformer to current application’s class aTransformer’s new()
      (
current application’s NSValueTransformer’s setValueTransformer:theTransformer forName:aTransformer)
    end repeat
  end awakeFromNib
  
  
#MARK: Data Source Overrides
  
on numberOfRowsInTableView:aTableView
    return my content()’s |count|()
  end numberOfRowsInTableView:
  
  
on tableView:aTableView viewForTableColumn:aColumn row:aRow
    –log "viewForTableColumn"
    
    
set aCellView to aTableView’s makeViewWithIdentifier:"YKZTableCellView" owner:me
    
–set isNull to aCellView’s isEqual:(current application’s NSNull’s |null|())
    
–log isNull as text
    
    
if aCellView is missing value then
      
      
set frameRect to current application’s NSMakeRect(0, 0, aColumn’s width, aTableView’s rowHeight())
      
set aCellView to current application’s YKZTableCellView’s alloc’s initWithFrame:frameRect
      
      
set anObj to "YKZURLToIcon"
      
set aKey to current application’s NSValueTransformerNameBindingOption
      
set bOptions to (current application’s NSDictionary’s dictionaryWithObject:anObj forKey:aKey)
      (
aCellView’s imageView())’s bind:(current application’s NSValueBinding) toObject:aCellView withKeyPath:"objectValue.fileURL" options:bOptions
      
      
set anObj to "YKZURLToDisplayedName"
      
set aKey to current application’s NSValueTransformerNameBindingOption
      
set bOptions to (current application’s NSDictionary’s dictionaryWithObject:anObj forKey:aKey)
      (
aCellView’s textField())’s bind:(current application’s NSValueBinding) toObject:aCellView withKeyPath:"objectValue.fileURL" options:bOptions
      
    end if
    
    
return aCellView
  end tableView:viewForTableColumn:row:
  
  
# テーブル内のセルが編集できるか
  
on tableView:aTableView shouldEditTableColumn:aColumn row:aRow
    return false
  end tableView:shouldEditTableColumn:row:
  
  
# テーブル内をダブルクリックしたらOKボタンを押す
  
on doubleAction:sender
    log "doubleAction"
    
## ヘッダをクリックした時は何もしない
    
if (sender’s clickedRow()) is -1 then return
    
    
set theEvent to current application’s NSEvent’s ¬
      keyEventWithType:(current application’s NSEventTypeKeyDown) ¬
        location:(current application’s NSZeroPoint) ¬
        
modifierFlags:0 ¬
        
timestamp:0.0 ¬
        
windowNumber:(sender’s |window|()’s windowNumber()) ¬
        
context:(current application’s NSGraphicsContext’s currentContext()) ¬
        
|characters|:return ¬
        
charactersIgnoringModifiers:(missing value) ¬
        
isARepeat:false ¬
        
keyCode:0
    current application’s NSApp’s postEvent:theEvent atStart:(not false)
  end doubleAction:
  
  
#MARK: Drag Operation Method
  
#ドラッグを開始(ペーストボードに書き込む)
  
on tableView:aTableView writeRowsWithIndexes:rowIndexes toPasteboard:pboard
    –log "writeRowsWithIndexes"
    
set aData to current application’s NSKeyedArchiver’s archivedDataWithRootObject:rowIndexes
    
pboard’s declareTypes:{_data_type} owner:(missing value)
    
pboard’s setData:aData forType:_data_type
    
return true
  end tableView:writeRowsWithIndexes:toPasteboard:
  
#ドラッグ途中
  
on tableView:aTableView validateDrop:info proposedRow:row proposedDropOperation:operation
    –log "validateDrop"
    
#列の間にドラッグ
    
if (operation is current application’s NSTableViewDropAbove) then
      return current application’s NSDragOperationMove
    end if
    
#項目の上にドラッグ
    
set aTypes to info’s draggingPasteboard’s types()
    
if (aTypes’s containsObject:_data_type) as boolean then
      return current application’s NSDragOperationNone
    end if
    
return current application’s NSDragOperationNone
  end tableView:validateDrop:proposedRow:proposedDropOperation:
  
#ドラッグ終了
  
on tableView:aTableView acceptDrop:info row:row dropOperation:operation
    –log "acceptDrop"
    
#
    
set pboard to info’s draggingPasteboard()
    
set aTypes to pboard’s types()
    
    
if (aTypes’s containsObject:_data_type) as boolean then
      
      
set rowData to pboard’s dataForType:_data_type
      
set rowIndexes to current application’s NSKeyedUnarchiver’s unarchiveObjectWithData:rowData
      
      
if (rowIndexes’s firstIndex()) < row then
        set row to row – (rowIndexes’s |count|())
      end if
      
      
set aRange to current application’s NSMakeRange(row, rowIndexes’s |count|())
      
set aIndexSet to current application’s NSIndexSet’s indexSetWithIndexesInRange:aRange
      
      
set anObj to ((my content())’s objectsAtIndexes:rowIndexes)
      
my removeObjects:anObj
      
my insertObjects:anObj atArrangedObjectIndexes:aIndexSet
      
my rearrangeObjects()
      
    else
      set pathList to pboard’s propertyListForType:(current application’s NSFilenamesPboardType)
      
–log result as list
      
repeat with aPath in pathList
        set isAdd to addItem_({filePath:aPath, atIndex:row})
        
if isAdd then beep
      end repeat
      
    end if
    
return true
  end tableView:acceptDrop:row:dropOperation:
  
  
#追加する
  
on addItem:sender –> {filePath:aPath, atIndex:aIndex}
    –log "addItem:"
    
set isAdd to false
    
    
#missing valueの時は最後に追加
    
set {filePath:aPath, atIndex:aIndex} to sender
    
if aIndex is missing value then
      set aIndex to my content()’s |count|() as number
    end if
    
    
#URLに変換
    
set appURL to (current application’s NSURL’s fileURLWithPath:aPath)
    
#アプリケーション以外は追加しない
    
set {aResult, aUTI, aError} to (appURL’s getResourceValue:(reference) ¬
      forKey:(current application’s NSURLTypeIdentifierKey) ¬
      
|error|:(reference))
    log aUTI
    
if (aUTI as text) is not (my _file_type as text) then return isAdd
    
    
#すでにあるか確認
    
set bList to my content() as list
    
repeat with aRecord in bList
      if ((appURL’s isEqual:(aRecord’s fileURL)) as boolean) then
        set isAdd to true
        
exit repeat
      end if
    end repeat
    
    
#なければ追加
    
if not isAdd then
      set anObj to {fileURL:appURL}
      (
my insertObject:anObj atArrangedObjectIndex:aIndex)
    end if
    
return isAdd
  end addItem:
end script

#MARK: – NSTableCellView
script YKZTableCellView
  property parent : class "NSTableCellView"
  
  
on initWithFrame:rect
    –log "initWithFrame"
    
continue initWithFrame:rect
    
    
setAutoresizingMask_(current application’s NSViewWidthSizable)
    
    
tell current application’s NSImageView’s alloc
      tell initWithFrame_(current application’s NSMakeRect(0, 0, 16, 16))
        setImageScaling_(current application’s NSImageScaleProportionallyUpOrDown)
        
setImageAlignment_(current application’s NSImageAlignCenter)
        
        
my setImageView:it
        
my addSubview:it
      end tell
    end tell
    
    
tell current application’s NSTextField’s alloc
      tell initWithFrame_(current application’s NSMakeRect(20, 2, 200, 14))
        setBordered_(false)
        
setDrawsBackground_(false)
        
setEditable_(false)
        
        
my setTextField:it
        
my addSubview:it
      end tell
    end tell
    
    
return me
  end initWithFrame:
end script

★Click Here to Open This Script 

Posted in dialog GUI | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSArrayController NSBundle NSCreatesSortDescriptorBindingOption NSDictionary NSNumber NSScrollView NSTableCellView NSTableView NSURL NSValueBinding NSValueTransformer | Leave a comment

Numbersで各シート名称を置換

Posted on 1月 15, 2020 by Takaaki Naganoya

Numbersでオープン中の最前面の書類中にあるすべてのシートの名前を置換するAppleScriptです。

内容は簡単ですが、Numbersにそうした機能が存在しないので、作っておくと便利です。アーカイブ本を作るのに、こうした(↓)資料を作る必要があるわけですが、そのためにこうしたこまごまとしたScriptをその場で作って作業の効率化を図っています。


▲上の画像あくまでは処理イメージなので、厳密に同一データの処理前・処理後の画面スナップショットではありません。各シートの名称の一部の文字列(YYYY部分)のみ置換されていることをご確認ください

AppleScript名:Numbersで各シート名称を置換
tell application "Numbers"
  tell front document
    set tList to every sheet
    
repeat with i in tList
      tell i
        set aName to name
        
set bName to replaceText(aName, "2011_", "2013_") of me
        
set name to bName
      end tell
    end repeat
  end tell
end tell

–任意のデータから特定の文字列を置換
on replaceText(origData, origText, repText)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {origText}
  
set origData to text items of origData
  
set AppleScript’s text item delimiters to {repText}
  
set origData to origData as text
  
set AppleScript’s text item delimiters to curDelim
  
return origData
end replaceText

★Click Here to Open This Script 

Posted in Text | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy Numbers | Leave a comment

Blogアーカイブ本 vol.5を販売開始

Posted on 1月 14, 2020 by Takaaki Naganoya

一部の本Blog愛読者の方々から「アーカイブ本まだ?」と言っていただいて気にはしておりました。ここに、Blogアーカイブ本のVol.5(2013〜2014年)の発売をお知らせいたします。

→ オンライン販売ページ
→ お試し版ダウンロードページ

本Blog「AppleScriptの穴」は、開設10年目を迎える直前の2018年1月末に、格安ホスティングサービス「Xserver」との間の手違いでDBがシャットダウンされ、そのままの形で公開し続けることができなくなってしまいました。

そこで、AppleScriptのプログラムによるFinder上のAppleScriptの自動HTML化、AppleScriptによるXML-RPC経由でのWordPressへの自動記事投入といったさまざまなソリューションを投下して、現在の登録記事数に復旧。自動記事投入による復旧を行なったために、当時の作業環境でオープンできない(OSバージョン依存、アプリケーション依存)Scriptについては掲載を見送っています。

 旧AppleScriptの穴:2008〜2018年 Mac OS X 10.4〜10.5の時代に開設
 現AppleScriptの穴:2018年〜   Cocoa APIを呼びまくる現在のスタイルが定着

自動投入可能なコンテンツを優先して掲載したため、旧Blogと現Blogでは掲載内容が大幅に変わっています。別物といってよいでしょう。

そのため、Cocoa APIを使用しない「オールドスタイルのAppleScript」(とくに昔のバージョンのアプリケーション依存)については再掲載が難しく、このBlogアーカイブ本シリーズにしか情報をまとめていません。

旧Blogアーカイブ本シリーズも、1年ごとに区切って記事をPDF化して5冊目。この頃の記事投稿数が少なかったので、Vol.5は2013年1〜2014年12月の2年分の内容をまとめています。全429ページ、2,000円。

ファイル形式はPDFで、キーワードによる全文検索や印刷が行えます。本文からリンクしているXcodeプロジェクトのダウンロードリンクも新たに現行Blogにアップロードしたアーカイブにリンクし直しています。

もちろん、各プログラムリスト末尾にURLリンクをそなえ、ワンクリックでプログラム内容をスクリプトエディタに転送可能です。

ほとんどの掲載プログラムについてコメントを行い、現時点(2020年時点)で評価してどうか、ということを追記しています。

AppleScriptの穴Blogアーカイブvol.5

AppleScriptObjCでViewを印刷
AppleScriptObjCで透明ウィンドウを表示
Bundle IDで指定したアプリの非同期起動
指定プロセスの死活判定
最前面のアプリケーションをいったん終了させてから起動
指定プロセスの死活判定 v2
複数のピリオドが入る数字の文字列を数値として解釈して返す
与えられたICC Profileの名称リストからもっともバージョンの新しい(大きい)数字を持つものを返す
システムにインストールされているICC Profileのうち、指定キーワードに該当する名前を持つものでバージョン番号が最新のものを返す v2
Photoshopのsave optionをテキストで指定して反映させるテスト
AppleScriptObjCでボタンの文字色を変更
Xcode 4.6でAppleScript用語辞書の若干の間引きを
USBメモリやネットワーク上のサーバーなどをアンマウント
AppleScriptObjCでボタンを動的に生成
AppleScriptObjCでボタンを動的に生成(横に複数作成)
miで文字置換
AppleScriptObjCでMyriad Helpersの三角関数を使ってWindowを円運動
AppleScriptObjCとメモリ管理
AppleScriptObjCでPDFViewを使ってPDFをプレビュー(3)
ログファイルから時間帯ごとの度数分布を計算
指定のコード体系の全パターンのコードを生成 v1
指定のコード体系の全パターンのコードを生成 v2
指定のコード体系の全パターンのコードを生成 v3
指定のコード体系の全パターンのコードを生成 v4
指定のコード体系の全パターンのコードを生成 v5
リストを任意のデリミタ付きでテキストに v2
特定の語句を含むMail.appのフォルダ(mailbox)を抽出してフルパスを文字列化
現在表示中のCanvasに存在しているラインのうち青いものに影を付ける
miで選択中の内容をファイルに書き出してperlのプログラムとしてterminalで実行
miで選択中の内容をファイルに書き出してperlのプログラムとしてterminalで実行 v2
文字入力モードを制御
iTunesのMobileアプリをコピーしてすべて展開する
Find same file name with different extension
AppleのAppleScript関連ドキュメントの個人的な翻訳サイト
インストールされているアプリのAS辞書を書き出すv2
Mailで選択中のmessageの親フォルダのフルパスを文字で取得する
指定フォルダ中のファイル名が拡張子を外すと衝突するかどうかチェック
AppleのiBookstoreが日本国内向けにコンテンツ販売を開始
Safariで指定可能なユーザーエージェントのリストを返す
Safari 6で指定のURLをオープンする
Safariで指定User Agentで指定URLをオープン
共通項目をキーにしてリスト内の項目を統合する v2
アプリケーションのクラッシュレポートダイアログの表示切り換え
入れ子のリストの昇順、降順ソート(超高速版)
IPアドレスがプライベートIPアドレスかどうかチェック
OS X 10.8のdateに強烈なバグ
1Dリスト中のシーケンシャルサーチ
1Dリストのスイープ
自然言語による相対日付指定v14
CSVデータを読み込んでリスト化
SafariでRadiko選局を行う 10.6.8+5.1.8版
SafariでRadikoの選局を行う v2
開始日と終了日の間を、指定日数単位で切った{開始日,終了日}のリストの日付文字列リストを返す
手作りのノンブルが作ってあるPowerPoint書類に対して、座標位置(一番左側に寄せてある)を手がかりにフレームを取得してリナンバリング
0〜255の8ビットの値から構成されるRGB値のリストの色をプレビューする
Photoshop CS6でRGB→LAB、LAB→RGB変換
0〜255の8ビットの値から構成されるRGB値のリストの色をプレビューする
PowerPointで、オブジェクトの外側の線の色を、水色から青に変更
Photoshop CS6でRGB→LAB、LAB→RGB変換
Photoshop CS6でRGB→HSB、HSB→RGB変換
Photoshop CS6でRGB→RGB Hex、RGB Hex→RGB変換
Photoshopでオープン中の画像をグレースケール→白黒2値の画像にモードを変換する
Safariでオープン中のファイルを別途ダウンロードv2
Photoshop上で選択範囲を指定色(RGB)で塗りつぶす
AppleScriptの処理中断
PDFのページ数を数える
EPSファイルの破損チェック(高速版)
プレビュー.appをAppleScriptから操作
国民の祝日を求める v4
AppleriptObjCベースのCocoaアプリケーションのSandbox化は可能か?
入り組んだリストの中に指定要素が存在するかどうかをチェック
Mail.appのメールボックスオブジェクトを渡すと、テキストのフルパスに変換 v1
Mail.appの指定メールボックス内に任意のメールボックスを新規作成 v2
OmniOutlinerで選択中の行の内容のうち指定列のデータをすべて取得
リストをテキストに
指定の文字エンコーディングでテキストをファイルに保存
ASObjCExtrasでファイルの情報を取得
ASObjCExtrasで1Dリスト中の合計値、最大値、最小値を求める
ASObjCExtrasで1D List中のヌル要素を削除
ASObjCExtrasで1D List中のmissing valueを置換
ASObjCExtrasで2DのListをフラット化(1D List化)
OS X 10.10 Yosemite のAppleScript関連バグまとめ
2Dリストで最長の要素に満たない個数の要素は後ろに埋め草を追加
2D Listの各要素に指定の1Dリストの内容をインサートする
指定ファイルからサイズ情報を取得
ドロップレットのデバッグ方法
Finder Windowを円運動 v2
list同士のdiffをとる(asoc)
listの共通項を返す(asoc)
1D Listのユニーク化(asoc) 処理内容比較
asocで文字置換
2D Listを1D Listに変換
レコードの操作
レコードのリストをソート(asoc)
レコードのリストから抽出(asoc)
リストから抽出(asoc)
レコードのリストから抽出(別リストに該当するもののみ)
Keynote 6.5で各スライドのタイトル、マスタースライド名を取得してデータ化
1D Listを文字列長でソート
2D Listを文字列長でソート
1D Listを文字列長でソート v2
10.10でプリンタを選択して印刷
10.10でプリンタの情報を取得する
無限次元リストのフラット化
2D Listを文字列長でソート
1D Listの内容すべてに指定数値を加算
画像の特定のピクセルの色を取得
画像中の色数をカウント
指定アプリケーションがフルスクリーン状態かどうか調べる
NSNumberFormatterのテスト
as integerの落とし穴
数値の桁数を求める
同一パターンの連番文字列の作成
1Dリスト中の複数指定アイテムの出現位置をリストで返す
CoreImageでフィルタしまくり
Bluetoothに接続中のデバイス名を取得するv2
NSSoundで音声を再生
バージョン番号文字列からメジャーバージョンを求める
バージョン番号文字列からメジャーバージョンを求める v2v3
指定AppleScriptをしらべたり実行したりする
指定ロケールの月名、曜日名を取得する
AppleScriptでJavaScriptを実行する
SafariのWebViewのGUI Scripting的な参照を取得する
アプリケーションのローカライズ分布を取得する
アプリケーションのローカライズ分布を取得するv2
アプリケーションのローカライズ分布を取得する v4
アプリケーションのローカライズ分布を取得する v5
アプリケーションごとのローカライズ言語数を求める
オーディオファイルのチャンネル数と再生時間を取得する
aListのうち、bListに入っていない項目を返す
PDFをページごとに分解する
文字エンコーディングを自動判別してテキストファイル読み込み v1
文字エンコーディングを自動判別してテキストファイル読み込み v2

Posted in PRODUCTS | Leave a comment

GUI ScriptingでGUI要素のIDもOSアップデート後には見直す必要あり

Posted on 1月 13, 2020 by Takaaki Naganoya

GUI Scripting、それは画面上のGUI部品に直接メッセージを送って強引にアプリケーションを動かす必要悪。AppleScript非対応機能を強引に動かすことが目的の機能です。

MarkdownエディタのMacDownも、PDF書き出しについてはAppleScript用語辞書にコマンドが掲載されていないので、Markdown書類のPDF書き出しはGUI Scriptingで行なっています。

メイン環境をmacOS 10.12.6から10.14.6に移行して、はじめて動かした重量級のAppleScriptがあります。指定フォルダ以下のPages、Markdown、Wordなどの書類をすべてデスクトップ上にPDFで書き出して、ファイル名順にならべかえて1つのPDFにまとめるAppleScriptです。

つまり、電子書籍の書き出し&連結作業を1本でこなすScriptなわけで、自分にとっては命綱的に重要なAppleScriptです。

で、こいつがmacOS 10.14.6上でまともに動かないことが判明して、顔色が変わりました。

システム環境設定のセキュリティ系の妨害を受けているのかと思って確認してみると、必要な設定はすべて行なってある状態。MacDownからのPDF書き出しだけが効いていません。


–注意!! ここでGUI Scriptingを使用。バージョンが変わったときにメニュー階層などの変更があったら書き換え
on macDownForceExport()
  activate application "MacDown"
  
tell application "System Events"
    tell process "MacDown"
      — File > Export > PDF
      
–click menu item 2 of menu 1 of menu item 14 of menu 1 of menu bar item 3 of menu bar 1
      
click menuItemRef1
      
      
–Go to Desktop Folder
      
keystroke "d" using {command down}
      
      
–Save Button on Sheet
      
click button 1 of sheet 1 of window 1
    end tell
  end tell
end macDownForceExport

★Click Here to Open This Script 

ためしに、SIPを解除して実行してみたものの、それでも問題は解決しません。

動きを観察していると、書き出し時に「保存」ではなく「キャンセル」ボタンをクリックしている模様。そこで、ボタンをIndexではなくTitleで指し示してみたら、問題なく書き出しできました。


–注意!! ここでGUI Scriptingを使用。バージョンが変わったときにメニュー階層などの変更があったら書き換え
on macDownForceExport()
  activate application "MacDown"
  
tell application "System Events"
    tell process "MacDown"
      — File > Export > PDF
      
–click menu item 2 of menu 1 of menu item 14 of menu 1 of menu bar item 3 of menu bar 1
      
click menuItemRef1
      
      
–Go to Desktop Folder
      
keystroke "d" using {command down}
      
      
–Save Button on Sheet
      
click button "保存" of sheet 1 of window 1 –保存ボタンのIndexが変わっていた
    end tell
  end tell
end macDownForceExport

★Click Here to Open This Script 

# 久しぶりに怪奇現象っぽい挙動で震えました。だいたい、怪奇現象とか心霊現象っぽい挙動というのは、技術や経験が足りない場合に「そう見える」だけであって、知っていたり経験していれば「当然」という現象に見えます

いま、ちょうどGUI Scriptingは端境期で、手で書かなくてもアプリケーションの状態を検知してオブジェクト階層を動的に走査して動かすようなScriptが一部で使われている一方で、古いタイプのIDやTitleを直接指定するような書き方が残っていたりします。

OSがアップデートされても、IDで書いておけば同じGUI部品を指定できるだろう、という思い込みがありましたが、Titleで指定していたほうがIDの数え方が変わっても影響がない、という現象だったのでしょうか。

久しぶりにハマりそうになりました。あと、MacDownのソースに手を入れて、PDF書き出し命令ぐらいは自前で実装したい気がします。

Posted in GUI Scripting | Tagged 10.14savvy MacDown System Events | Leave a comment

RoundWindow v2

Posted on 1月 12, 2020 by Takaaki Naganoya

Edama2さんと「無理だよねー」「そうそう、絶対無理〜」などとメールで言っていたら、Shane Stanleyから届いた「できるよ」という衝撃のメール。

スクリプトエディタ上で記述する通常のAppleScriptで、CocoaのCustom Class宣言と呼び出しができるとのこと。

自分で動作確認してみるまで、半信半疑でしたが、、、、できますねこれは、、、

–> Download Editable and Executable Script Bundle

冗談半分で思いついたことを試してみたらできてしまったり、冗談半分でできるわけないよねと念のために書いておいたことが世界の誰かの目に止まったりと、「冗談半分」ってけっこう重要なことだと思えてきました。

以下、Shane Stanleyの説明による、その書き換え手順です。

(1)Subclassファイル(複数可)をXcode上のプロジェクトで書くようなスタイルで書く

こういう(↑)スタイルですね。かならずscript宣言しつつ、parent属性を宣言しておくところがXcode上のAppleScriptアプリケーションのスタイルです。あとで動作確認して、アプリケーションの起動や終了に関するイベントハンドラを書いておいたのは無駄(実行されない)ではないかとも思われました。

(2)実行するメインのScriptのResourcesフォルダ内にSubclassファイルを入れる

普通、AppleScriptのファイルが入る/Contents/Resources/Scripts/でも、ライブラリを入れておく/Contents/Resources/Script Libraries/でもなく、/Contents/Resources/の直下に入れます。ファイル名はオリジナルのEdama2さんのものをそのまま採用していますが、割となんでもいいようです。Custom Classファイルは分割してもいいし、このサンプルのようにまとめてもいいんでしょう。

# 追加実験してみたところ、Resourcesフォルダ以下の/Scriptsや/Script Libraries/フォルダと重複しない名称の別フォルダ(例:/Classes/)に入れておいても大丈夫でした

(3)use framework “AppleScriptObjC”の宣言文を追加

見たことのない光景ですが、書くことについてはとくに障害はありません。AppKit.Frameworkもuse宣言しておいたほうがよかったかもしれません。

(4)メインスクリプトの実行時に以下の処理を実行

set theBundle to current application’s NSBundle’s bundleWithPath:pathToFolderWithScripts
theBundle’s loadAppleScriptObjectiveCScripts()

★Click Here to Open This Script 

試行錯誤して、上記の「pathToFolderWithScripts」にバンドル内の/Contents/Resources/を入れて実行すればよいことが理解できました。

以上の変更を加えて、ためしにスクリプトエディタ&Script Debugger上で実行してみたところ、改変前と変わりなく実行できてしまいました(冒頭のスクリーンショット)。

いや、これはめちゃくちゃすごいですよ!! 何がすごいって、CocoaのCustom Classをスクリプトライブラリ中に入れて呼び出せるということで、けっこう無茶な箱庭インタフェースが作れてしまう予感が、、、、。

そして、AppleScriptObjC(AppleScriptObjC.frameworkより)でスクリプトエディタの「.scpt」形式のファイルを読み込んで実行できてしまったということは、Xcode上のAppleScriptアプリケーション内のScriptもテキスト形式だけでなく、スクリプトエディタで編集できる.scpt形式のファイルを突っ込んで編集できる可能性が見えてきました。

ただ、テキスト形式になっていないと、Interface Builderとの連携のあたりで問題になりそうな気もします。

AppleScript名:customClassTest.scptd
—
–  Created by: Edama2 2020/01/10
–  Adviced by: Shane Stanley 2020/01/11
–  Modified by: Takaaki Naganoya 2020/01/12
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppleScriptObjC"
use scripting additions

property _clock_text_view : missing value –> 時計用の文字列
property _clock_timer : missing value –> 時計用のNSTimer

–Script Bundle内のResourcesフォルダを求める
set resourcePath to POSIX path of (path to me) & "Contents/Resources/"
set theBundle to current application’s NSBundle’s bundleWithPath:resourcePath
theBundle’s loadAppleScriptObjectiveCScripts()

my performSelectorOnMainThread:"raizeWindow:" withObject:(missing value) waitUntilDone:true

# ウィンドウを作成
on raizeWindow:aParam
  
  
# 時計用の文字を作成
  
tell current application’s NSTextView’s alloc()
    tell initWithFrame_(current application’s NSMakeRect(35, 120, 300, 40))
      setRichText_(true)
      
useAllLigatures_(true)
      
setTextColor_(current application’s NSColor’s whiteColor())
      
setFont_(current application’s NSFont’s fontWithName:"Arial-Black" |size|:48)
      
setBackgroundColor_(current application’s NSColor’s colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.0)
      
setAlphaValue_(1.0)
      
setEditable_(false)
      
–setString_("00:00:00")
      
      
set my _clock_text_view to it
    end tell
  end tell
  
  
# 時計を更新するNSTimerを作成
  
set my _clock_timer to current application’s NSTimer’s scheduledTimerWithTimeInterval:1 target:me selector:"idleHandler:" userInfo:(missing value) repeats:true
  
  
# 丸いViewを作成
  
set aFrame to current application’s NSMakeRect(0, 0, 300, 300)
  
tell current application’s RoundView’s alloc()
    tell initWithFrame_(aFrame)
      setNeedsDisplay_(true)
      
setSubviews_({my _clock_text_view})
      
set customView to it
    end tell
  end tell
  
  
#スクリーンのサイズを調べる
  
set aScreen to current application’s NSScreen’s mainScreen()
  
  
# Window
  
set aBacking to current application’s NSWindowStyleMaskBorderless
  
–set aBacking to current application’s NSBorderlessWindowMask
  
set aDefer to current application’s NSBackingStoreBuffered
  
  
tell current application’s CustomWindow’s alloc()
    tell initWithContentRect_styleMask_backing_defer_screen_(aFrame, aBacking, aDefer, false, aScreen)
      –setTitle_(uniqueName) –>タイトル
      
setBackgroundColor_(current application’s NSColor’s clearColor()) — Grammar Police –>背景色
      
setContentView_(customView) –>内容ビューのセット
      
setDelegate_(me) –>デリゲート
      
setDisplaysWhenScreenProfileChanges_(true) –>スクリーンプロファイルが変更されたときウインドウの内容をアップデートするか
      
setHasShadow_(true) –>ウインドウに影があるか
      
setIgnoresMouseEvents_(false) –>マウスイベントを無視するか
      
–setLevel_((current application’s NSScreenSaverWindowLevel) + 1) –>ウインドウの前後関係の位置
      
setOpaque_(false) –>ウインドウを不透明にするか
      
setReleasedWhenClosed_(true) –>閉じたときにメモリを解放するか
      
      
#
      
|center|()
      
makeKeyAndOrderFront_(me) –>キーウインドウにして前面に持ってくる
      
–setFrame_display_(aFrame, true) –>表示
    end tell
  end tell
end raizeWindow:

#タイマー割り込み
on idleHandler:aSender
  set mesStr to time string of (current date)
  (
my _clock_text_view)’s setString:mesStr
end idleHandler:

★Click Here to Open This Script 

AppleScript名:CocoaAppletAppDelegate.scpt
script CocoaAppletAppDelegate
  property parent : class "NSObject"
  
  
on applicationWillFinishLaunching:aNotification
    —
  end applicationWillFinishLaunching:
  
  
  
on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
end script

script CustomWindow
  property parent : class "NSWindow"
  
property canBecomeKeyWindow : true
  
  
property _initial_location : missing value
  
  
on mouseDown:theEvent
    set my _initial_location to theEvent’s locationInWindow()
  end mouseDown:
  
  
on mouseDragged:theEvent
    –set res to display dialog "mouseDragged" buttons {"OK"} default button "OK"
    
try
      set screenVisibleFrame to current application’s NSScreen’s mainScreen()’s visibleFrame()
      
set screenVisibleFrame to my myHandler(screenVisibleFrame)
      
set windowFrame to my frame()
      
set windowFrame to my myHandler(windowFrame)
      
set newOrigin to windowFrame’s origin
      
      
set currentLocation to theEvent’s locationInWindow()
      
set newOrigin’s x to (newOrigin’s x) + ((currentLocation’s x) – (_initial_location’s x))
      
set newOrigin’s y to (newOrigin’s y) + ((currentLocation’s y) – (_initial_location’s y))
      
      
set tmpY to ((newOrigin’s y) + (windowFrame’s |size|’s height))
      
set screenY to (screenVisibleFrame’s origin’s y) + (screenVisibleFrame’s |size|’s height)
      
if tmpY > screenY then
        set newOrigin’s y to (screenVisibleFrame’s origin’s y) + ((screenVisibleFrame’s |size|’s height) – (windowFrame’s |size|’s height))
      end if
      
      
my setFrameOrigin:newOrigin
    on error error_message number error_number
      set error_text to "Error: " & error_number & ". " & error_message
      
display dialog error_text buttons {"OK"} default button 1
      
return error_text
    end try
    
  end mouseDragged:
  
  
on myHandler(aFrame)
    if class of aFrame is list then
      set {{theX, theY}, {theWidth, theHeight}} to aFrame
      
set aFrame to {origin:{x:theX, y:theY}, |size|:{width:theWidth, height:theHeight}}
      
–set aFrame to current application’s NSMakeRect(theX, theY, theWidth, theHeight)
    end if
    
return aFrame
  end myHandler
end script

script RoundView
  property parent : class "NSView"
  
  
on drawRect:rect
    set aFrame to my frame()
    
set myColor to current application’s NSColor’s redColor()
    
    
tell current application’s NSBezierPath
      tell bezierPathWithOvalInRect_(aFrame)
        myColor’s |set|()
        
fill()
      end tell
    end tell
  end drawRect:
end script

★Click Here to Open This Script 

Posted in Custom Class GUI How To | Tagged 10.14savvy 10.15savvy NSBezierPath NSBundle NSColor NSFont NSScreen NSTextView NSTimer NSView NSWindow | Leave a comment

RoundWindow

Posted on 1月 10, 2020 by Takaaki Naganoya

本Scriptは、Edama2さんから投稿していただいたものです。Cocoa AppleScript AppletでCustom Classを宣言して作られた、丸いウィンドウ(透明ウィンドウの上に丸いグラフィックを描画)を表示して、タイマー割り込みで時計を表示するAppleScriptです。

–> Download Editable and Executable Applet

AppleScriptのランタイム環境はいくつかあり、それぞれに「できること」と「できないこと」、「手軽さ」などが異なります。

(1)スクリプトエディタ上で記述、実行する環境
一番セキュリティ上の制約が緩く、できることの多い環境です。

(2)Script Debugger上で記述、実行する環境
Cocoaのイベントやオブジェクトのログ表示などができる環境です。

(3)Applet環境
AppleScriptの実行ファイルです。

(4)Script Menu環境
macOS標準装備の、メニューからAppleScriptを実行できる環境です。

さらに、Cocoa Scriptingの機能に着目してみると、見え方が変わります。

本Scriptを記述している「Cocoa AppleScript Applet」環境(上の図の赤い部分)は、スクリプトエディタ上で記述する通常のAppleScriptと、Xcode上で記述するCocoaアプリケーションの中間的な性格を持つものです。スクリプトエディタ上で直接は動かせず、アプレット形式で動作させることになりますが、スクリプトエディタ上で動かすよりも、よりCocoaの機能が利用できます。

Cocoa AppleScript Appletでは、アプリケーション(Applet)起動や終了の最中で発生するイベントを利用できますし、本ScriptのようにCocoaのCustom Classを宣言できます。これは、普通のスクリプトエディタ上で記述する(本Blogの大部分のScriptのような)Scriptではできない真似です。
→ Shane Stanleyからツッコミが入って、手の込んだ作業を行うとできるとかで(テンプレートそのままでは無理)、後で実際に試してみます

タイトルは「丸いウィンドウと時計の表示」
NSWindowのカスタムクラスを使ったタイトルバーなしのドラッグで移動できる丸いウィンドウとオマケに時計を表示したものです。
初心者受けしそうなやつです。
問題はそこではなく、
XcodeやCocoa applescript appletから実行するASOCだとカスタムクラスが作れるけど、
ノーマルのapplescriptから実行するASOCではカスタムクラスが作れないということです。
表現がややこしいですが...。
ノーマルのapplescriptからカスタムクラスを作ると、ただのスクリプトオブジェクトにしかなりません。
誰かうまい解決方法を知っている人がいたら教えてください。

ちょうど、こういう資料をまとめていたので補足説明に役立ってしまいました。スクリプトエディタ上で記述する通常のAppleScriptでもCustom Cocoa Classが宣言できると便利そうですが、どんなもんでしょうか? 

Custom Classは便利なので使いたくなる一方、AppleScriptのインタプリタ上で実行するため、Objective-Cなどで書くのと同じような感覚で使うと「遅くて使えない」という話になると思いますが、このEdama2さんのサンプルぐらいの使いかたであれば、ちょうどいいんじゃないかというところです。

歴史的にみると、Cocoa-AppleScript Appletは、Xcode上で記述するCocoa-Applicationを簡略化してスクリプトエディタ上でCocoa Scriptingを手軽に使えるように手直しした「途中」の環境といえます。

Cocoa-AppleScript Appletは、GUIが手軽に作れるわけでもなく、スクリプトエディタ上で直接実行やログ表示ができるわけでもなありません。マスターしたところで最終到達点がCocoaアプリケーションほど高くなく、編集や習熟もしづらいことから「中途半端」「使えない」という評価になっていました(自分も使っていませんでした)。

その後、Cocoa-AppleScript Appletの機能要素をさらにダウンサイジングして、スクリプトエディタ上で手軽に記述・実行ができるように進化したのが現在・広くつかわれているCocoa Scripting環境です。

ただ、使いやすくなって広く使われるようになったはいいものの、「Xcodeを使うまでもないが、もうちょっとCocoaの機能が利用できないか?」という意見も出るようになり、Cocoa-AppleScript Appletを再評価してもいいんじゃないかと考えるようになってきてはいます。

ちなみに、本Cocoa-AppleScript AppletでCustom Classを宣言しているのと同じような書き方で、通常のCocoa Scriptingの環境で動かすような変更を加えたScriptもEdama2さんが試していますが、それは「動かない」ということで結論が出ています。

AppleScript名:CocoaAppletAppDelegate.scpt
script CocoaAppletAppDelegate
  property parent : class "NSObject"
  
  
property _clock_text_view : missing value –> 時計用の文字列
  
property _clock_timer : missing value –> 時計用のNSTimer
  
  
on applicationWillFinishLaunching:aNotification
    my raizeWindow()
  end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    my _clock_timer’s invalidate()
    
return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
# ウィンドウを作成
  
on raizeWindow()
    
    
# 時計用の文字を作成
    
tell current application’s NSTextView’s alloc()
      tell initWithFrame_(current application’s NSMakeRect(35, 120, 300, 40))
        setRichText_(true)
        
useAllLigatures_(true)
        
setTextColor_(current application’s NSColor’s whiteColor())
        
setFont_(current application’s NSFont’s fontWithName:"Arial-Black" |size|:48)
        
setBackgroundColor_(current application’s NSColor’s colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.0)
        
setAlphaValue_(1.0)
        
setEditable_(false)
        
–setString_("00:00:00")
        
        
set my _clock_text_view to it
      end tell
    end tell
    
    
# 時計を更新するNSTimerを作成
    
set my _clock_timer to current application’s NSTimer’s scheduledTimerWithTimeInterval:1 target:me selector:"idleHandler:" userInfo:(missing value) repeats:true
    
    
    
# 丸いViewを作成
    
set aFrame to current application’s NSMakeRect(0, 0, 300, 300)
    
tell current application’s RoundView’s alloc()
      tell initWithFrame_(aFrame)
        setNeedsDisplay_(true)
        
setSubviews_({my _clock_text_view})
        
set customView to it
      end tell
    end tell
    
    
#スクリーンのサイズを調べる
    
set aScreen to current application’s NSScreen’s mainScreen()
    
    
# Window
    
set aBacking to current application’s NSWindowStyleMaskBorderless
    
–set aBacking to current application’s NSBorderlessWindowMask
    
set aDefer to current application’s NSBackingStoreBuffered
    
tell current application’s CustomWindow’s alloc()
      tell initWithContentRect_styleMask_backing_defer_screen_(aFrame, aBacking, aDefer, false, aScreen)
        –setTitle_(uniqueName) –>タイトル
        
setBackgroundColor_(current application’s NSColor’s clearColor()) –>背景色
        
setContentView_(customView) –>内容ビューのセット
        
setDelegate_(me) –>デリゲート
        
setDisplaysWhenScreenProfileChanges_(true) –>スクリーンプロファイルが変更されたときウインドウの内容をアップデートするか
        
setHasShadow_(true) –>ウインドウに影があるか
        
setIgnoresMouseEvents_(false) –>マウスイベントを無視するか
        
–setLevel_((current application’s NSScreenSaverWindowLevel) + 1) –>ウインドウの前後関係の位置
        
setOpaque_(false) –>ウインドウを不透明にするか
        
setReleasedWhenClosed_(true) –>閉じたときにメモリを解放するか
        
        
#
        
|center|()
        
makeKeyAndOrderFront_(me) –>キーウインドウにして前面に持ってくる
        
–setFrame_display_(aFrame, true) –>表示
      end tell
    end tell
  end raizeWindow
  
  
#タイマー割り込み
  
on idleHandler:aSender
    set mesStr to time string of (current date)
    (
my _clock_text_view)’s setString:mesStr
  end idleHandler:
end script

script CustomWindow
  property parent : class "NSWindow"
  
property canBecomeKeyWindow : true
  
  
property _initial_location : missing value
  
  
on mouseDown:theEvent
    set my _initial_location to theEvent’s locationInWindow()
  end mouseDown:
  
  
on mouseDragged:theEvent
    –set res to display dialog "mouseDragged" buttons {"OK"} default button "OK"
    
try
      set screenVisibleFrame to current application’s NSScreen’s mainScreen()’s visibleFrame()
      
set screenVisibleFrame to my myHandler(screenVisibleFrame)
      
set windowFrame to my frame()
      
set windowFrame to my myHandler(windowFrame)
      
set newOrigin to windowFrame’s origin
      
      
set currentLocation to theEvent’s locationInWindow()
      
set newOrigin’s x to (newOrigin’s x) + ((currentLocation’s x) – (_initial_location’s x))
      
set newOrigin’s y to (newOrigin’s y) + ((currentLocation’s y) – (_initial_location’s y))
      
      
set tmpY to ((newOrigin’s y) + (windowFrame’s |size|’s height))
      
set screenY to (screenVisibleFrame’s origin’s y) + (screenVisibleFrame’s |size|’s height)
      
if tmpY > screenY then
        set newOrigin’s y to (screenVisibleFrame’s origin’s y) + ((screenVisibleFrame’s |size|’s height) – (windowFrame’s |size|’s height))
      end if
      
      
my setFrameOrigin:newOrigin
    on error error_message number error_number
      set error_text to "Error: " & error_number & ". " & error_message
      
display dialog error_text buttons {"OK"} default button 1
      
return error_text
    end try
    
  end mouseDragged:
  
  
on myHandler(aFrame)
    if class of aFrame is list then
      set {{theX, theY}, {theWidth, theHeight}} to aFrame
      
set aFrame to {origin:{x:theX, y:theY}, |size|:{width:theWidth, height:theHeight}}
      
–set aFrame to current application’s NSMakeRect(theX, theY, theWidth, theHeight)
    end if
    
return aFrame
  end myHandler
end script

script RoundView
  property parent : class "NSView"
  
  
on drawRect:rect
    set aFrame to my frame()
    
set myColor to current application’s NSColor’s redColor()
    
    
tell current application’s NSBezierPath
      tell bezierPathWithOvalInRect_(aFrame)
        myColor’s |set|()
        
fill()
      end tell
    end tell
  end drawRect:
end script

★Click Here to Open This Script 

Posted in GUI | Tagged 10.14savvy 10.15savvy NSBezierPath NSColor NSScreen NSTextView NSTimer NSView NSWindow | Leave a comment

AppleScript, my(me), it

Posted on 1月 8, 2020 by Takaaki Naganoya

Script Object関連の調べ物をしていて、AppleのWebサイト掲載のReferenceを見ていたら、サンプルをまじえて説明されていたので、理解が深まりました。

AppleScript:トップレベルObject。不変
my(me):現在のScript Object。可変
it:現在のアプリケーションObject。可変

AppleScript > my(me) ≧ it

というレベルになっていることもよく理解できました。

ただ、サンプルが自分的にいまひとつわかりやすくなかったので、自分用に書き換えてみました。バージョン取得ではなく、「名前を取得」しないといまひとつ分からないんじゃないでしょうか。

AppleScript名:testScript
me
–> «script»–実行中のAppleScript書類(Script Object)

AppleScript
–> «script AppleScript»

it
–> «script»–current target object

tell application "Finder"
  it
  
–> application "Finder"–current target object
  
  
–testMe() –> error "Finderでエラーが起きました: testMeを続けることができません。" number -1708
  
testMe() of me
  
testMe() of aTEST of me
  
testMe() of bTEST of aTEST of me
end tell

on testMe()
  set aName to name of me
  
–> "testScript"
  
display dialog aName –Name of this AppleScript document file
end testMe

script aTEST
  on testMe()
    set aName to name of me
    
–> "aTEST"
    
display dialog aName –Name of this script object (aTEST)
  end testMe
  
  
script bTEST
    on testMe()
      set aName to name of me
      
–> "bTEST"
      
display dialog aName –Name of this script object (bTEST)
    end testMe
  end script
end script

★Click Here to Open This Script 

Posted in OSA | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy | Leave a comment

最前面のアプリケーションの用語辞書を表示する v4

Posted on 1月 8, 2020 by Takaaki Naganoya

最前面のアプリケーションのAppleScript用語辞書をオープンするAppleScriptです。

macOS標準装備のScript Menuに入れて呼び出すことを前提に作りました。はるかかなた昔に作って、OSバージョンが上がるごとに細かい改修を行なって使い続けているものです。

この手のScriptは日常的にAppleScriptを書いている人間なら、たいてい書いてみたことがあるはずです。しかし、あまり生真面目なアプローチでアプリケーションバンドル中のsdefのパスを求めてオープンといった処理を行っていると、「例外」にブチ当たって困惑します。

sdefファイルを直接持っていないAdobe Creative Cloud製品です。InDesignあたりがそうなんですが、直接sdefを保持しておらず、どうやら実行時に動的に組み立てるようで、絶体パス(absolute path)で指定してもsdefをオープンできません。

また、Microsoft Office系アプリケーションのsdefも、外部の(OS側のsdef)テンプレートをincludeするようなので、生真面目に対象アプリケーションのInfo.plistの情報をもとにアプリケーションバンドル中のsdefファイルをオープンするように処理すると、sdefの一部のみを表示するようになってしまって、sdef全体を表示することができません。

そうしたもろもろの問題に当たって、結局アプリケーションそのものをScript Editorでオープンするように指定しています。

AppleScript名:–このアプリケーションの用語辞書を表示する v4
— Created 2017-07-23 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

–最前面のプロセスのファイルパスを取得する
set aFile to path to frontmost application
set aRec to (getAppPropertyFromInfoPlist(aFile, "NSAppleScriptEnabled") of me) as boolean

–スクリプト用語辞書をScript Editorでオープンする手順
if aRec = true then
  –OS X 10.10でScript Editor側からアプリケーションをオープンしてもダメだったので、Finder側からScript Editorで指定アプリをオープンすることに
  
try
    tell application "Finder"
      set apFile to (application file id "com.apple.scripteditor2") as alias
      
open aFile using application file apFile
    end tell
  on error
    tell application id "com.apple.scripteditor2"
      open aFile
    end tell
  end try
  
  
tell application id "com.apple.scripteditor2" to activate
  
else
  display dialog "本アプリケーションは、各種OSA言語によるコントロールに対応していません。" buttons {"OK"} default button 1 with icon 2 with title "Scripting非対応"
end if

on getAppPropertyFromInfoPlist(aP, aPropertyLabel)
  set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of aP)
  
set aBundle to current application’s NSBundle’s bundleWithURL:aURL
  
set aDict to aBundle’s infoDictionary()
  
  
set aRes to aDict’s valueForKey:aPropertyLabel
  
if aRes is not equal to missing value then
    set aRes to aRes as anything
  end if
  
  
return aRes
end getAppPropertyFromInfoPlist

★Click Here to Open This Script 

Posted in sdef | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy Script Editor | Leave a comment

path to temporary items

Posted on 1月 6, 2020 by Takaaki Naganoya

AppleScript users ML上で2016/10/16〜18に行われていた議論の内容を自分でも再確認しました(Thanks Yvan!)。一時フォルダの場所を求める「path to temporary items」の値が、macOS 10.12から変更になっています。


▲AppleScript Users ML上の議論のフロー(Mail Flow Visualizerによりバッチ出力。つまり、Mail.app上で出力フローを選択してAppleScriptでフロー図出力しています)

AppleScript標準装備の「path to」コマンドは、Classic MacOS環境からMac OS X環境に移行した後に重要度が上がったコマンドです。OS側が用意している特別な意味を持つフォルダの場所を返してくれます。

とくに、(いまさらですが)Mac OS X環境はマルチユーザー環境なので、とくにPicturesとかDocumentsとかDesktopとかの特別なフォルダのパスを求める機能は基礎的ではあるものの、とても重要です。このあたりをめんどくさがってなんでもかんでも固定パスで書きたがる人を見かけたことがありますが、その人が書いたプログラムは他のユーザー環境で動かなくて苦労していました(本人ではなく周囲の人々が)。

AdobeのCS/CCアプリケーションのサンプルAppleScriptでも固定パスで書かれたものを多数見かけましたが、あれはなんだったんでしょう。

ドメイン

もともと、path toコマンドにより求められる各種パスには、

system domain:/System 
network domain:/Network
user domain:~

などのほか、

local domain:/Library
Classic domain: Classic Mac OSのシステムフォルダ(Classic環境をサポートするOS&ハードウェアの組み合わせ上でのみ有効)

などの「ドメイン」が指定できることになっていました。system domainはOSのSystemが利用、User domainはユーザーのホームフォルダ以下。network domainはmacOSのNetBootが廃止/他の機能への移行対象となっている(すでに、iMac ProではNetBoot非サポート)ほか、そのような環境下にないと有意な結果が得られません。

作業用一時フォルダtemporary items

ドメインの区分けが存在するものの、これらの区分のうちClassic domainははるかかなた昔に消滅、network domainも使ったことのあるユーザーは稀(まれ)でしょう。

そんな中、作業用の一時フォルダの場所を求める「path to temporary items」の仕様がmacOS 10.12で変更になっていました。

テンポラリフォルダの特性ゆえに、細かいディレクトリ名はユーザー環境ごと、実行時ごとに微妙に異なりますが(赤字部分が変化する部分)、上の図では(↑)どのあたりに作られるのかという点に着目して色分けしてみました。

macOS 10.12以降では、user domainでもsystem domainでも同じような場所が指定されることになることがわかります。

ちなみに、Cocoaの機能を用いて求められる一時フォルダはまた別の場所が示されています。

use framework "Foundation"

current application’s NSTemporaryDirectory() as text
–> "/var/folders/h4/jfhlwst88xl9z0001s7k9vk00000gr/T/"

★Click Here to Open This Script 

Posted in File path History | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy | Leave a comment

Post navigation

  • Older posts
  • Newer posts

電子書籍(PDF)をオンラインストアで販売中!

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 15, Sequoia
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • Numbersで選択範囲のセルの前後の空白を削除
  • メキシカンハットの描画
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AppleScriptによる並列処理
  • macOS 15でも変化したText to Speech環境
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • デフォルトインストールされたフォント名を取得するAppleScript
  • AppleScript入門③AppleScriptを使った「自動化」とは?
  • 【続報】macOS 15.5で特定ファイル名パターンのfileをaliasにcastすると100%クラッシュするバグ
  • macOS 15 リモートApple Eventsにバグ?
  • Script Debuggerの開発と販売が2025年に終了
  • AppleScript入門① AppleScriptってなんだろう?
  • macOS 14で変更になったOSバージョン取得APIの返り値
  • NSObjectのクラス名を取得 v2.1
  • macOS 15:スクリプトエディタのAppleScript用語辞書を確認できない
  • 有害ではなくなっていたSpaces
  • AVSpeechSynthesizerで読み上げテスト

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (212) 13.0savvy (198) 14.0savvy (151) 15.0savvy (140) CotEditor (66) Finder (51) Keynote (119) NSAlert (61) NSArray (51) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (53) NSDictionary (28) NSFileManager (23) NSFont (21) NSImage (41) NSJSONSerialization (21) NSMutableArray (63) NSMutableDictionary (22) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (119) NSURL (98) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (76) Pages (55) Pixelmator Pro (20) Safari (44) Script Editor (27) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • Beginner
  • Benchmark
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • check sum
  • Clipboard
  • Cocoa-AppleScript Applet
  • Code Sign
  • Color
  • Custom Class
  • date
  • dialog
  • diff
  • drive
  • Droplet
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • Hex
  • History
  • How To
  • iCloud
  • Icon
  • Image
  • Input Method
  • Internet
  • iOS App
  • JavaScript
  • JSON
  • JXA
  • Keychain
  • Keychain
  • Language
  • Library
  • list
  • Locale
  • Localize
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • parallel processing
  • PDF
  • Peripheral
  • process
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • rectangle
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2025年7月
  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2024年2月
  • 2024年1月
  • 2023年12月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年12月
  • 2019年11月
  • 2019年10月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月
  • 2018年2月

https://piyomarusoft.booth.pm/items/301502

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org

Forum Posts

  • 人気のトピック
  • 返信がないトピック

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org
Proudly powered by WordPress
Theme: Flint by Star Verte LLC