Keynote、Pages、NumbersのiWorkアプリがバージョン14にアップデートされました。
本バージョンはmacOS 13以降に対応しています。
各アプリのAppleScript用語辞書に変更はありません。Pagesで見られている、ウィンドウで表示されていないページ上のオブジェクトからの情報取得ができない(正確にいえば、表示中の見開き+2見開き分まで取得可能)という挙動は変わっていません。どうも処理速度向上のための仕様のようなので、この部分はこのままだと思います。
Keynote、Pages、NumbersのiWorkアプリがバージョン14にアップデートされました。
本バージョンはmacOS 13以降に対応しています。
各アプリのAppleScript用語辞書に変更はありません。Pagesで見られている、ウィンドウで表示されていないページ上のオブジェクトからの情報取得ができない(正確にいえば、表示中の見開き+2見開き分まで取得可能)という挙動は変わっていません。どうも処理速度向上のための仕様のようなので、この部分はこのままだと思います。
電子書籍「Cocoa Scripting Course」の第7巻、NSColorを刊行しました。PDF 478ページです。
→ 販売ページ
本書は、Cocoa Scripting本の第7弾。色関連の処理をAppleScriptで行いたい人向けの解説書です。画像処理やRTF処理などで避けては通れない「色」に関する内容です。
色についての処理は割と概念が独特で、色空間、色の扱い、色差(ΔE)、明度計算などなど、知っていれば「そんなもんか」という程度のものですが、知らないとさっぱり分かりません。
ささいなOS上の色設定の情報をplistから読み取って処理するような場合にも、「普通、RGB値の色しか設定しないよね」と誰もが思っていたスクリプトエディタの構文色分け設定に、CMYK色やGrayscale色を設定しているユーザーがいて、慌てていろいろ対応する羽目になったりと、いい思い出がたくさんあります。
Adobe Swatch Exchangeファイル書き出しや、頻出色のリストアップ、近似色の計算や色差ΔEの計算など、今日明日からすぐに役立つ内容を多く含んでいます。
1章 入門編
Cocoa Scriptingの概要
Cocoa Scriptingってどういうもの?
Cocoa Scriptingの実際
Cocoa Scriptingの威力
Cocoa Scriptingのメリット
Cocoa Scriptingに必要なもの
Cocoa Scriptingまとめ
Cocoa Scripting9つの誓い
Cocoa Scriptingに適したmacOSについて
Cocoa Scripting環境の進化の歴史
Cocoa Scriptable macOS
参考資料:AppleScriptランタイム環境情報
Cocoa Scripting環境ごとの挙動の違い
SIP解除の是非
プログラミングスタイル
開発・実行環境のちがい
処理手順の違い
メインスレッド実行が必須な機能のScripting
delegation, notification
実行スタイルの違いによる書き換え
AppleScriptでCocoaオブジェクトを呼び出すと…
サブルーチン記述
オブジェクト階層を示すmyとme
クラス拡張
高速なCocoa Scriptを書くためには
アプリケーションとのやりとり
暗黙の型変換
一部のコマンドで書き換えが必要
計算の優先順位を示すカッコを修正
オブジェクトの数え方
情報の調べ方
Cocoa Scriptingを行う際の調べ方
Appleのオンラインドキュメント
Xcodeでヘッダーファイルを「素早く開く」
ヘッダーファイルの歩き方
ヘッダーファイルの構成要素
Deprecatedな機能に遭遇した場合
Enum(定数)の記載パターン
AppleScriptの数値表現幅を超えるEnum(定数)
2章 実践編
Cocoa Scriptを実際に動かす
Script Editor/Script Debuggerを起動
Cocoa Scriptを実行
Cocoa Objectのログを表示
Cocoa Scriptの書類を保存
Cocoa Scriptのエクスポート形式
Objective-CのCocoa呼び出し記述をAppleScript記述に翻訳する
Cocoa Script(AppleScriptObjC)の構成
Objective-Cの各種データ表記書き換え(1/3)
Objective-Cの各種データ表記書き換え(2/3)
Objective-Cの各種データ表記書き換え(3/3)
Cocoaメソッド名の大文字小文字指定
Cocoaメソッド名の変換(1/3)
Cocoaメソッド名の変換(2/3)
Cocoaメソッド名の変換(3/3)
基礎的なCocoaオブジェクト解説
メソッド呼び出し時のパラメータ
NSString(文字列)
NSArray(配列)
NSDictionary(辞書)
Number(数値)
Enum(定数)
nil
NSObject
Cocoa Scriptingの特徴的な動き
AppleScriptとCocoa間の
オブジェクト変換
AppleScriptオブジェクトに対応するCocoaクラス
配列関連のCocoaクラス
レコード関連のCocoaクラス
文字列関連のCocoaクラス
日付関連のCocoaクラス
File Path関連オブジェクト
File Path関連オブジェクト変換方法
画像関連Cocoaオブジェクト
ファイルパス文字列(NSString)関連(1/2)
ファイルパス文字列(NSString)関連(2/2)
URL関連
Remote URL文字列関連(1/2)
Remote URL文字列関連(2/2)
Local File URL文字列関連
配列関連
Dictionary関連
NSString文字エンコーディング関連
Color関連
HTML関連
Cocoa Object同士の変換、生成
NSData
Styled String(1/2)
Styled String(2/2)
2次元座標データ
1次元座標系データ
言語、Locale系データ
有用なCocoaオブジェクト(抜粋)
3章 NSColor編
Colorデータの位置付けと役割
NSColor Basic Samples
NSColorList Basic Samples
NSColorSpace Basic Samples
4章 Color処理 基礎編
choose colorコマンドで表示されるカラーピッカーの使い方
choose colorコマンドで指定したRGB色でNSColorを作成
Numbers書類上に記入したRGB値を色プレビュー
NSColorからRGBAの各要素を取得
RGB色からHSBA色に変換
NSColorからHSBAの各要素を取得
NSColorから色空間名を取得
鉛筆(クレヨン)ピッカーに登録されている色名を取得
5章 Color処理 上級編
色から明度情報を取得
画像の指定座標のピクセルの色情報を取得
AppleScriptの構文色分け設定の書式情報読み取り
HTML色コードの取り扱い
CIColorを作成してCoreImageフィルタを実行
ざっくりとした色判定(カラードメイン処理)
色差(ΔE)を計算する
色名を推定(dbColNamesKit)
色のポスタライズ
頻出色の抽出(ColorCube)
2つの色の合成
輝度をMAXにした色を取得(Colours)
Adobe Swatch Exchangeファイル作成
画像の空白判定
添付サンプルScript紹介
資料編
Cocoa Scripting関連のAppleScript命令
Cocoa ScriptingとScript Object
AppleScript Droplet
サードパーティ製FrameworkやAppleScript Librariesを呼ぶ
AppleScript mini reference
AppleScript 各種ランタイム環境および関連ツール
AppleScript予約語一覧
エラーコード表
理解度確認テスト
あとがき、奥付
NaturalLanguage.frameworkを用いて、英語の文章の意味的な距離を測るAppleScriptです。
単語単位の意味的な距離を計算する機能はいまひとつ使い道が限定される感じですが、文単位での意味的な距離の計算には期待してしまうところです。
実際にやってみました。
やってはみたものの、なにかピンと来ないというか、このAPIは1つの文章だけで距離を測るためのものなのか、それとも複数の文の塊で計算するものなのか、、、、
文章のかたまりでも計算できているようです。いろいろサンプル文章をひろってみて距離を計測してみましたが、「なんとなくそんな感じ」の結果が返ってくるだけです。
これは別にAppleが悪いということではなくて、自然言語処理ってこんな感じです。相対的な違いでしかないので、その結果をもって「いい」「わるい」という評価が行えるわけではなく「なんとなくこっち」という判断をするだけです。ただ、間違うこともあるので、その点をあらかじめ知っておくことが重要です。
AppleScript名:英語で文章同士の距離を測る_English.scpt |
— – Created by: Takaaki Naganoya – Created on: 2024/03/13 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.8" — Monterey (12.0) or later use framework "Foundation" use framework "NaturalLanguage" use scripting additions set targLang to current application’s NLLanguageEnglish set aEmb to current application’s NLEmbedding’s sentenceEmbeddingForLanguage:(targLang) if aEmb = missing value then return –NLLanguageJapanese is not available here in macOS 13 set aSent to "This is my book." set bSent to "We the People of the United States, in Order to form a more perfect Union, establish Justice, insure domestic Tranquility, provide for the common defence, promote the general Welfare, and secure the Blessings of Liberty to ourselves and our Posterity, do ordain and establish this Constitution for the United States of America." set cSent to "Thanks for updating Takaaki! You have almost completed updating AdRotate to version 5.12.9! To complete the update click the button on the right. This may take a few seconds to complete! For an overview of what has changed take a look at the development page and usually there is an article on the blog with more information as well." set dSent to "He says that he like to read something with iPad." set aDist to (aEmb’s distanceBetweenString:aSent andString:bSent distanceType:(current application’s NLDistanceTypeCosine)) –> 1.350924730301 set bDist to (aEmb’s distanceBetweenString:aSent andString:cSent distanceType:(current application’s NLDistanceTypeCosine)) –> 1.374191045761 set cDist to (aEmb’s distanceBetweenString:aSent andString:dSent distanceType:(current application’s NLDistanceTypeCosine)) –> 1.168848276138 |
NaturalLanguage.frameworkには各種言語の定義を行なった定数が57ほど定義されているようです。ただし、これらの定義がすべて利用できるわけがありません(Appleのやることなので、必ずミスやもれがあります)。
とりあえず、本当にどのぐらいの言語が使えるのか、チェックしておくことが必要です。
結論からいえば、Appleが何を考えているのかよくわかりません。macOS 13では7言語ほど使えるという結果になりましたが、macOS 14では英語しか使えないという結果になっています。OSがバージョンアップするとOSの機能が低下するという理解不能な挙動を示しています。バグ、、、なのかも????
Appleが用意した新機能は、ひととおり「本当に使えるのか」をチェックする必要があります。だいたいは搭載されて1発目はバグだらけで、OSのメジャーアップデートを経て良くなったり、よくならなかったりします。
この機能はどちらなんでしょう? Shortcutみたいに「救いようがない」のもありますが……
AppleScript名:指定言語でNLEmbeddingを処理できるかチェック_13_14.scpt |
— – Created by: Takaaki Naganoya – Created on: 2024/03/13 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.8" use framework "Foundation" use framework "NaturalLanguage" use scripting additions –The result is on macOS 13.6.5 / 14.4 set aRes to testNLLanguage("NLLanguageEnglish") of me –> true set aRes to testNLLanguage("NLLanguageFrench") of me –> true–>false (macOS 14) set aRes to testNLLanguage("NLLanguageGerman") of me –> true–>false (macOS 14) set aRes to testNLLanguage("NLLanguageItalian") of me –> true–>false (macOS 14) set aRes to testNLLanguage("NLLanguagePortuguese") of me –> true–>false (macOS 14) set aRes to testNLLanguage("NLLanguageSimplifiedChinese") of me –> true–>false (macOS 14) set aRes to testNLLanguage("NLLanguageSpanish") of me –> true–>false (macOS 14) set aRes to testNLLanguage("NLLanguageUndetermined") of me –> true –Natural Language framework doesn’t recognize. set aRes to testNLLanguage("NLLanguageAmharic") of me –> false set aRes to testNLLanguage("NLLanguageArabic") of me –> false set aRes to testNLLanguage("NLLanguageArmenian") of me –> false set aRes to testNLLanguage("NLLanguageBengali") of me –> false set aRes to testNLLanguage("NLLanguageBulgarian") of me –> false set aRes to testNLLanguage("NLLanguageBurmese") of me –> false set aRes to testNLLanguage("NLLanguageCatalan") of me –> false set aRes to testNLLanguage("NLLanguageCherokee") of me –> false set aRes to testNLLanguage("NLLanguageCroatian") of me –> false set aRes to testNLLanguage("NLLanguageCzech") of me –> false set aRes to testNLLanguage("NLLanguageDanish") of me –> false set aRes to testNLLanguage("NLLanguageDutch") of me –> false set aRes to testNLLanguage("NLLanguageFinnish") of me –> false set aRes to testNLLanguage("NLLanguageGeorgian") of me –> false set aRes to testNLLanguage("NLLanguageGreek") of me –> false set aRes to testNLLanguage("NLLanguageGujarati") of me –> false set aRes to testNLLanguage("NLLanguageHebrew") of me –> false set aRes to testNLLanguage("NLLanguageHindi") of me –> false set aRes to testNLLanguage("NLLanguageHungarian") of me –> false set aRes to testNLLanguage("NLLanguageIcelandic") of me –> false set aRes to testNLLanguage("NLLanguageIndonesian") of me –> false set aRes to testNLLanguage("NLLanguageJapanese") of me –> false set aRes to testNLLanguage("NLLanguageKannada") of me –> false set aRes to testNLLanguage("NLLanguageKazakh") of me –> false set aRes to testNLLanguage("NLLanguageKhmer") of me –> false set aRes to testNLLanguage("NLLanguageKorean") of me –> false set aRes to testNLLanguage("NLLanguageLao") of me –> false set aRes to testNLLanguage("NLLanguageMalay") of me –> false set aRes to testNLLanguage("NLLanguageMalayalam") of me –> false set aRes to testNLLanguage("NLLanguageMarathi") of me –> false set aRes to testNLLanguage("NLLanguageMongolian") of me –> false set aRes to testNLLanguage("NLLanguageNorwegian") of me –> false set aRes to testNLLanguage("NLLanguageOriya") of me –> false set aRes to testNLLanguage("NLLanguagePersian") of me –> false set aRes to testNLLanguage("NLLanguagePolish") of me –> false set aRes to testNLLanguage("NLLanguagePunjabi") of me –> false set aRes to testNLLanguage("NLLanguageRomanian") of me –> false set aRes to testNLLanguage("NLLanguageRussian") of me –> false set aRes to testNLLanguage("NLLanguageSinhalese") of me –> false set aRes to testNLLanguage("NLLanguageSlovak") of me –> false set aRes to testNLLanguage("NLLanguageSwedish") of me –> false set aRes to testNLLanguage("NLLanguageTamil") of me –> false set aRes to testNLLanguage("NLLanguageTelugu") of me –> false set aRes to testNLLanguage("NLLanguageThai") of me –> false set aRes to testNLLanguage("NLLanguageTibetan") of me –> false set aRes to testNLLanguage("NLLanguageTraditionalChinese") of me –> false set aRes to testNLLanguage("NLLanguageTurkish") of me –> false set aRes to testNLLanguage("NLLanguageUkrainian") of me –> false set aRes to testNLLanguage("NLLanguageUrdu") of me –> false set aRes to testNLLanguage("NLLanguageVietnamese") of me –> false on testNLLanguage(aLangName) set aText to "use AppleScript use framework \"Foundation\" use framework \"NaturalLanguage\" set targLang to (current application’s " & aLangName & ") set aEmb to current application’s NLEmbedding’s wordEmbeddingForLanguage:(targLang) if aEmb = missing value then return false return true " return run script aText end testNLLanguage |
NaturalLanguage frameworkといえば、macOS 10.14で追加されたものですが、自然言語テキストが「何語」であるかを推測するなどの使い方をAppleScriptから行なってきました。正直、その程度しか「役に立つ機能がない」という認識でした。
日本語のサポートはまだまだですが、日本語でなければ意外と使えることがわかりました。
試しに、NaturalLanguage.frameworkの機能を用いて指定の英単語の類義語を生成して、それぞれの元の単語との意味的な距離を計算してみました。
自然言語処理的にわかりやすい言葉でいえば、類語語のリストをword2vecでベクトル化してコサイン距離を計算する、というところでしょうか。
類義語展開であれば、日本語WordNetを利用して検索するAppleScriptを4年ぐらい前に試作ずみなので、このOS側の類義語展開機能がなくても別に構わないのですが、word2vecやsentence2vecで単語や文章をベクトル化して意味的な距離を計測する演算については、利用したいところです。
ただ、OSの機能が向上するどころか退化しているようなので、この分野ではmacOSの進歩は期待できないのかもしれません。
AppleScript名:指定単語の類義語を展開して元の単語との距離を測る.scpt |
— – Created by: Takaaki Naganoya – Created on: 2024/03/12 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use framework "NaturalLanguage" use scripting additions set targLang to current application’s NLLanguageEnglish set aEmb to current application’s NLEmbedding’s wordEmbeddingForLanguage:(targLang) if aEmb = missing value then return –NLLanguageJapanese is not available here in macOS 13 –類義語展開(Max.50) set aWord to "computer" set aSym to (aEmb’s neighborsForString:aWord maximumCount:20 distanceType:(current application’s NLDistanceTypeCosine)) as list –コサイン距離を計測(0.0〜2.0)数字が小さいと近いはず。ちょっとでも意味が遠いと2.0になるという悪癖を持つ set distList to {} repeat with i in aSym set j to contents of i set aDist to (aEmb’s distanceBetweenString:aWord andString:j distanceType:(current application’s NLDistanceTypeCosine)) set the end of distList to {wordName:j, wordDistance:aDist as real} end repeat –昇順ソート set bList to sortRecListByLabel(distList, "wordDistance", true) of me –> {{wordDistance:0.837697923183, wordName:"workstation"}, {wordDistance:0.875068962574, wordName:"mainframe"}, {wordDistance:0.886509418488, wordName:"laptop"}, {wordDistance:0.901307225227, wordName:"software"}, {wordDistance:0.901674091816, wordName:"computing"}, {wordDistance:0.904342055321, wordName:"palmtop"}, {wordDistance:0.951638877392, wordName:"desktop"}, {wordDistance:0.954249441624, wordName:"intranet"}, {wordDistance:0.958346903324, wordName:"keystroke"}, {wordDistance:0.961381614208, wordName:"notebook"}, {wordDistance:0.964299142361, wordName:"server"}, {wordDistance:0.970234155655, wordName:"hardware"}, {wordDistance:0.974493980408, wordName:"pager"}, {wordDistance:0.981385648251, wordName:"electronic"}, {wordDistance:0.984282553196, wordName:"peripheral"}, {wordDistance:0.993325233459, wordName:"machine"}, {wordDistance:0.996084809303, wordName:"diskette"}, {wordDistance:0.999181330204, wordName:"portable"}, {wordDistance:1.001676082611, wordName:"compatible"}, {wordDistance:1.00532245636, wordName:"programmer"}} –リストに入れたレコードを、指定の属性ラベルの値でソート on sortRecListByLabel(aRecList as list, aLabelStr as string, ascendF as boolean) 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 sortedArray to aArray’s sortedArrayUsingDescriptors:{sortDesc} set bList to (sortedArray) as anything return bList end sortRecListByLabel |
本当は単語ではなく「文章」の距離を計測できないと実用性が低いところです。word2vecではなくsentence2vecの演算を行いたいところ。
自作のAppleScriptによるアイデアプロセッサ「Kamenoko」も、当初から自然言語処理の機能を盛り込むことを企画していました。sentence2vecぐらいの演算を行なって、各ノードに書いてある文章同士の距離を計測して、距離に応じて色を変えるといった機能も検討していました。
ただ、そうした機能を実装するのに割とデータ量が多くなるとか、アプリとしてパッケージングするのに無理があるとか、もういっそWebサーバー側で処理したほうがいいんじゃないの? 的な話になって見送った経緯があります。
このNaturalLanguage.frameworkがもっと使えるように、なったらいいのに。簡体字の中国語に対応しているぐらいなので、日本語への対応も期待したいところですが……macOS 14では対応言語が英語だけになるなど、展開の仕方が謎であります。
CotEditorで2つの書類をオープンしておき、行単位での差分を検出し、新規書類に結果を出力するAppleScriptです。
もともと、macOS搭載のFramework名一覧の差分を検出する資料を作成する必要があり、これを片付けるために作成しました。
本AppleScriptを実行すると……
のように、結果を出力します。それほど巨大なデータを想定して作ってはいないので、ほどほどの規模に抑えて利用してください。
AppleScript名:左右のドキュメントを比較.scpt |
use AppleScript version "2.4" use scripting additions use framework "Foundation" script spd property aList : {} property bList : {} end script set (aList of spd) to {} set (bList of spd) to {} tell application "CotEditor" set dCount to count every document if dCount is not equal to 2 then display notification "Error: This script needs only 2 documents" return –Document number Error end if tell window 1 set w1Bounds to bounds copy w1Bounds to {w1X1, w1Y1, w1X2, w1Y2} set w1Doc to document of it end tell tell window 2 set w2Bounds to bounds copy w2Bounds to {w2X1, w2Y1, w2X2, w2Y2} set w2Doc to document of it end tell if w1X1 > w2X1 then set {w1, w2} to {2, 1} else set {w1, w2} to {1, 2} end if tell document w1 –左ウィンドウ set (aList of spd) to paragraphs of contents end tell tell document w2 –右ウィンドウ set (bList of spd) to paragraphs of contents end tell end tell –ゴミ掃除 set (aList of spd) to cleanUp1DList((aList of spd), {" "}) of me set (bList of spd) to cleanUp1DList((bList of spd), {" "}) of me –差分計算 set (cList of spd) to getDiffBetweenLists((aList of spd), (bList of spd)) of me –結果出力テキスト組み立て set aRes to listToTextUsingDelim(addItems of (cList of spd), "") set bRes to listToTextUsingDelim(minusItems of (cList of spd), "") –結果の新規書類への出力 set d3 to makeNewCotEditorDoc("左→右で追加された項目" & return & return & aRes) of me set d4 to makeNewCotEditorDoc("左→右で削除された項目" & return & return & bRes) of me on getDiffBetweenLists(aArray as list, bArray as list) set allSet to current application’s NSMutableSet’s setWithArray:aArray allSet’s addObjectsFromArray:bArray –重複する要素のみ抜き出す set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray) –重複部分を削除する allSet’s minusSet:duplicateSet set resArray to (allSet’s allObjects()) as list set aSet to current application’s NSMutableSet’s setWithArray:aArray set bSet to current application’s NSMutableSet’s setWithArray:resArray aSet’s intersectSet:bSet –積集合 set addRes to aSet’s allObjects() as list set cSet to current application’s NSMutableSet’s setWithArray:bArray cSet’s intersectSet:bSet –積集合 set minusRes to cSet’s allObjects() as list return {addItems:minusRes, minusItems:addRes} end getDiffBetweenLists on cleanUp1DList(aList as list, cleanUpItems as list) set bList to {} repeat with i in aList set j to contents of i if j is not in cleanUpItems then set the end of bList to j end if end repeat return bList end cleanUp1DList –デリミタ文字を指定してリストを文字列化 on listToTextUsingDelim(aList, aDelim) set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to aDelim set outText to every text item of aList set outText to outText as string set AppleScript’s text item delimiters to curDelim return outText end listToTextUsingDelim –指定テキストでCotEditorの新規書類を作成 on makeNewCotEditorDoc(aCon) tell application "CotEditor" activate set newDoc to make new document tell newDoc set contents to aCon end tell end tell end makeNewCotEditorDoc |
Pagesのいつかのバージョンから現在表示中のページから離れたページのオブジェクト情報取得および操作ができなくなっていました。バージョン13.xではすでにそうなっていました。12.xからそうだったかもしれません。
2024/4/3追記:Pages v14.0で確認したところ、同じ挙動でした
1〜2ページを表示中に、3〜4ページのオブジェクト情報取得および操作は行えるものの、7〜8ページ以降のオブジェクト情報は取得できないという状況です。自分が確認したのはtableオブジェクトのposition情報。
25%の縮小表示を行った場合には、
問題なく、すべてのページのtable(ツメ)のpositionを取得できますが、
拡大表示すると……
7ページ以降のtableのpositionを取得できていません。
この現象は、全ページに対してツメ(Dictionary index)を付加して統一操作を行うAppleScriptにおいて問題になっていました。実際に、ファイル名に「章番号」を書いておくと、それをピックアップして、ツメの見た目を変更するというAppleScriptを作成して運用しています。このScriptは、ツメの塗りの状態を自動検知して当該章の塗り方を自動で反映するようになっています。
このような高機能Scriptを実用化したものの、最近になっておかしな挙動が確認されていました。
・現在表示中のページのオブジェクト操作は行える
・表示中から離れたページのオブジェクト操作/情報取得が行えない
なんじゃこら????
Pages書類のツメ操作で、いろいろ問題に。
そこで、実験のために表示ページを移動しながらオブジェクト情報を取得してみたら、問題なく情報取得できました。
Pagesには表示対象ページの変更機能はないので、GUI Scriptingで「次のページ」コマンドを強引に実行。あるいは、実行前にPagesの書類表示ズーム倍率を、25%に変更しておく……というほうが「楽」かもしれません。
これをバグとして報告すべきなのか、アプリケーションの挙動として「知っておくべき情報」なのかは判断できません。処理速度向上のための「改善」の結果としてこのような状況が生まれてしまったのかもしれないためです。
ただ、特定のページを表示状態にする機能がないのに、表示範囲外(現在の見開きから+2見開きを超える範囲)のオブジェクトの情報を取得できないのは、片手落ちの状態でしょう。
Adobe Acrobatは、一応AppleScript用語辞書がついてはいるものの、ほぼ「使えないアプリ」「役に立たない用語辞書」の名をほしいままにしてきました。AppleScript界における「がっかり遺産」のような存在です。
登場以来、一番期待されるPDF本文テキスト抽出の用途にまったく役に立たない(文字化けした謎テキストを出力)うえに、TOCやBookmarkへのアクセスもさっぱりです。
Classic MacOS時代にAdobe AcrobatのAppleScript用語辞書への深い失望があって、そこからフリーの「Skim PDF Viewer」の登場とか、のちにCocoaを直接呼べるようになって、十分なPDFへのアクセスが行えるようになりました。もはや、「もっといいもの」がいろいろ存在しているため、PDFを操作したいとか情報を抽出したいという需要は別のものによって満たされている状態です。
いまや、Adobe AcrobatのAppleScript用語辞書の存在感は「歴史上、そんなものがあったと語りつがれさえもしない」という「Air」のようなレベルです。事実、それに見出せる価値は何もありません。
そうした歴史認識と前提となる話がありつつも、それでも1つだけAdobe Acrobatには価値ある機能が存在します。本当に1つだけ。
それが、PDFの圧縮機能です。
最近は、macOS上のQuartzFilterのPDF圧縮もまったく機能しておらず、逆に呼び出すとファイルサイズが大きくなるとかいう笑えない冗談みたいな状態。PDFの圧縮ソリューションについてはAdobe Acrobatないしはactobat.adobe.comのWebアプリぐらいしか、手軽に使えるものが存在していない状態です。
とはいうものの、Adobe AcrobatのPDF圧縮機能は、AppleScript用語辞書に呼び出し用のコマンド用語が用意されてはいません。強引にGUIを操作するしかないようです。
Adobe AcrobatのAppleScript用語辞書の中にも「execute」コマンドが用意されており、任意のメニュー項目を操作できるような雰囲気が漂っていますが、いくら指定しても操作できません。
というわけで、とても嫌ではあるもののGUI Scripting経由で機能にアクセス。ちなみに、こういう時のために用意しておいた「dynamicMenuClicker」ライブラリは、Adobe Acrobat向けにはうまく動作しません。アプリケーション名、プロセス名、表示プロセス名などでAdobe Acrobatは不具合を持つ「特異点」であるため、Acrobatを操作する場合にのみ別の対処ルーチンを組み込んでおく必要があることでしょう。
AppleScript名:GUI Scripting経由でオープン中のPDFのファイルサイズを縮小.scpt |
tell application "Adobe Acrobat" tell front document set aCount to count every document if aCount = 0 then return end tell end tell activate application "Adobe Acrobat" tell application "System Events" tell process "Acrobat" –ファイル>その他の形式で保存>サイズが縮小されたPDF… click menu item 1 of menu 1 of menu item 9 of menu 1 of menu bar item 3 of menu bar 1 delay 0.5 –ダイアログ上のボタン「OK」をクリック tell window 1 click button "OK" end tell delay 0.5 –保存ダイアログ(名前を付けて保存) tell window 1 click button "保存" –Localized delay 0.5 set sList to every sheet if length of sList is not equal to 0 then tell sheet 1 click button "置き換え" –Localized end tell end if end tell end tell end tell |
下記Scriptは、動作しません。
AppleScript名:本来はこう書けば動くはずだったメニュー操作.scpt |
use dynC : script "dynamicClicker"
set appName to "AdobeAcrobat" –Application Name set aList to {"ファイル", "その他の形式で保存", "サイズが縮小されたPDF…"} –Localized Menu Titles set aRes to clickSpecifiedMenuElement(appName, aList) of dynC |
Macの処理速度を測るのにちょうど手頃な内容のプログラムです。与えた配列要素の、順列組み合わせ計算を行います。
M2 MacBook Air@macOS 15.1の環境の実行結果は、
–> {{4, 0.004417896271}, {5, 0.009887933731}, {6, 0.063844919205}, {7, 0.450636982918}, {8, 3.521628022194}, {9, 31.777850985527}}
なので、ほとんどM1 Mac miniと変わりません(少し遅いぐらい)。
AppleScript名:与えられた文字列の1D Listのすべての順列組み合わせパターン文字列を返す v3_for benchmark.scptd |
— 2014-10-06 Original By Nigel Garvey@macscripter.net — 2019-06-19 Modified By Takaaki Naganoya — 2024-02-18 Modified By Takaaki Naganoya use AppleScript version "2.4" use scripting additions use framework "Foundation" script spdPerm property permutations : missing value property allRes : {} end script on run set allList to {{"A", "T", "G", "C"}, {"A", "T", "G", "C", "1"}, {"A", "T", "G", "C", "1", "2"}, {"A", "T", "G", "C", "1", "2", "3"}, {"A", "T", "G", "C", "1", "2", "3", "4"}, {"A", "T", "G", "C", "1", "2", "3", "4", "5"}} repeat with i in allList set theList to contents of i set a1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate() set aRes to permute(theList) of me set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate() set c1Dat to (b1Dat – a1Dat) set the end of (allRes of spdPerm) to {length of theList, c1Dat} end repeat return (allRes of spdPerm) — MacBook Pro 2012 Retina Core i7 2.6GHz@macOS 10.14.6 の実行結果 –> {{4, 0.01 }, {5, 0.010347008705}, {6, 0.05}, {7, 1.44}, {8, 11.54}, {9, 107.271}} –M1 Mac mini@macOS 13.6.5 の実行結果 –> {{4, 0.005248069763}, {5, 0.01240503788}, {6, 0.063866019249}, {7, 0.434872984886}, {8, 3.519423961639}, {9, 31.62052500248}} end run on permute(theList as list) set theArray to current application’s NSMutableArray’s arrayWithArray:theList set (permutations of spdPerm) to current application’s NSMutableArray’s array() prmt(theArray, 0, (count theList) – 1) –Return AppleScript string list set aFinishArray to current application’s NSMutableArray’s new() set anEnum to (permutations of spdPerm)’s objectEnumerator() repeat set aValue to anEnum’s nextObject() if aValue = missing value then exit repeat set aStr to aValue’s componentsJoinedByString:"" (aFinishArray’s addObject:aStr) end repeat return aFinishArray as list end permute on prmt(theArray, theStart as number, theEnd as number) if (theStart = theEnd) then (permutations of spdPerm)’s addObject:theArray else repeat with x from theStart to theEnd set theCopy to theArray’s mutableCopy() –swap if (x > theStart) then (theCopy’s exchangeObjectAtIndex:theStart withObjectAtIndex:x) prmt(theCopy, theStart + 1, theEnd) end repeat end if end prmt |
Pages書類で選択中のtext item(Pagesでこれを識別するクラスがないのでshape)内のテキストに複数の文字サイズが存在している場合に、特定の文字サイズ部分のみ異なるものに置き換えるAppleScriptです。
ただし、本Scriptで使用している自作のdisplay text fieldsライブラリを、本ScriptをmacOS標準搭載の「スクリプトメニュー」に入れた状態で呼び出すと、ダイアログ中への文字入力ができませんでした(macOS 13.6.5)。Pagesの書類の方に文字入力フォーカスが残ってしまっています。文字サイズをポップアップメニューからの選択方式にするなど、テキスト入力「以外」の方法に差し替えることで対処できることは判明しています。
このあたりのmacOS側の挙動に対して、「ナニコレ?」と違和感をおぼえつつも……スクリプトメニューに入れて呼び出す場合には対処するしかないのでしょう。細かい機能がAppleScriptランタイム環境ごとに「使える」「使えない」といった違いを生んでいるうえに、こうしたGUIの挙動についてもAppleScriptランタイム環境ごとに違っている点について、より細かい点をチェックする必要がありそうです(メーカー側がどんどん基礎的な部品の挙動を変更しては発表もしない状況)。
▲架空の本のPages書類のうち、処理対象のtext itemを選択状態にして実行
▲どのフォントサイズを置き換えるかをダイアログ選択。リサイズ後の数値を入力するとリサイズ。空欄のままにすると、リサイズしない
AppleScript名:最前面の書類中の選択中のテキストアイテムの文字サイズを、特定サイズのみ対象にして置換 v3.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/02/16 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.7" — macOS 10.13 or later use framework "Foundation" use scripting additions use tfLib : script "display text fields" tell application "Pages" tell front document set tmpList to selection repeat with i in tmpList set j to contents of i set tmpC to class of j –選択中のアイテムがshape(text itemを指定したいが、PagesではこのClassは存在しない)の場合のみ処理 if tmpC is equal to shape then –最大サイズの文字のみ抽出 set cRes to (size of every character of object text of j) set uRes to removeDuplicates(cRes) of me set selection to {j} –ダイアログ表示 set strList to stringfyListItems(uRes) of me set blankList to makeBlankListByIndicatedItem(strList, "") of me set dRes to confirm text fields main message "テキストアイテムの文字サイズ置換" sub message "置換しない場合には空欄のまま。サイズはポイント数で指定" key list strList value list blankList if dRes = false then exit repeat –文字サイズ置換 repeat with ii from 1 to (length of strList) set targSize to (contents of item ii of strList) as real —From Size set repSize to contents of item ii of dRes –To Size if repSize is not equal to "" then set repSizeNum to repSize as real set size of (every character of object text of j whose size is targSize) to repSizeNum end if end repeat end if end repeat end tell end tell –指定リストの項目数によって、空白アイテムが入ったリストを返す on makeBlankListByIndicatedItem(aList, blankItem) set newList to {} set aLen to length of aList repeat aLen times set the end of newList to blankItem end repeat return newList end makeBlankListByIndicatedItem –リストの全項目をテキスト化 on removeDuplicates(aList) set newList to {} repeat with i from 1 to (length of aList) set anItem to item 1 of aList set aList to rest of aList if {anItem} is not in aList then set end of newList to anItem end repeat return newList end removeDuplicates –リスト内の要素をすべてテキストに変換する on stringfyListItems(a as list) set newL to {} repeat with i in a set j to contents of i set j to j as string set the end of newL to j end repeat return newL end stringfyListItems |
macOS 13.6.5アップデート(13.6.5(22G605))が配信されましたが、AppleScript系のバグは直っていません。
Appleのエンジニアは、「会社から給料をもらって日々新しいバグを作るのが仕事」という状況です。新しい機能よりも、新しいバグの方が多いというのは、もはやメーカーではなくてクラッシャーと名乗るべきなのでは?
・スクリプトエディタ上のテンプレートから選択するCocoa-AppleScript Appletランタイムが動作しなくなった
・スクリプトエディタ上でscpt形式のAppleScript書類に書いた「説明」が白地に白文字で表示されて見えなくなる
・日本語環境で、特定のTTSキャラクタ名(Bells、Hysterical、Organ、Princess、Trinoids、Whisper)が指定できない
2023年に使用していたmacOS:macOS 13
毎年行なっている、Piyomaru Softwareが書いたAppleScriptの1年を振り返る記事の2023年版です。10年ほど続けてきた旧「AppleScriptの穴」Blogが2018年の年初にホスティング会社との行き違いでシャットダウンされ、再構築したのがこの現行の「AppleScriptの穴」Blogです。
→ 2018年に書いた価値あるAppleScript
→ 2019年に書いた価値あるAppleScript
→ 2020年に書いた価値あるAppleScript
→ 2021年に書いた価値あるAppleScript
→ 2022年に書いた価値あるAppleScript
旧「AppleScriptの穴」Blogの内容については、データベースから抜き出したデータをもとに再構成した「Blogアーカイブ本」にまとめています。
AppleScriptの穴Blogアーカイブvol.1
AppleScriptの穴Blogアーカイブvol.2
AppleScriptの穴Blogアーカイブvol.3
AppleScriptの穴Blogアーカイブvol.4
AppleScriptの穴Blogアーカイブvol.5
AppleScriptの穴Blogアーカイブvol.6
本Blogは、機械翻訳で翻訳しやすいように、平易な日本語で記述してある点がチャームポイントです。それはもう、小学生の日記ぐらいの難易度で。もともとは、2000年代初頭に開発していた「人工知能インタフェース Newt On」のソースコード部品バラバラにして掲載し、用いた部品を個別にメンテナンスすることを「隠れた目的」としていました。また、Scripter間のノウハウの共有を推進することも目的としています。
AppleScript以外の一般的なテーマの記事については、こちらにいろいろ投稿しています。
2023年的な状況といいますか、昨今のMac環境をとりまく状況として新バージョンのmacOSとしてmacOS 14がありつつも、Appleがマイナーアップデートで新たなバグを盛り込んでくるため、macOS 14に付き合うこと自体がリスクです。β版で確認を行なっても、Release版で安定度が激下がりして、その後にバグ改修と新機能追加が行われるため、つねにどこかにド派手な不具合を抱えているという状況です。
2023年にはそれほど発表できるようなAppleScriptを書いていない(=自分の作業を効率化するものしか書いていないので外部に発表のしようがない)のと、それほど技術レベルや解決策のレベルが上がったような内容のものはありません。
さまざまな技術的な内容をまとめた記事については、電子書籍に掲載したり、付録Scriptとして添付しています。年間19冊出しています。
ポケコンサークル「LL」会誌Vol.19復刻版(282ページ)
AppleScript基礎テクニック集(29)セキュリティ機能解除(36ページ)
AppleScript+Xcodeで作るMacアプリ(484ページ)
ChatGPTにAppleScriptを書かせてみた!(76ページ)
AppleScript基礎テクニック(30)コンテクストメニューScriptの作り方(41ページ)
AppleScript基礎テクニック(30)コンテクストメニューScriptの作り方 英語版(41ページ)
AppleScript基礎テクニック(31)スクリプトバンドルの活用(34ページ)
AppleScript 7つの宝珠(3)(35ページ)
Cocoa Scripting Course #5 NSImage(473ページ)
ゆっくりAppleScript解説(1)(45ページ)
ゆっくりAppleScript解説(2)(45ページ)
つたわる資料のつくりかた(66ページ)
Keynote Scripting Book With AppleScript(434ページ)
Cocoa Scripting Course #6 PDFKit(560ページ)
ゆっくりAppleScript解説(3)(42ページ)
AppleScript最新リファレンス v2.8(1008ページ)
AppleScript最新リファレンス v2.8英語版(223ページ)
戦場の絆〜僕らの15年戦争〜v2(394ページ)
Piyomaru Software電子書籍カタログ 2024冬(100ページ)
2023年に書いたものは、例年どおりの「価値あるAppleScript」と言うほどのものではなく、「2023年に書いた記事の中で注目すべきもの」をリストアップするという程度の内容になりそうです。
住所ジオコーディング(住所→緯度経度情報)/逆住所ジオコーディング(緯度経度情報→住所)は、AppleScriptで普通に実行できてほしい処理のひとつです。こうしてObjective-C/Swiftで書いたプログラムをFrameworkとして呼び出せるようにして呼び出すとか、いろいろ方法があるわけで……少なくとも、ローカルで処理が完結する解決策は用意しておきたいところです。
AppleScriptからのChatGPTのREST API呼び出しは、かなり早期からできていました。処理したい内容のScriptをChatGPTに書かせて実行するといった「なげやり」な方法であれば、こうしたScriptの延長線上で可能ですが、あらかじめきちんと動くことを保証したScriptのパラメータ部分だけをLLMから取得するとか、複数のScriptを組み合わせて処理を実行させるといった内容を実現する方法を見つけたいところです。
Keynoteはいいアプリケーションだと思うものの、あまりバージョンアップしても機能が追加されないというか、実際に使っている人間からのフィードバックがさっぱりないというか、ユーザーと開発現場の距離が離れてしまっている感じがします。
他形式の3DデータをUSDZデータに変換するあたりのツールが充実する必要があるというか、Keynote側の読み込み機能がもう少し強化されてもよさそうな気もします。
この本は、発行するのに30冊以上も本を出す必要があり、数年かけて計画を実行して、ようやくアップデートにこぎつけました。最初の「AppleScript最新リファレンス」から7年が経過していることに驚かされます。
Microsoft Excelは依然としてAppleScript用語辞書が大きなアプリケーションではあるのですが、Excelの機能が強力すぎる(表現力が豊かすぎる)ために、目的の処理を行うためにはなかなか一筋縄では行かないようです。
PowerPointにかぎらず、Microsoft OfficeアプリのAppleScript用語辞書が、より詳細な記述を行なっているところに懸念をおぼえます。こんなに細かく書かないとダメなのだろうかと。敷居が高くなりすぎていないかと。あと、Script MenuにPowerPointを操作するAppleScriptを入れて実行すると動かないというのは、ランタイム環境が強く限定され、こんにちのmacOS環境の中で標準レベルといえるScript Menuで動かないのは、よくないと考えます。
macOS 12.xのマイナーバージョンアップ時に機能が損なわれた箇所です。そして、Appleにバグレポートしても治らない。こんな根本的な部分で不具合を起こされても困るのですが……。
「システム環境設定」が「システム設定」に変わったときに、各設定Paneを表示するためのAppleScript用語辞書が機能しない、空白の期間が発生していました。macOS 14βで本機能が復旧されたのと同じタイミングで、macOS 13.xにもさかのぼって同じ機能が実装されました。
ただ、システム設定の各Paneへの表示切り替えが行えるだけで、たとえばオーディオ入出力デバイスの切り替え機能が提供されているわけではないため、それについては別途実装したものを呼び出すという解決方法が必要になります。
GUIアプリケーションの操作において、若干の不満を覚えつつもmacOS上のGUIアプリケーションの操作を行えてきました。
ただ、「次」の段階が見えているのに、GUIアプリケーション側の機能がそれに追いついていなかったり、未実装の部分があったりで、GUIアプリケーション側が足を引っ張っているように見える今日このごろです。
たとえばKeynoteにおいて、特定のグラフィックだけを削除したい(会社ロゴなど)という場合に、メニューに「この部品に近似する部品を削除」といった機能が実装されていてもよさそうな昨今ですが、それはありません。「類似画像を削除」「類似部品を削除」といった処理はやりたくなる部分だと(勝手に)考えるものです。だいたい、OS内の機能を見ても容易に実装できそうに見えます。
Keynote書類にはimageオブジェクトが用意されており、さまざまなプロパティを取得できるようになっていますが、file nameは取得できても、
file属性を取得できない状態です。
AppleScript名:画像からfile属性を取得(できない).scpt |
tell application "Keynote" tell front document set aSel to selection set aaSel to first item of aSel set aFile to file of aaSel –> error "Keynoteでエラーが起きました: AppleEventのハンドラで誤りが起きました。" number -10000 end tell end tell |
iCloud上に存在するKeynote書類の内部ファイルに対してのパスを表現しづらい、といった理由は理解できるかもしれませんが、用語辞書にfile属性が取れると明記してある以上、file属性は(ローカルに書類が存在するなどの条件下では)取得できるべきだと考えます。
そして、file属性(おそらく、file pathをalias形式で取得できる)を取れれば、画像の「内容」にもアクセスして、「指定の画像に近似するものを削除」といった処理はできるはずです(画像のハッシュ値を計算する処理は別途する必要はあるわけですが)。
このあたりの処理が、そろそろできてもいいんですが、いろいろ邪魔が入ってできないのが残念な感じがします。
AppleScript初心者がつまづきやすいのが、logコマンドのようです。
スクリプトエディタ上でlogコマンドによって、スクリプトエディタ上にログ表示されるので、他の実行環境(Mail.appのプラグインScriptとか、AppleScriptアプレットとか)でlogコマンドを実行して、その内容がスクリプトエディタにログ表示されないことにブチ切れる初心者が何度も観測されています。
logコマンドは、スクリプトエディタ(もしくはScript Debugger)上でAppleScriptを実行している場合に、その実行しているエディタのウィンドウ内のログエリアに表示されます。
スクリプトエディタ(およびScript Debugger)以外の実行環境でAppleScriptを実行しても、スクリプトエディタのログ表示エリアに表示は出ません。これは、バグでもなんでもない仕様なのですが、この点でブチ切れる初心者の多いこと多いこと。
AppleScriptの実行環境=ランタイム環境はmacOS標準装備されているだけでも11個ぐらいありますが、環境によって実行できないコマンドがいくつか存在します。
前述のとおり、便利なコマンドではあるものの、「いつでも使える」「どこでも使える」というものではない点に注意が必要。
本コマンドは、アプリケーションの組み込みAppleScript環境で実行できないケースが観測されています。AppleScript実行をXPCサービス内で行なっているアプリケーション(Keyboard Maestro、BBEdit)では、notification表示がOSの制約(仕様)により行えません。
この実装自体が間違っているわけではないのですが、ユーザーに「本アプリの内蔵スクリプトメニューから実行したAppleScriptでdisplay notificationコマンドは有効ではない」ことが周知されていないことに問題があります。
本コマンドが実行できないケースはほとんどありませんが、Xcode上でAppleScriptによりGUIアプリを組んでいる際に、メインのAppleScriptではなくサブクラスを定義しているAppleScript内でダイアログ表示が行えない(デバッグしにくい)という現象を確認しています。
おおよそ、display dialogコマンドと同様です。
ドロップレット形式で書き出した(=スクリプトエディタやScript Debugger上で実行した状態ではない)状態であればドラッグ&ドロップは受け付けますが、そうでない場合には本イベントハンドラにより他のファイルやフォルダをFinder上でAppleScript書類にドラッグ&ドロップしても、ファイル/フォルダの受信は行われません。
寝る前にMacをスリープさせるのにScript MenuからAppleScriptを呼び出して実行しています。もともとは、Apple Magic Mouseの充電用に作ったScriptでしたが、普通にマウスの充電を行わない場合にでも呼び出してスリープさせています。
そんなScriptに対して、
「マウスのバッテリー残量を調べて、残量が少ない場合には充電するようにメッセージを出せば便利なのでは?」
などと考えて、ありものの部品を組み合わせて作ろうとしたところ……動かない。
しばらく見ないうちに、system_profiler経由で取得したBluetoothデバイスの各種情報から直接バッテリー残量を取れなくなっていたもよう。
仕方がないので、シェルのioregコマンドから詳細情報を取得し、system_profilerで取得したBluetoothデバイス名(ただしApple純正に限る)の一覧と付け合わせを行なって、これらの周辺機器のバッテリー残量を取得するようにしてみました。
正直、やっつけで作ったので、プログラム自体はあんまり見るべきものはありません。1回作ったら、二度と見直したくないような出来です。Magic Track Padは持っていないので、同デバイスの電池残量レポートについては、お持ちの方はぜひお試しください。
system_profiler経由でBluetoothデバイス名を取得するあたりの処理をライブラリに追い出して、バンドルScript内に入れて呼び出しているので、下記リストは参考程度。実際に実行するには、添付のアーカイブを展開して実行してください。
–> Download script bundle archive
追加:
Apple Magic Trackpad(乾電池式、銀色)の中古を買ってきて試してみたら、
Bluetoothメニュー上でバッテリー残量表示は行われるのですが、本AppleScriptでバッテリー残量を取得することはできませんでした。
AppleScript名:Apple純正マウス、キーボードのバッテリー残量取得.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/01/11 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.8" use framework "Foundation" use framework "AppKit" use scripting additions use btLib : script "btLib" set devList to getBTBatteryLifeByNameList() of btLib set aRes to (do shell script "ioreg -c AppleDeviceManagementHIDEventService -r -l") set aList to paragraphs of aRes set fromStr to " {" set toStr to " }" set statF to false set allList to {} set sNum to 0 set eNum to 0 set aCount to 1 –Step 1: ioregの実行結果からデバイスごとの情報に分割 repeat with i in aList set j to contents of i if statF = false then if j starts with fromStr then set statF to true set sNum to aCount end if else if j ends with toStr then set eNum to aCount set the end of allList to (items sNum thru eNum of aList) set statF to false copy {0, 0} to {sNum, eNum} end if end if set aCount to aCount + 1 end repeat –Step 2: Bluetoothのデバイス(Apple純正デバイス)の名称リストと、Addressをもとにioregの内容を照合 set devIList to {} set devCount to 1 repeat with i in devList set j to contents of i set tmpName to device_name of j set tmpAddr to device_address of j set tmpAddr to repChar(tmpAddr, ":", "-") of me repeat with ii in allList repeat with iii in ii set jjj to contents of iii ignoring case if jjj contains tmpAddr then set the end of devIList to {tmpName, devCount, contents of ii} set devCount to devCount + 1 exit repeat end if end ignoring end repeat end repeat end repeat –Step 3: 取得した名前、Indexをもとにバッテリー比率を求める set endList to {} repeat with i in devIList copy i to {tmpName, tmpIndex, dList} repeat with ii in dList set jj to contents of ii if jj contains "BatteryPercent" then set batNum to splitAfterAtmark(jj, "= ") of me set the end of endList to {tmpName, batNum as number} end if end repeat end repeat return endList –> {{"Takaaki Naganoya のキーボード #1", 46}, {"Takaaki Naganoya のマウス", 4}} –指定マーク文字以降の文字列を返す on splitAfterAtmark(anAdr, aMark) set atPos to offset of aMark in anAdr if atPos = 0 then return false set domainText to text (atPos + 1) thru -1 of anAdr return domainText end splitAfterAtmark –Written By Philip Aker –文字置換ルーチン on repChar(origText as string, targStr as string, repStr as string) set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr} set temp to text items of origText set AppleScript’s text item delimiters to repStr set res to temp as text set AppleScript’s text item delimiters to txdl return res end repChar |
macOS 13.6.4+スクリプトエディタ バージョン2.11 (229)の組み合わせで、AppleScript書類の「説明」欄に記入した内容が「消える」トラブルが発生しています。macOS 14上でも発生していることを確認しました。
▲スクリプトエディタ上で新規書類を作成して、AppleScript本文と「説明」欄の内容を書き込んでみた
▲スクリプトエディタで名称を指定して保存(.scpt形式)した状態
▲保存していったんクローズして、再度オープンしてみたところ。「説明」欄の内容が見えない
▲「説明」欄の内容を選択したところ。白い色の文字が存在していることがわかる
「消える」というよりは、「見えなくなる」というのが正しい状況と思われますが、macOSのマイナーアップデートでこうした変更が加わる(正確にいえば、APIなどの変更が行われた一方で、スクリプトエディタの修正が行われずに動作がおかしくなる)というのは納得できません。
なお、バンドル形式のAppleScript(.scptd形式)であれば、「説明」欄の内容が白く表示されることはないようです。
特定のディスプレイのみ消灯して処理続行、という処理を行なってみたかったのですが、いろいろ調べた結果、すべてのディスプレイを消灯する方法しか見つかりませんでした。
それでも、寝る前に電子書籍1冊分のデータをPDFにすべて書き出して連結する、といったAppleScriptを実行するのに、ディスプレイをあらかじめスリープ状態にしたあとで、処理終了後にコンピュータごとsleepにしてもよさそうです。
1000ページ分の電子書籍のPages書類をすべてPDFに書き出して、ファイル名順に連結してもM1 Mac miniで7分ぐらいで処理できるので、この程度の処理だとディスプレイを消して処理する意義はそれほどないのかもしれませんけれども。
AppleScript名:ディスプレイをスリープ状態にして処理続行.scpt |
do shell script "pmset displaysleepnow" beep 10 |
ChatGPTに書かせたAppleScriptを微修正したものです。ベクトルの内積、外積の計算を経てコサイン類似度計算のAppleScriptを書かせました。
もともとは、ChatGPTのAPIを利用して自然言語テキストをベクトル化し、それらの類似度を計算させるための準備で用意しました。自分が試したときには、ChatGPTのREST APIは1536次元のベクトルを返してきました。残念ながら、いま試してみると(全然REST API呼び出しをしていないのに)Quota Exceedのエラーが出てしまって目的の処理はできませんでした。
このあたり、実際にChatGPTのコンソールから利用履歴を確認してみても、全然呼び出していないことが確認できたので、自分の記憶違いではありません。
もともと、日本語テキストを複数の機械翻訳APIを利用して英訳し、再度日本語訳したのちに文章をベクトル化。これらの複数の機械翻訳APIの結果を比較して、もともとの日本語の文章と類似度が高いものを「正確に英訳された文章」として採用してみるといいんじゃないかと思っていました。翻訳文の質を疑似的に評価してみようと思ったわけです。
ChatGPTに出力させたAppleScriptは、「間違ってはいないんだけど、正しくないし、微妙にムカつく(resultを使って計算したりする)」内容で、よくわかっている人間にとっては簡単に修正できるものですが、基礎がわかっていないとどこが間違っているか指摘しにくいし、そもそも間違っているかどうかも指摘しにくいので……より正確な知識が要求されます。
AppleScript名:可変次元のベクトルに対応したコサイン類似度計算.scpt |
— ベクトルの例 set vectorA to {1, 2, 3, 4} set vectorB to {4, 5, 6, 7} — コサイン類似度を計算 set similarityResult to cosineSimilarity(vectorA, vectorB) — 結果を表示 return similarityResult –> 0.975900072949 — ベクトルのノルムを計算する関数 on vectorNorm(aVec) set sumSquares to 0 repeat with i from 1 to (count of aVec) set sumSquares to sumSquares + (item i of aVec) ^ 2 end repeat return (sumSquares) ^ 0.5 end vectorNorm — ベクトルのコサイン類似度を計算する関数 on cosineSimilarity(vector1, vector2) set dimension1 to count of vector1 set dimension2 to count of vector2 if dimension1 = dimension2 then set dotProductResult to dotProduct(vector1, vector2) set norm1 to vectorNorm(vector1) set norm2 to vectorNorm(vector2) set similarity to dotProductResult / (norm1 * norm2) return similarity else error "ベクトルの次元数が一致していません。" end if end cosineSimilarity — ベクトルの内積を計算する関数 on dotProduct(vector1, vector2) set dimension1 to count of vector1 set dimension2 to count of vector2 if dimension1 = dimension2 then set sRes to 0 repeat with i from 1 to dimension1 set sRes to sRes + ((item i of vector1) * (item i of vector2)) end repeat return sRes else error "ベクトルの次元数が一致していません。" end if end dotProduct |
正確にいえばmacOS 12あたりから大幅に変わっていて、忙しさにかまけて詳細な調査は行なってこなかったのですが……必要に迫られていろいろ調べてみました(Piyomaru Context Menu Assistant関連で)。
変更点1:TTS Voiceから年齢(Age)という属性値が削除された
変更点2:TTS Voiceの名前(Name)という属性値がローカライズされて返るようになった
変更点3:AppleScriptのsayコマンドにTTS Voiceの名前(Name)を設定するとエラーになるものが多数出てきた
変更点4:TTS Voice低音質キャラクタと高音質キャラクタ(Premium、Enhanced)があった場合に、AppleScriptのsayコマンドで低音質キャラクタが指定されるようになった。高音質キャラクタ(Premium、Enhanced)を明示的に指定する方法はない(sayコマンドでは不可能。AVSpeechSynthesizerを呼び出して読み上げるのは可能)
変更点5:AppleScriptのsayコマンドでSiriボイスを指定できないが、システムのデフォルト読み上げ設定にSiri音声を指定していると、sayコマンドでTTSボイス無指定(システムのデフォルト設定ボイスを使用)でSiri音声で読み上げられる
変更点1は、ポリコレの一環なんでしょうか。別に機械音声なので「年齢を基準に処理するな」とかいう不満は誰も抱かないと思います。これを決定した責任者は、頭がおかしいです。
変更点2は、NameのほかにLocalizedNameとかいった属性値を持たせるべきだったんじゃないでしょうか。経験の足りないエンジニアがとりあえずやっつけで仕事をしてしまったように見えます。これを決めた責任者は頭がおかしいです。バカと言って差し支えないでしょう。
変更点3は、けっこう困ります。AppleScriptのデフォルトコマンドには、TTS Voiceキャラクタ名の一覧を取得する、といった命令が存在せず、なんとなく「システム環境設定に出てくる名前を指定して使ってね」といった無責任な状況になっていました。昔からあるTTS VoiceのうちBells、Hysterical、Organ、Princess、Trinoids、Whisperを指定してもエラーになります(OS内に存在しているのに)。これは、OSの内部が壊れているものと判断しています。いい加減にしてほしいです。
変更点4は、Apple社内がえらく混乱しているように見えます。ちゃんと状況を整理していないような、開発現場のカオスな状況しか感じません。エンジニアの人数はさほど増やしていないのに、OSの数を野放図に増やしすぎです。これは、そういう管理をしている管理職の頭がおかしいです。
変更点5は、おそらくApple側が意図していない動作だと思われますが、「いまだとsayコマンドでAppleScriptからSiriの音声が指定し放題」であるということです。sayコマンドでは音声の指定を行わないと、OSデフォルトの音声キャラクタが指定されます。このデフォルト音声をSiriの音声にしておいて、キャラクタ無指定でsayコマンドを実行すると、Siriの音声キャラクタで発声が行われます。
sayコマンドで指定できるということは、音声ファイルにレンダリング可能だということで、Appleがキャラクタ提供元とそういうライセンス契約をしているのであればよいのですが、バグによって意図しない使われ方をしてしまう可能性があるわけです。ただ、このような状況を作った責任はAppleにあるものであって、ユーザーにはありません。
追跡調査を行なってみたところ、shell commandの/usr/bin/sayは、これらの、AppleScriptのsayコマンドではエラーになるText To Speechキャラクタ「Bells」も問題なく指定できました。
Piyomaru Softwareの電子書籍カタログ(2024年冬版)を刊行しました(フリー配布)。PDF 100ページです。
数年前は「AppleScriptの書籍がぜんぜんない」と言われていましたが、いまでは「多すぎて選べない」と言われる状況に。いろいろな角度から、ぴったり合う本が選べることでしょう。