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

タグ: 10.14savvy

ファイル保存ダイアログ(SavePanel)表示

Posted on 4月 22, 2020 by Takaaki Naganoya

Mac App StoreアプリケーションをAppleScriptで作ったときに、ファイル保存ダイアログを実装するのにchoose file nameコマンドでは拡張子の処理に問題があります(ユーザーが拡張子まで入力しなかった場合への対処を行うと逆効果に)。

choose file nameコマンド
ユーザーが選択、入力したパス:Macintosh HD:Users:me:Desktop:aaaaa
Script側で拡張子を補足:Macintosh HD:Users:me:Desktop:aaaaa.kame
--> エラー(Sandbox制限による)

その回避策としてありものを引っ張り出してきて手直ししたNSSavePanelベースのファイル保存ダイアログ表示サブルーチンです。


▲choose file nameコマンドで表示したファイル名入力ダイアログ。ダイアログ上でタグの選択はできるがchoose file nameにはタグ受信のための機能がない。また、拡張子が入力されていなかったらそのまま


▲本Scriptで表示したNSSavePanelによる保存ファイル名入力ダイアログ。タグの選択、指定した拡張子の指定などが行える。ユーザーが拡張子を入力していなくても自動で補える

choose file nameによるダイアログも、NSSavePanelによるダイアログも、見た目は同じで見分けはつきません。

普通にAppleScriptを書いて自分で実行している分にはchoose file nameコマンドでも問題はありません。

AppleScript名:ファイル保存ダイアログ(SavePanel)表示
— Original by Shane Stanley
— Modified 2020-04-22 by Takaaki Naganoya
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property savePath : ""
property saveTag : {}

set savePath to ""
set saveTag to {}

set aParam to {extList:{"kame"}, saveMsg:"新規ファイルの名前と場所を指定", saveName:"Some name", initialDir:(POSIX path of (path to documents folder))}
my performSelectorOnMainThread:"showModalSave:" withObject:(aParam) waitUntilDone:true
return {savePath:savePath as string, saveTags:saveTag as list}
–> {savePath:"/Users/me/Desktop/Some name.kame", saveTags:{"ブルー", "ヤンキー"}}

on showModalSave:sender
  set tmpExt to extList of sender as list
  
set tmpMsg to saveMsg of sender as string
  
set defName to saveName of sender as string
  
set tmpInit to initialDir of sender as string
  
  
using terms from scripting additions
    set startURL to current application’s NSURL’s fileURLWithPath:(tmpInit)
  end using terms from
  
  
set thePanel to current application’s NSSavePanel’s savePanel()
  
tell thePanel
    its setMessage:(tmpMsg)
    
its setAllowedFileTypes:(tmpExt)
    
its setNameFieldStringValue:(defName)
    
its setShowsHiddenFiles:false
    
its setTreatsFilePackagesAsDirectories:false
    
–its setDirectoryURL:startURL–指定しないほうが前回呼び出し時と同じフォルダが表示されて便利
    
set returnCode to its runModal() as integer
  end tell
  
  
if returnCode = (current application’s NSFileHandlingPanelOKButton) as integer then
    set my savePath to thePanel’s |URL|()’s |path|()
    
    
if (thePanel’s respondsToSelector:"tagNames") as boolean then
      set my saveTag to thePanel’s tagNames()
    end if
    
  else
    — cancel button
    
error -1
  end if
end showModalSave:

★Click Here to Open This Script 

Posted in dialog File path Sandbox | Tagged 10.13savvy 10.14savvy 10.15savvy NSSavePanel NSURL | Leave a comment

Xcode上で作成したアプリケーション上でDark Mode検出

Posted on 4月 22, 2020 by Takaaki Naganoya

Xcode上で作成したAppleScriptアプリケーションでDark Modeの検出を行いたいときに、NSAppearance’s currentAppearance()で取得したら、正しくModeの検出が行えませんでした。同じコードをスクリプトエディタ/Script Debugger上で動かした場合には正しくModeの判定が行えているのですが。

そこで、System Eventsの機能を用いてMode判定を行うように処理を書き換えたりしてみたのですが、Mac App Storeに出すアプリケーションでこの処理を記述していたら、これを理由にリジェクトされてしまいました。

仕方なく解決策を探してみたところ、macOS 10.13用に書いたshell scriptによる迂回処理を、そのまま他のOSバージョンでも動かせばよいのではないかと気づき、結局そこに落ち着きました。

AppleScript名:Dark Modeの検出(Xcode上でも正しく判定)
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/04/22
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set apRes to retLightOrDark() of me
–> true (Dark), false (Light)

on retLightOrDark()
  try
    set sRes to (do shell script "defaults read -g AppleInterfaceStyle")
    
return (sRes = "Dark") as boolean
  on error
    return false
  end try
end retLightOrDark

★Click Here to Open This Script 

Posted in shell script System | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

Sandbox環境で封じられる処理

Posted on 4月 22, 2020 by Takaaki Naganoya

ふだん、AppleScriptの処理はOSによる制約の少ない環境で処理を行っています。サンドボックスによる制約がない、あるいはきわめて少ない環境であるといえます。

そうした自由な環境に慣れていると、Sandbox環境下で(Xcode上で)アプリケーションを作成したときに、あっと驚く制約が存在していて驚かされることが多々あります。

他のアプリケーションを操作するScriptは書き込み禁止に

Sandbox環境下では、他のアプリケーションを操作するAppleScriptについては、実行専用形式で保存したうえでファイル書き込み不可の状態にしておく必要があります。Scriptのプロパティ(resultもプロパティ)を書き換えられてはいけないので、この措置が必要になります。Sandbox環境ではこのプロパティの書き換えが、自己書き換えと判定され、禁則事項に該当してしまうためです。

ファイルの新規保存時のchoose file nameコマンド(+拡張子追加)が抵触

ファイルの新規保存時にchoose file nameコマンドで保存先のパス+ファイル名をユーザーに指定させるような処理を行っています。このときに、ファイルの拡張子が指定されていない場合には、choose file nameから返ってきたパスを文字列に変換して、拡張子を文字列で追加するような処理もよく行っています。

これが、Sandbox環境下では禁じ手になります。

最初に遭遇したときには「意味がわからない!」と、イラつきまくりましたが、落ち着いて考えつつ追試を行ってみたところ理解できました。

Sandbox化したアプリケーションでファイル保存を行うためには、Xcode上でentitlementsファイルを編集し、「com.apple.security.files.user-selected.read-write」といったエントリに「YES」を設定しておくことになります。ユーザーが選択したファイルの読み書きを許可するという設定です。

このとき、choose file nameコマンドで入力されなかった拡張子の部分をAppleScript側で勝手に補ってしまうと、「ユーザーが指定したファイル」以外のファイルを処理することになるわけで、(拡張子を文字列操作で補ったようなパスは)ファイル保存することができませんでした。

そこで、NSSavePanelを用いてファイル保存ダイアログを作成する必要に迫られます。事前に補うべき拡張子の情報を渡してダイアログ表示を行うので、ユーザーが拡張子まで入力しなくても、拡張子がついたファイルパスが返ってきます。

ほかにもいろいろありますが、作成するAppleScriptのプログラム全体の数から見ると、Sandbox環境下で動かすAppleScriptはごく一部であるため、あまりノウハウが蓄積されていません。たまーにSandboxの制約に抵触して驚かされるといったところでしょうか。

Posted in How To Sandbox | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

新型アプリケーション「Kamenoko」をMac App Storeレビューに提出

Posted on 4月 21, 2020 by Takaaki Naganoya

本Blogにちょくちょく、その作例を掲載している6角形図形を組み合わせた図でアイデアを練るソフトウェア「Kamenoko」をMac App Storeのレビューに送信しました。2作目なので、レビューの概要もわかっており(1発で通ることはないので)前回のように却下に対して24時間即時対応、みたいな体勢にはしていません。しばらくApp Storeの審査とやりとりする必要があることを理解しています(1週間ぐらいでしょうか)。

目下App Store系の審査の担当者の人数が少ないために審査にかかる時間が長くなっているとの噂がありますが、これまでもMac App Storeの審査は時間がかかっていたので(前回1か月かかったし)、そんなもんだと思っています。

このKamenoko v1.0はAppleScriptからのスクリプティングには対応していません。ただ、中身はほとんど(99.9%)AppleScriptで書いてあるので、対応は難しくはありません。

難しくはないものの、このアプリケーションはAppleScriptによって操作してもあまり意味がないので(アイデアを練るためのアプリケーション)、書類の作成とか書類の内容取得、書類の内容変更などが行えるライブラリをアプリケーションに同梱する方向でAppleScriptサポート機能の実装を検討しています。

■リジェクト1発目

System Eventsを呼んでいることを問題視されているようです。当初、このアプリケーションでSystem Eventsを呼び出す必要はなかったのですが、Dark Modeの検出がmacOS 10.13でうまく働かなかったので、System EventsでDark Modeの検出を行わせるようにしていました。

Mac App Storeのレビューでは、指摘事項同士の矛盾については考慮されていません。(A)という指摘をされたので(B)という対応をしたら、説明の仕方を変更するだけで実は(A)の状態のままでよかった、ということがままあります。また、アプリケーション全体で複数の指摘項目があったとしても、1回のレビューで指摘されるのはだいたい1項目だけです。

なので、1項目の指摘事項があったので即時修正したとしても、さみだれ式に次々と指摘事項が(枝葉末節の問題から、徐々にセキュリティ系の事項へと)上がってくるものなので、「そういうもんだ」と割り切っていないとやりきれません。

System Eventsに依存しないAppearanceの判定を行わせると、macOS 10.13でDark Modeの検出ができなくなる可能性があり、macOS 10.13でDark Modeの検出ができなくなると、macOS 10.13対応が不適切であるという指摘が未来のタイミングで行われ、結局macOS 10.13対応を行うためにはSystem Eventsを呼ぶしかなかった、という結論に落ち着きそうな感じがとっても嫌な雰囲気です。

ただ、これまで1発目のレビュー(リジェクト)とかいうと、10分ぐらいであっという間に終わっていたので(溢れる「流れ作業」感)、1時間もかかったのは新記録ではないでしょうか。お茶飲みながらの1時間かもしれませんけれども。

■リジェクト2発目(2020/5/1)

のちのちのバージョンでやりたい(実現できるとは言っていない)機能のために宣言しておいたEntitlementsが、アプリケーションの機能に存在していないので却下、と判断されました。

あれ? AppleのWeb側にもXcode上にもそんな設定は(残ってい)ないのですがー(ーー;;;

Posted in PRODUCTS | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

ディスプレイの設定切り替えをAppleScriptでも行えるSwitchResX

Posted on 4月 19, 2020 by Takaaki Naganoya

Cocoaの機能やサードパーティのFrameworkの機能を呼び出して、ディスプレイの回転コントロールを行なったり、解像度の変更を行うなどの制御がAppleScript単体でできるようになってきましたが、ディスプレイの位置関係を定義して変更したいとか凝ったことを言い出すと、さすがにまだまだ市販のツール類を併用したほうが話が早かったりします。

実際に、「システム設定」アプリをGUI Scriptingで強引に操作したり、Objective-Cなどのプログラムを呼び出したとしても、相当に苦労する箇所です。SwitchResXを買って解決できるなら、それで解決すべきだと考えます。最近のシステム設定.appは作りがおかしいので、GUI Scriptingで詳細な設定の変更は行えません。

以前からSwitchResX(16USドル)がAppleScriptからコントロールできることを知っていましたが、どの程度のコントロールが行えるかについては調べたことはありませんでした。どのように使えて、どのようにコントロールできて、どのような点に注意すべきなのかを実際に調べてみました。

SwitchResX v4.9.2を実際にためしてみた

SwitchResXの解像度変更機能自体は水準通りだと思います。この手のツールは割といろいろ存在しており、自分はQuickResを利用しています。どちらのツールも画面のオーバースキャン(実解像度よりも大きな解像度の表示)ができます。画面の回転や色数、画面の相対位置の変更、アプリケーションごとに解像度を変更する機能などが本ツールの特徴でしょう。

画面解像度の変更機能について1つ、QuickResを大幅に上回っているものがありました。HiDPI(Retina解像度)の表示サポートです。非Retina解像度のディスプレイであっても、表示ピクセル数を抑えることでHiDPI表示を可能とするもので、表示すること自体にはあまり意味はありませんが、「HiDPI解像度の画面キャプチャが行える」というメリットがあります(非Retina環境でRetina解像度の画面キャプチャが行えるのは、資料作成時にとても便利)。このあたり、Mac miniでちょっと困らされた点でした。

Mac mini 2014(macOS 10.15.4)+HDMI Display(1980x1080)の組み合わせで、OSが標準で提供しているのは960x540解像度におけるHiDPI表示ですが、SwitchResXは1280x800 / 960x600 / 840x525 / 1280x720 / 800x450 などの解像度におけるHiDPI表示もサポートしています。

SwitchResXはメニューバーに常駐して、解像度設定の切り替えが行えるようになっています。設定自体はこのメニューバーから「SwitchResX Preferences…」を選択するか、システム環境設定の「SwitchResX」を選択すると起動される「SwitchResX Control」というGUIアプリケーションから行います。

SwitchResXでは、画面解像度、色(カラー、グレイ)、表示ON/OFF、ミラーリング、メインディスプレイ、画面回転、カラープロファイルなどを設定したディスプレイセットを作成し、このディスプレイセットをメニューやキーボードショートカット、コンテクストメニューから切り替えられるようになっており、その一環としてAppleScriptから同様にディスプレイセットの切り替えが行えるようになっています。

AppleScriptからのコントロール

SwitchResXのAppleScript用語辞書は以下のとおりです。

AppleScriptによるコントロールは「SwitchResX Daemon」という不可視アプリケーションプロセスに対して行うようになっており、基本的には各種ディスプレイの状態を取得(Read Only)することと若干の基本的なコマンドの実行と、ユーザーが定義したディスプレイセットの切り替えを行う、という内容です。

AppleScript側からこまかくディスプレイのIDを指定して個別にグレースケール表示を行わせるといったことはできません。逆に、指定したIDのディスプレイの現在の状況(properties)を取得することはできます。そういう感じです。

けっこう多い注意点

ディスプレイセットを新規作成したあとで、GUI側から明示的に保存(Command-S)を実行しないと、追加したディスプレイセットは認識されませんでした。ここは、たいへんに注意が必要です(なかなか気づきませんでした)。

ディスプレイの回転や位置関係の変更など、込み入った設定変更を行ったディスプレイセットを作成した場合には、それらを元に戻したディスプレイセットを作成しておく必要があります。restore desktopコマンドで元の状態に戻してくれるのかと思っていたのですが、そういうものではないようです。

こういうツールを使おうかと考えているユーザーは複数のディスプレイをMacにつないで使っているはずなので、本ツールで一気に切り替えたあと、戻す設定が定義されていないと手作業で元に戻すというScripterにとってはたいへんに屈辱的な作業を強いられることになります。

ディスプレイセットには、すべての設定項目が同居できるというわけではなく、特定の設定項目のみが単独で切り替えられるというものもあるようなので、この点も注意が必要です(注意点ばっかりやな)。

AppleScriptのプログラム中からSwitchResXの機能を呼び出して画面構成の変更を自由に行えるわけですが、個人的には「そこまでやる必要があるのか?」という印象です。あと、AppleScript用語辞書にサンプルScript掲載しとけとか画面キャプチャのグラフィックを入れておかないとわかりにくいので、そのあたり改善の余地ありといったところでしょうか。他人のアプリケーションについては、山のように不満点や改善点が出てくるものです。

あと、SwitchResXを操作するAppleScriptをどこから呼び出すことになるのか、については少し興味があります。macOS標準搭載のスクリプトメニューから呼び出すのが一番「ありそう」な利用パターンですが、それ単体で呼び出すと「隣り合ったSwitchResXのメニューから呼び出すのとほぼ等価な内容をスクリプトメニューに入れたAppleScriptから呼び出す」という間抜けな状態になります。

まとまった自動処理を行うのに必要な画面設定(速度重視のために画面解像度を極端に落とすとか、メニュー操作が想定外の動きを行わないように特定の解像度に明示的に変更するとか)を行い、処理本体を実行したうえで、後処理で画面設定を元に戻しておく、といったところでしょうか。

AppleScript名:ディスプレイを数えて、プロパティを取得
tell application "SwitchResX Daemon"
  set dCount to count every display
  
–> 2
  
  
repeat with i from 1 to dCount
    properties of display i
    
–> {built in:false, position:{0, 0}, name:"Cinema HD Display", class:display, brightness:-1.0, id:69501836, mirroring:{}, enabled:true, overscan:false, index:1, current mode:mode 1 of display 1 of application "SwitchResX Daemon", orientation:0, underscan:1.0, current depth:32, display profile:profile "Cinema HD Display" of application "SwitchResX Daemon"}
    
    
–> {built in:false, position:{-1920, 0}, name:"Cinema HD", class:display, brightness:-1.0, id:69513479, mirroring:{}, enabled:true, overscan:false, index:2, current mode:mode 1 of display 2 of application "SwitchResX Daemon", orientation:0, underscan:1.0, current depth:32, display profile:profile "Cinema HD" of application "SwitchResX Daemon"}
  end repeat
end tell

★Click Here to Open This Script 


▲display set 2だと2行目の「disp set 2 (90 degree rotation)」が指定される

AppleScript名:display set の切り替え
tell application "SwitchResX Daemon"
  set dSet to display set 2
  
apply dSet
end tell

★Click Here to Open This Script 

Posted in System | Tagged 10.14savvy 10.15savvy SwitchResX | Leave a comment

プログラムで作ったアラートダイアログ上のTextViewをフォーカスする

Posted on 4月 14, 2020 by Takaaki Naganoya

AppleScriptでダイナミックに(動的に)生成したアラートダイアログ上にテキストビューを生成し、そのテキストビュー上にテキスト入力用のキャレットを移動させる(フォーカスする)AppleScriptです。

Xcode上でAppleScriptでGUIアプリケーションを作っていて、文字サイズの大きなテキスト入力フィールドを動的に生成。さらに、テキスト入力フィールドにテキスト入力用のキャレットを移動させようとして、割と手こずっていました。

テキスト入力を受け付けるGUI部品に対して、入力フォーカスを与え、テキスト入力のキャレットが置かれた状態を再現するには、GUIの画面上からはマウスカーソルでクリック操作するとできます。同じ状態をプログラム側から作る場合にはFirstResponderにセットするという処理になります。

この、FirstResponderに指定することは理解でき、Xcode(Interface Builder)上で配置した部品に対して実行する処理は昔からやっています。NSTextFieldに強制的に入力フォーカスを置いた上でバーコードリーダーからのテキスト入力を受け付けるといった処理です。

一方、プログラムから動的に生成したGUI部品に対して、Cocoaが用意しているAPIのどれを用いて、どのように指定すべきなのかで困りました。

親WindowのFirstResponderにしてみたり、アラートウィンドウのFirstResponderにしてみたり、いろいろ試した末に、

parentWin's setInitialFirstResponder:aView

で、Alert DialogのWindowをparentWinに、alert dialog上のテキストビューをaViewに代入した状態で実行して、入力キャレットをテキストビュー上に移動できました。本Xcode Projectは上記の1行の記述の検証を行うためのテストプロジェクトです。

–> Download Xcode Project

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— dialogCarret
—
— Created by Takaaki Naganoya on 2020/04/14.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  property parent : class "NSObject"
  
  
property |NSURL| : a reference to current application’s |NSURL|
  
property NSFont : a reference to current application’s NSFont
  
property NSView : a reference to current application’s NSView
  
property NSAlert : a reference to current application’s NSAlert
  
property NSColor : a reference to current application’s NSColor
  
property NSTextView : a reference to current application’s NSTextView
  
property NSScrollView : a reference to current application’s NSScrollView
  
property NSRunningApplication : a reference to current application’s NSRunningApplication
  
  
— IBOutlets
  
property theWindow : missing value
  
  
property returnCode : 0
  
property resStr : ""
  
  
  
on applicationWillFinishLaunching:aNotification
    —
  end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
on clicked:sender
    set tmpStr to "TEST"
    
set paramObj to {myMessage:"Input Text", mySubMessage:"", mes1:(tmpStr), mesWidth:400, mesHeight:200}
    
my performSelectorOnMainThread:"dispTextViewWithAlertdialog:" withObject:paramObj waitUntilDone:true
    
set aResText to (my resStr) as string
    
    
display dialog aResText
  end clicked:
  
  
on dispTextViewWithAlertdialog:paramObj
    –Receive Parameters
    
set aMainMes to (myMessage of paramObj) as string –Main Message
    
set aSubMes to (mySubMessage of paramObj) as string –Sub Message
    
set mesStr to (mes1 of paramObj) as string –Text Input field 1 Label
    
set aWidth to (mesWidth of paramObj) as integer –TextView width
    
set aHeight to (mesHeight of paramObj) as integer –TextView height
    
    
set vNum to system attribute "sys2"
    
if vNum > 13 then
      set apRes to retLightOrDark() of me
      
if apRes = true then
        set textColor to (current application’s NSColor’s cyanColor())
      else
        set textColor to (current application’s NSColor’s blackColor())
      end if
    else
      set textColor to (current application’s NSColor’s blackColor())
    end if
    
    
    
— Create a TextView with Scroll View
    
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
    
set aView to NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
    
aView’s setDelegate:me
    
aView’s setRichText:true
    
aView’s useAllLigatures:true
    
aView’s setTextColor:textColor
    
aView’s setFont:(current application’s NSFont’s systemFontOfSize:90.0)
    
set aColor to current application’s NSColor’s colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.1
    
    
aView’s setBackgroundColor:aColor
    
aView’s setString:mesStr
    
aScroll’s setDocumentView:aView
    
aView’s enclosingScrollView()’s setHasVerticalScroller:true
    
    
— set up alert
    
set theAlert to NSAlert’s alloc()’s init()
    
tell theAlert
      its setMessageText:aMainMes
      
its setInformativeText:aSubMes
      
its addButtonWithTitle:"OK"
      
–its addButtonWithTitle:"Cancel"
      
its setAccessoryView:aScroll
      
set parentWin to its |window|()
    end tell
    
    
parentWin’s setAlphaValue:0.8
    
–parentWin’s setOpaque:(false)
    
parentWin’s setLevel:(current application’s NSScreenSaverWindowLevel)
    
    
parentWin’s setInitialFirstResponder:aView —Place Input Carret to Alert Dialog
    
    
— show alert in modal loop
    
NSRunningApplication’s currentApplication()’s activateWithOptions:0
    
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
    
    
if (my returnCode as number) = 1001 then
      —
    else
      set my resStr to aView’s |string|()
    end if
  end dispTextViewWithAlertdialog:
  
  
  
on doModal:aParam
    set (my returnCode) to aParam’s runModal()
  end doModal:
  
  
  
on retLightOrDark()
    return true
  end retLightOrDark
  
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode dialog How To | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSColor NSFont NSMakeRect NSRunningApplication NSScrollView NSTextView | Leave a comment

システムフォントの名称を取得

Posted on 4月 13, 2020 by Takaaki Naganoya

システムフォントの名称を取得するAppleScriptです。

GUIベースのアプリケーションを作っているときに、「もう、無難なフォントなんでもいいからとりあえず指定できるものがあれば指定しておこうよ」という局面はあります。ないフォントを指定するとクラッシュすることもあるので、とりあえずコレ指定しておけば大丈夫だから!

という「安全パイ」のフォントとしてSystem Fontを取得&指定したいという時に書いたScriptでもあります。プログラム内容がつまらない割には、切実なニーズを満たすためのものです。

AppleScript名:システムフォントの名称を取得.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/04/06
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

set aFont to current application’s NSFont’s systemFontOfSize:24.0
set aInfo to aFont’s fontDescriptor()
set aSize to (aInfo’s pointSize()) as real
set aPSName to (aInfo’s postscriptName()) as string
–> ".SFNSDisplay"

set bFont to current application’s NSFont’s boldSystemFontOfSize:24.0
set bInfo to bFont’s fontDescriptor()
set bSize to (bInfo’s pointSize()) as real
set bPSName to (bInfo’s postscriptName()) as string
–> ".SFNSDisplay-Bold"

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode Font | Tagged 10.13savvy 10.14savvy 10.15savvy NSFont | Leave a comment

NSFontPanelでフォントを選択

Posted on 4月 7, 2020 by Takaaki Naganoya

自前でメニューを作ってフォントおよびサイズの選択を行おうとするとめんどくさい(時間がかかるし管理も大変)ので、NSFontPanelを用いてフォントを選択する試作品を作ってみました。

ただし、まだ完全ではなく「1つ前の状態が取得できる」という状態なので、修正が必要です。作成はmacOS 10.14.6+Xcode 11.3.1上で行っています。

–> Download Xcode Project

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— fontPanel
—
— Created by Takaaki Naganoya on 2020/03/12.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
property theField : missing value
  
  
property aFontNameField : missing value
  
property aFontSizeField : missing value
  
  
property aFontManager : missing value
  
  
property font : missing value
  
property aFP : missing value
  
  
on applicationWillFinishLaunching:aNotification
    set aFontManager to current application’s NSFontManager’s sharedFontManager()
    
aFontManager’s setAction:"appSpecificChangeFont:"
    
set aFP to current application’s NSFontPanel’s sharedFontPanel()
    
set aFont to current application’s NSFont’s fontWithName:"Helvetica" |size|:16
    
aFontManager’s setSelectedFont:aFont isMultiple:false
    
    
theField’s setStringValue:"ぴよまるソフトウエア, Piyomaru Software"
  end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    — Insert code here to do any housekeeping before your application quits
    
return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
on clicked:aSender
    theWindow’s makeFirstResponder:theField
    
aFP’s makeKeyAndOrderFront:me
  end clicked:
  
  
on appSpecificChangeFont:sender
    set aSelFont to sender’s selectedFont()
    
set aDesc to aSelFont’s fontDescriptor()
    
set aPSID to (aDesc’s postscriptName()) as string
    
set aSize to (aDesc’s pointSize()) as real
    
theField’s setFont:aSelFont
    
aFontNameField’s setStringValue:aPSID
    
aFontSizeField’s setStringValue:(aSize as string)
  end appSpecificChangeFont:
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode Font | Tagged 10.13savvy 10.14savvy 10.15savvy NSFont NSFontManager NSFontPanel | 1 Comment

パネル構成書類「入出力音量調整」

Posted on 4月 3, 2020 by Takaaki Naganoya

新型コロナウィルスの蔓延により、リモートワークでビデオ/オーディオチャットを行う機会が増え、音量調整のためのいい方法がないと嘆いている方が多いようなので、便利な方法をご紹介します。

macOSにはアクセシビリティ系(障害者支援)の機能が多々用意されており、その中核をなす「スイッチコントロール」という機能があります。この機能を利用して、画面上に操作可能な機能ボタンを貼り付けておくことができるため、オーディオ系の音量調整機能などをここに割り振って利用すると便利です。

# 業務系のScriptをフローティングパレット表示しておいて、ワンクリックで実行できるようにしておくと、とても便利だと思います

このスイッチコントロールの機能はユーザーごとに自由にカスタマイズすることができ、さらにその内容を書類に書き出して他のユーザーと共有できるようになっています。

それがパネル構成書類です。これはmacOS標準装備の機能「スイッチコントロール」の書類で、ボタン定義データやボタンから呼び出すAppleScriptが内包されています。

–> Download switchControlUserPanels1.ascconfig(12KB)

[Update] English Version included in same panel

このパネル構成書類はmacOS 10.14上で作成し、macOS10.14.6およびmacOS 10.15.4上での動作を確認しています。

Zipアーカイブから展開して、ユーザーの~/Library/Application Support/com.apple.AssistiveControlフォルダに入れてください。macOS 10.15上では展開後.ascconfig書類がフォルダに見えるかもしれませんが、気にせずそのまま上記フォルダに移動してください。

# 「com.apple.AssistiveControl」フォルダがApplication Support内に存在しない場合には作成してください。このフォルダ名を間違えるとOSに認識されないので、ご注意ください

「システム環境設定」を起動。

「アクセシビリティ」を選択。

左の一覧リストの下の方にある「スイッチコントロール」を選択。

「スイッチコントロールを有効にする」にチェックを入れます。この際に、管理者パスワードを求められる場合があります。

フローティング操作パレット「スイッチコントロール」のホーム画面が表示されるので、「カスタム」をクリック。

カスタムの中にさきほど追加した「入出力音量調整」があるので、それをクリック(”Sound Volume Control” is English version)。

これで、フローティングパレットの入出力音量調整パレットが表示されます。


▲SwitchControlの操作方法。macOS標準のGUI体系とは若干異なる

パレット上の各ボタンをクリックするか、あるいはMacのサブディスプレイとしてiPadを接続している場合には、iPadの画面上を指でタップすると各ボタンの機能が実行されます。

スイッチコントロールのフローティングパレットはパレット左上の「x」をクリックすると消去できます。いったん消去しても、ふたたび「システム環境設定」>「アクセシビリティ」>「スイッチコントロール」に戻って、「スイッチコントロールを有効にする」のチェックを入れると表示されます。

iPadをMacのサブディスプレイとして利用するアプリケーションは、Apple純正のSide Car(macOS 10.15標準装備)のほか、サードパーティ製の「duet display」や「AirDisplay」などが有名です。

とくに、サードパーティ製のアプリケーションは、古めのiOSや古めのiPadをサポートしている(Apple純正機能は最新のiPadしかサポートしていない)ため、身の回りに転がっている古いiPadや中古のiPadをMacのタッチ操作コントローラーにお安く利用できるため、とてもおすすめです。

Posted in news Tools | Tagged 10.14savvy 10.15savvy Switch Control | Leave a comment

NSURLSessionでREST API呼び出しv4.4.2a

Posted on 4月 3, 2020 by Takaaki Naganoya

REST API呼び出しに欠かせない部品をアップデートしました。URLキャッシュが効くようになったような気がします。

–> GET method REST API v4.4.1
–> GET method REST API v4.4
–> GET method REST API v4.3
–> GET method REST API v4.1
–> GET method REST API v4

前バージョンではmacOS 10.15上でクラッシュしないかわりにURLキャッシュが効かないという特徴がありました。ただ、edama2さんと協議した結果、macOS 10.15上でクラッシュする原因と考えられていた内容にあまり根拠がないことがわかってきました(人ごとではなく自分のことなのですが)。

可能な範囲でトライアル&エラーで調査を行なったところ、本バージョンのような処理に落ち着きました。AppleScriptからのCocoa利用については明確にドキュメントがAppleから出ているわけではないので、すでに存在するObjective-Cのプログラムの処理を参考にしつつ、Objective-CからAppleScriptへの置き換えが可能かを検討しています。

URLキャッシュについては、(当然のことながら)処理1回目には効きません。なぜか2回目も効きません。3回目とか4回目あたりから効いていることが実感できる感じです(回数ではなく、前回処理時からの経過時間を見ているのかも? GUIアプリケーションに入れて使うと2回目から効いたりします)。URLキャッシュが効いていない場合には1.5秒ぐらい、URLキャッシュが効き出すと0.02秒ぐらいで結果が返ってきています。

macOS 10.13/14/15で検証を行い、繰り返し処理を行ってもクラッシュしないことを確認しています。ただ、動作保証するというレベルではないので(本Blog掲載のScriptすべてそうですが)、問題があったら知らせてください。

ためしに、Xcode上で作成したGUIベースのAppleScriptアプリケーションに本処理を導入したところ、REST APIへの問い合わせがキャッシュされて著しい高速化を実現できました。

AppleScript名:GET method REST API v4.4.2a_wikipedia.scptd
— Created 2019-05-02 by Takaaki Naganoya
— Modified 2020-04-03 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLCache : a reference to current application’s NSURLCache
property NSURLSession : a reference to current application’s NSURLSession
property NSMutableData : a reference to current application’s NSMutableData
property NSURLQueryItem : a reference to current application’s NSURLQueryItem
property NSOperationQueue : a reference to current application’s NSOperationQueue
property NSURLComponents : a reference to current application’s NSURLComponents
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration
property NSURLRequestReturnCacheDataElseLoad : a reference to current application’s NSURLRequestReturnCacheDataElseLoad

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false
property aSession : missing value
property aCache : missing value

on run
  set retData to missing value
  
set drecF to false
  
set aSession to missing value
  
  
set aQueryKeyTitle to "AppleScript"
  
set aRes to getWikiText(aQueryKeyTitle) of me
  
return aRes
end run

on getWikiText(aQueryKeyTitle)
  set reqURLStr to "https://en.wikipedia.org/w/api.php"
  
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL, 5) of me
  
if aRes = missing value then return false
  
  
set bRes to (aRes’s valueForKeyPath:"parse.wikitext.*") as string
  
return bRes
end getWikiText

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set (my retData) to NSMutableData’s alloc()’s init()
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
–if my aCache = missing value then
  
set cachePath to (POSIX path of (path to library folder from user domain)) & "/Caches/AppleScriptURLCache"
  
set my aCache to NSURLCache’s alloc()’s initWithMemoryCapacity:512000 diskCapacity:1024 * 1024 * 5 diskPath:cachePath
  
–end if
  
NSURLCache’s setSharedURLCache:(my aCache)
  
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
aConfig’s setRequestCachePolicy:(NSURLRequestReturnCacheDataElseLoad)
  
  
aConfig’s setURLCache:(my aCache)
  
  
–どちらでも速度差がない
  
set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(NSOperationQueue’s mainQueue())
  
–set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeoutSec) times
    if (my drecF) is not equal to false then
      exit repeat
    end if
    
delay "0.001" as real
  end repeat
  
  
–delegateの無効化
  
my aSession’s finishTasksAndInvalidate()
  
set my aSession to missing value
  
  
return my parseSessionResults()
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  (my retData)’s appendData:tmpData
end URLSession:dataTask:didReceiveData:

on URLSession:tmpSession task:tmpTask didCompleteWithError:tmpError
  if tmpError = missing value then
    set (my drecF) to true
  else
    error "Donwload Failed"
  end if
end URLSession:task:didCompleteWithError:

on parseSessionResults()
  set resStr to NSString’s alloc()’s initWithData:(my retData) encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict
end parseSessionResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

★Click Here to Open This Script 

Posted in Internet JSON REST API URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSJSONSerialization NSMutableData NSMutableDictionary NSMutableURLRequest NSOperationQueue NSString NSURL NSURLCache NSURLComponents NSURLQueryItem NSURLRequestReturnCacheDataElseLoad NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | 1 Comment

NSURLSessionでREST API呼び出しv4.4.1

Posted on 4月 2, 2020 by Takaaki Naganoya

REST API呼び出しに欠かせない部品をアップデートしました。macOS 10.15でクラッシュしないように書き換えています。

–> GET method REST API v4.4
–> GET method REST API v4.3
–> GET method REST API v4.1
–> GET method REST API v4

前バージョンではmacOS 10.15上でクラッシュするかわりにmacOS 10.14上で高速という特徴がありました。ただ、macOS 10.15上でクラッシュしないように調整を行っていくと、処理速度については別段速くもなく(キャッシュがヒットしていない雰囲気)、よりいっそうキャッシュについて調べる必要が出てきています。

一応、キャッシュの作り方については調べてみたものの、

キャッシュが効いている雰囲気がまったくありません。

キャッシュの内容を確認してみると、からっぽですね(^ー^; もう少し(時間のあるときに)キャッシュの連携などを調べておくといいのかもしれません。最低限、macOS 10.15でクラッシュしなくなったので、NSURLConnectionを呼び出してリジェクトを喰らわないように準備しておくという感じでしょうか。

AppleScript名:GET method REST API v4.4.1_wikipedia.scptd
— Created 2019-05-02 by Takaaki Naganoya
— Modified 2020-04-02 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSMutableData : a reference to current application’s NSMutableData
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false
property aSession : missing value
property aCache : missing value

on run
  set retData to missing value
  
set drecF to false
  
set aSession to missing value
  
  
set aQueryKeyTitle to "AppleScript"
  
set aRes to getWikiText(aQueryKeyTitle) of me
  
return aRes
end run

on getWikiText(aQueryKeyTitle)
  set reqURLStr to "https://en.wikipedia.org/w/api.php"
  
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL, 5) of me
  
if aRes = missing value then return "Error"
  
  
set bRes to (aRes’s valueForKeyPath:"parse.wikitext.*") as string
  
return bRes
end getWikiText

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set (my retData) to NSMutableData’s alloc()’s init()
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
–if my aCache = missing value then
  
set cachePath to (POSIX path of (path to library folder from user domain)) & "/Caches/AppleScriptURLCache"
  
set my aCache to current application’s NSURLCache’s alloc()’s initWithMemoryCapacity:512000 diskCapacity:1024 * 1024 * 5 diskPath:cachePath
  
–end if
  
current application’s NSURLCache’s setSharedURLCache:(my aCache)
  
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set v2 to system attribute "sys2" –> 14
  
if v2 < 15 then
    –macOS 10.14まで
    
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  else
    –macOS 10.15以降。10.15でdefaultSessionConfigurationを使うとクラッシュしやすい???
    
set identifier to "BackgroundSessionConfiguration"
    
set aConfig to NSURLSessionConfiguration’s backgroundSessionConfiguration:(identifier)
  end if
  
  
aConfig’s setRequestCachePolicy:(current application’s NSURLRequestReturnCacheDataElseLoad)
  
  
aConfig’s setURLCache:(my aCache)
  
–aConfig’s setTimeoutIntervalForRequest:0.5
  
–aConfig’s setTimeoutIntervalForResource:timeoutSec
  
–aConfig’s setWaitsForConnectivity:false
  
  
–どちらでも速度差がない
  
set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(current application’s NSOperationQueue’s mainQueue())
  
–set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeoutSec) times
    if (my drecF) is not equal to false then
      exit repeat
    end if
    
delay "0.001" as real
  end repeat
  
  
–aSession’s invalidateAndCancel() –delegateの無効化
  
my aSession’s finishTasksAndInvalidate()
  
set my aSession to missing value
  
  
return my parseSessionResults()
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  (my retData)’s appendData:tmpData
end URLSession:dataTask:didReceiveData:

on URLSession:tmpSession dataTask:tmpTask willCacheResponse:cacheRes completionHandler:aHandler
  set (my drecF) to true
end URLSession:dataTask:willCacheResponse:completionHandler:

on URLSession:tmpSession task:tmpTask didCompleteWithError:tmpError
  if tmpError = missing value then
    set (my drecF) to true
  else
    error "Donwload Failed"
  end if
end URLSession:task:didCompleteWithError:

on parseSessionResults()
  set resStr to NSString’s alloc()’s initWithData:(my retData) encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict
end parseSessionResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

★Click Here to Open This Script 

Posted in Internet REST API URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSJSONSerialization NSMutableData NSMutableDictionary NSMutableURLRequest NSString NSURL NSURLCache NSURLComponents NSURLQueryItem NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | 1 Comment

iWork Apps Update v10.0

Posted on 4月 1, 2020 by Takaaki Naganoya

Keynote、Pages、Numbersのv10.0が配信されました。Keynoteの前バージョンはv9.2、Pagesはv8.2、Numbersはv6.2.1でしたが、バージョン番号を別々に採番することがめんどくさくなったのか、内部のエンジンが一新されたのか、バージョン番号をそろえてきました。

おそらく、マーケティング的な要請やユーザーサポートの手間を省くために番号をそろえてきたのでしょう。

Pages/NumbersについてはmacOS 10.14以上が対象。KeynoteはmacOS 10.15.4が必要とのことですが、いろいろ致命的なバグの修正を含んでいるため、後日macOS 10.14.6向けのKeynoteアップデートが配信されることを期待したいところです。

# アップデートに出てこないだけで、Mac App Storeから個別にKeynote v10.0のダウンロードが(macOS 10.14.6上でも)できました。なんででしょう?

v10.0 UpdateのAppleScript的な変更の有無

■Keynote v10.0:2か所

■Pages v10.0:1か所

■Numbers v10.0:変更点なし
Numbers v6.2で「特定の行数の表を作るとエラーになる」というバグがありましたが、これはv6.2.1で修正されました。これが修正されています(記憶違いだったので、記事を修正しておきます)。

Pages v10.0の変更点

documentにfacing pagesというプロパティが新設されました。見開き表示時にページの左右(奇数ページ、偶数ページ)を考慮して2ページ表示のペアを変更するという機能のようです。

AppleScript名:Pages v10.0で追加されたfacing pagesの操作を行う
tell application "Pages"
  tell front document
    set curStat to facing pages
    
    
set facing pages to not curStat –反転
    
delay 2
    
set facing pages to curStat –元に戻す
  end tell
end tell

★Click Here to Open This Script 

全言語的に普遍的な内容ではあるのですが、日本語ユーザー的には縦書き/横書きの設定属性値を持ってくれたほうがありがたいところです。たぶん、自分は使うことはないと思います。

Keynote v10.0の変更点

Keynoteは前バージョンでかなりおかしなバグが発覚していたので、その修正が行われているかどうか、というのが見所です。

結論からいえば、バグは修正されています。macOSに関して久しぶりに前向きなニュースといえます。彼らにバグを修正する意思と能力が残されていたことについては喜びたいところです。同時に残念なニュースとして、この修正に関連して新たなバグが生まれています(このあたりがいかにもAppleらしい)。

Keynoteバグ1:表(table)作成時に行数によってはエラーになる

5行の表を作るとエラーになり、他の行数でもいろいろエラーになる組み合わせが確認されていました。テスト用のAppleScriptを書いて、行数を2〜100行で変更しつつ作成、列数を2〜30列で変更しつつ作成、行数および列数を順次ループで2〜20まで変更しつつ新規作成するなどのテストを実施。無事、修正を確認できました。

ただし、本テストは表の新規作成についてのみ確認したものであり、既存の表の行数/列数の変更を確認したものではありません。Appleの仕事に関しては、修正点の周囲に新たなバグを生む可能性が高く、修正時と修正後が一番危険な状態です。彼らに「自分の作った機能を動作確認する」という能力を期待してはいけません。信じてもいけません。つねに、疑いの目で見ることが重要です。

AppleScript名:Keynote書類上に表を作成、行数を2から100まで可変
tell application "Keynote"
  tell front document
    tell current slide
      repeat with i from 2 to 100
        set aTable to make new table with properties {header column count:0, header row count:0, row count:i, column count:3}
        
delay 1
        
delete aTable
      end repeat
    end tell
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:Keynote書類上に表を作成、列数を2から30まで可変
tell application "Keynote"
  tell front document
    tell current slide
      repeat with i from 2 to 30
        set aTable to make new table with properties {header column count:0, header row count:0, row count:5, column count:i}
        
delay 1
        
delete aTable
      end repeat
    end tell
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:Keynote書類上に表を作成、行数および列数を2から20まで可変
tell application "Keynote"
  tell front document
    tell current slide
      repeat with x from 2 to 20
        repeat with y from 2 to 20
          set aTable to make new table with properties {header column count:0, header row count:0, row count:y, column count:x}
          
delay 0.01
          
delete aTable
        end repeat
      end repeat
    end tell
  end tell
end tell

★Click Here to Open This Script 

Keynoteバグ2:書類(document)のムービーexport optionsにバグ

数値ではじまる予約語や記号を含む予約語はAppleScriptの言語処理系では宣言できません。エラーになります。それをAppleの(おそらくKeynoteの)担当者がKeynote v7.1のアップデート時に、従来の「small」「midium」「large」といったEnumによる指定から、「360p」「540p」「720p」「1080p」「2160p」という指定を行えるように変更を加えました。

より大きな解像度の書き出しに対処したことは評価できると思いますが、そもそもAppleScriptの処理系で認識できない「数字で始まる予約語」に変えたのはダメダメです(スクリプトエディタ上で構文確認を行うとエラーになる=使えない)。つまり、この担当者はsdefの改変を行なっただけで、実際にコードを書いて動作確認を行っていないことがわかります。

Appleにバグレポートを書きつつ、このような処理が必要な場合にはnative sizeで書き出して、そのあとでムービーをリサイズするような処理で回避していました(GUI Scriptingで乗り切ったScripterもいるようですが)。

Keynote v10.0では「format360p」「format540p」「format720p」「format1080p」「format2160p」と変更され、AppleScriptの構文確認時にエラーでハネられることはなくなりました。この点についてはバグ修正が行われたものと判断してよいと思われます。

ただし、従来動作していたEnum「native size」を指定するとエラーになるようになってしまいました。互換性のために残したが動作していない、といったコメントが書かれているわけでもないため、これはバグだと判断します。

■Keynote書類フォーマットとムービー書き出し時の解像度の対応表(Piyomaru Software独自調査による)

movie export formats 標準(4:3) ワイド(16:9)
format360p 480 × 360 640 × 360
format540p 720 × 540 960 × 540
format720p 960 × 720 1280 × 720
format1080p 1440 × 1080 1920 × 1080
format2160p 2880 × 2160 3840 × 2160
AppleScript名:Keynote 360p movie export test
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format360p}
  end tell
end timeout

★Click Here to Open This Script 

AppleScript名:Keynote 540p movie export test
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format540p}
  end tell
end timeout

★Click Here to Open This Script 

AppleScript名:Keynote 720p movie export test
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format720p}
  end tell
end timeout

★Click Here to Open This Script 

AppleScript名:Keynote 1080p movie export test
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format1080p}
  end tell
end timeout

★Click Here to Open This Script 

AppleScript名:Keynote 2160p movie export test
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format2160p}
  end tell
end timeout

★Click Here to Open This Script 

AppleScript名:Keynote ‌‌native size movie export test (Bug)
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    –export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:‌‌native size}
  end tell
end timeout

★Click Here to Open This Script 

Posted in Bug news | Tagged 10.14savvy 10.15savvy Keynote Numbers Pages | 1 Comment

NSURLSessionでREST API呼び出しv4.4

Posted on 3月 29, 2020 by Takaaki Naganoya

REST API呼び出しに欠かせない部品をアップデートしました。

–> GET method REST API v4.3
–> GET method REST API v4.1
–> GET method REST API v4

従来、NSURLConnectionを使って同期処理を行っていましたが、これがDepreceted扱いになりました。すぐになくなることはありませんが、いつかなくなる可能性があります。

このため、NSURLConnectionから動作原理の異なるNSURLSessionを使うよう移行する必要があります(curlコマンドを利用するというルートもあります)。

とはいえ、blocks構文の使えないAppleScriptでこのNSURLSessionを使えるようにするのは大変です。非同期通信を行うNSURLSessionを非同期処理のしにくいAppleScriptで、同期処理っぽく書かなくてはなりません。

NSURLSessionによる通信では、サーバーとの間で何回かのやりとりがあって、データを小分けに複数回受信する必要がありました。NSMutableDataというオブジェクトの存在を知ったのでいい感じに処理できるようになってきました。

NSURLSessionのメリットとして喧伝されている非同期処理は、AppleScriptから呼び出しているかぎりはそれほどメリットになりません。もう少し使い込めば活用できるかもしれませんが、まだそういう段階にはありません。

NSURLSessionの導入によって得られるメリットで最大のものは、キャッシュ機構です。NSURLConnectionでもキャッシュ機構は利用できましたが、NSURLSessionではよりAPIに深く統合されているものと理解しました。

キャッシュの効き方については、設定で何段階かに設定できるとAppleのオンラインドキュメントに書かれています。本Scriptでは、キャッシュ優先でキャッシュが存在している場合にはキャッシュ内のデータを返し、キャッシュが存在していない場合にはWebサーバーに問い合わせを行うように設定しています。

キャッシュが効いている状況なら、NSURLConnectionで1.8秒ぐらいの処理がNSURLSessionで0.1秒程度と大幅に速く処理できます。キャッシュが効いていない状況(初回実行時)だと、NSURLSessionのほうがやや処理に時間がかかるぐらいです。

処理結果について、NSURLConnection版とNSURLSession版で結果の比較を行ってみましたが、とくに差異は見られませんでした。

本サンプルScriptでは、Wikipedia(英語版)へのキーワードの問い合わせを行います。NSURLConnection版では複数回実行しても同じぐらいの速度で実行されますが、NSURLSession版では2度目から早く終わります(Script Debugger上で動かすと秒以下の精度の時間がわかります)。

macOS 10.14上で作ってmacOS 10.14.6/10.13.6上で動作確認しています(スクリプトエディタ、Script Debuggerで動作確認)。ただし、macOS 10.15上だとクラッシュします。Xcodeのプロジェクトに入れてみましたが、同様にmacOS 10.15上ではクラッシュします。

ただし、自分のmacOS 10.14.6環境はSIP解除しているのと、macOS 10.15環境のクラッシュログにSIP関連のメッセージが残っているので、OSバージョンではなくSIPのためかもしれません(macOS 10.14.6でもSIPを有効にするとクラッシュするかもしれない & macOS 10.15.xでもSIPを無効にするとクラッシュしないかもしれない)。

AppleScript名:GET method REST API v4.4_wikipedia
— Created 2019-05-02 by Takaaki Naganoya
— Modified 2020-03-29 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSMutableData : a reference to current application’s NSMutableData
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false

set aQueryKeyTitle to "Steve Jobs" –キーワードの正規化が必要("戦場の絆"→"機動戦士ガンダム 戦場の絆" )
set reqURLStr to "https://en.wikipedia.org/w/api.php"
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL, 10) of me
set bRes to (aRes’s valueForKeyPath:"parse.wikitext.*") as string
return bRes

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set (my retData) to NSMutableData’s alloc()’s init()
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
aConfig’s setRequestCachePolicy:(current application’s NSURLRequestReturnCacheDataElseLoad)
  
set aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
aTask’s resume() –Start URL Session
  
  
repeat (10 * timeoutSec) times
    if (my drecF) = true then
      exit repeat
    end if
    
delay 0.1
  end repeat
  
  
return my parseSessionResults()
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  (my retData)’s appendData:tmpData
end URLSession:dataTask:didReceiveData:

on URLSession:tmpSession dataTask:tmpTask didCompleteWithError:tmpError
  set (my drecF) to true
end URLSession:dataTask:didCompleteWithError:

on URLSession:tmpSession dataTask:tmpTask willCacheResponse:cacheRes completionHandler:aHandler
  set (my drecF) to true
end URLSession:dataTask:willCacheResponse:completionHandler:

on parseSessionResults()
  set resStr to NSString’s alloc()’s initWithData:(my retData) encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict
end parseSessionResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel1(aRecList as list, aPredicate as string)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
set bList to filteredArray as {list, missing value}
  
return bList
end filterRecListByLabel1

★Click Here to Open This Script 

AppleScript名:GET method REST API_wikipedia
— Created 2016-03-03 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set aQueryKeyTitle to "Steve Jobs" –キーワードの正規化が必要("戦場の絆"→"機動戦士ガンダム 戦場の絆" )
set reqURLStr to "https://en.wikipedia.org/w/api.php"
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL, 10) of me
set aRESTres to json of aRes
set bRes to (aRESTres’s valueForKeyPath:"parse.wikitext.*") as string

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL, timeoutSec)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to (dRes’s statusCode()) as integer
  
  
–Get Response Header
  
set resHeaders to (dRes’s allHeaderFields()) as record
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel1(aRecList as list, aPredicate as string)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
set bList to filteredArray as list
  
return bList
end filterRecListByLabel1

★Click Here to Open This Script 

Posted in Internet REST API URL | Tagged 10.13savvy 10.14savvy NSArray NSJSONSerialization NSMutableData NSMutableDictionary NSMutableURLRequest NSPredicate NSString NSURL NSURLComponents NSURLQueryItem NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | 2 Comments

マウスカーソルを変更

Posted on 3月 24, 2020 by Takaaki Naganoya

Xcode上で記述するAppleScriptアプリケーションにおいて、マウスカーソルを変更するAppleScriptです。

NSCursorにアクセスして、macOS側で用意しているカーソルにマウスカーソルのイメージを変更します。

–> Watch Demo Movie

あらかじめmacOSが用意しているカーソルはいくつかあるわけですが、これで満足するわけがなくて……任意のNSImageをカーソルに指定する方法について調べていたものの、なかなかうまくいかなかったので、このOS側で用意しているカーソルへの切り替えのみまとめておきました。

–> Download Xcode Project

他のアプリケーションに切り替えると通常のカーソルに戻ってしまうので、本プロジェクト側でアプリケーション切り替えのイベントハンドラでカーソルの再変更などを行うべきなのかも。

  set aImage to current application's NSImage's  imageNamed:(current application's NSImageNameComputer)
  set tmpCursor to current application's NSCursor's alloc()'s initWithImage:aImage hotSpot:{0,15}
tmpCursor's |set|()

結局、コンピュータのアイコンをマウスカーソルに指定するというところまでは持って行けた(カーソル画像の差し替えができた)わけなんですが、NSCursorの挙動を評価してみたら、カーソルが標準のものに戻るタイミングがバラバラ(他のディスプレイにカーソルが移動したとき、というわけでもない)で、挙動が謎すぎであります。

その後、対象のビュー(NSViewなど、その派生クラス)にマウスカーソルが入った/出たことを検出するイベントハンドラでマウスカーソルの形状変更を明示的に指定するような実装で落ち着きました(Edama2さんから教えていただきました。ありがとうございます)。

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— CursorTest
—
— Created by Takaaki Naganoya on 2020/03/24.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
  
on applicationWillFinishLaunching:aNotification
    — Insert code here to initialize your application before any files are opened
  end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    — Insert code here to do any housekeeping before your application quits
    
return current application’s NSTerminateNoww
  end applicationShouldTerminate:
  
  
on clicked:aSender
    set aTag to (aSender’s tag) as integer
    
if aTag = 100 then
      current application’s NSCursor’s arrowCursor()’s |set|()
    else if aTag = 101 then
      current application’s NSCursor’s disappearingItemCursor()’s |set|()
    else if aTag = 102 then
      current application’s NSCursor’s contextualMenuCursor()’s |set|()
    else if aTag = 103 then
      current application’s NSCursor’s openHandCursor()’s |set|()
    end if
  end clicked:
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode System | Tagged 10.13savvy 10.14savvy 10.15savvy NSCursor NSImage | Leave a comment

指定画像をICNSに変換

Posted on 3月 19, 2020 by Takaaki Naganoya

指定画像をICNS書類に変換するAppleScriptです。

ICNS書類自体は、Classic Mac OS時代にあったアイコンの画像リソースである「icn#」リソースをファイル化したもの、と理解しています(位置付け的に、データ形式とか厳密なレベルで比較したわけではなくて)。

現在では、ICNS書類を作ってアプリケーションアイコンに指定したり、

Xcode上で解像度の異なる画像ファイルをドラッグ&ドロップすると、アプリケーションのICNSファイルを作ってくれます。

Finder上で解像度の異なる画像をフォルダ構造に入れてフォルダの拡張子をつけかえるだけでICNSと認識してくれたような記憶もあります。

そのため、ICNS書類をわざわざScriptから作る需要もないだろうと考えて掲載してこなかったのですが、意外なところでICNS書類の作成を求められました。

自作アプリケーションのカスタム書類を定義して、書類にカスタムアイコンをつけようとしたところ、PNGなどの画像では認識されず、結局ICNS書類を指定する必要に迫られました(意外)。

そんなわけで、いろいろICNS作成Scriptをまとめておきました。

こちらのScriptは実際には実行していませんが、/usr/bin/tiff2icnsコマンドがmacOS 10.15にも含まれていることを確認しています。

AppleScript名:TIFF画像をicnsに変換 v2scpt
tell application "Finder"
  set a to choose file
end tell
set theTiffPath to POSIX path of a
–128 x 128のtiff画像が必要
do shell script "/usr/bin/tiff2icns -noLarge " & (quoted form of theTiffPath)

★Click Here to Open This Script 

こちらは、オープンソースの「IcnsFactory」をフレームワーク化したIconFactory.frameworkを呼び出すバージョンです。自分が実際に使ったのはこちらです。

macOS 10.14以降ではScript Debugger上で実行するか、Script Debuggerから書き出したアプレット(Application(Enhanced))で実行するか、あるいはMacのSIPを解除して実行するなどの方法で実行できます。

Xcode上のAppleScript Applicationプロジェクトに突っ込んで呼び出せば、SIPの解除やScript Debuggerのインストールは必要ありません。

–> Download iconFactory.framework

AppleScript名:画像をICNS書類に
— Created 2017-04-14 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "IconFactory" –https://github.com/kgn/IcnsFactory

set aFile to POSIX path of (choose file)
set outFile to POSIX path of (choose file name)
set anImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aFile
set iconFam to current application’s IcnsFactory’s writeICNSToFile:outFile withImages:anImage

★Click Here to Open This Script 

Posted in file Image | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

WebKit Utilities v2

Posted on 3月 16, 2020 by Takaaki Naganoya

AppleScriptで指定URLのページを表示する「WebKit Utilities」がmacOS 10.13以降の環境で動かなくなっていたので、書き換えて動くようにしておきました。

–> Download WebKit Utilities_archive v2

これ自体が役に立ったということはなく、単にAppleScript Librariesの書き方のサンプルと理解しています。Webサイトの表示を行うよりも1枚ものの画像やPDFにレンダリングする処理のほうがバッチ処理の中では相性がいいと思います。

また、このScriptはWkWebViewではなく古いWebViewを使っているので、じきに動かなくなります。

AppleScript名:WebKit Utilitiesで指定URLをウィンドウ表示
— Created 2017-03-24 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use webLib : script "WebKit Utilities"

set targetURL to "http://www.piyocast.com/"
display URL targetURL window size {1024, 1024}

★Click Here to Open This Script 

AppleScript名:WebKit Utilities
— An example AppleScript/Objective-C library that uses the WebKit framework.

use AppleScript
use framework "AppKit"
use framework "WebKit"

property NSURL : a reference to current application’s NSURL
property WebView : a reference to current application’s WebView
property NSScreen : a reference to current application’s NSScreen
property NSThread : a reference to current application’s NSThread
property NSWindow : a reference to current application’s NSWindow
property NSURLRequest : a reference to current application’s NSURLRequest
property NSMutableDictionary : a reference to current application’s NSMutableDictionary

on _DisplayWebWindowWithURL:theURLString windowSize:theWindowSize
  — Create and display a horizontally centered window with a WebView
  
  
set {thisWindowWidth, thisWindowHeight} to theWindowSize
  
set screenBounds to the NSScreen’s mainScreen’s visibleFrame as any
  
  
if class of screenBounds = record then
    set screenWidth to screenBounds’s |size|’s width
    
set screenHeight to screenBounds’s |size|’s height
    
set windowLeft to ((screenWidth – thisWindowWidth) / 2) + (screenBounds’s origin’s x)
    
set windowBottom to screenHeight – thisWindowHeight + (screenBounds’s origin’s y) – 40
  else
    copy screenBounds to {{originX, originY}, {screenWidth, screenHeight}}
    
set windowLeft to ((screenWidth – thisWindowWidth) / 2) + originX
    
set windowBottom to screenHeight – thisWindowHeight + originY – 40
  end if
  
  
set theStyleMask to (get current application’s NSTitledWindowMask) + (get current application’s NSClosableWindowMask) + (get current application’s NSMiniaturizableWindowMask) + (get current application’s NSResizableWindowMask)
  
set webWindow to NSWindow’s alloc()’s initWithContentRect:(current application’s NSMakeRect(windowLeft, windowBottom, thisWindowWidth, thisWindowHeight)) ¬
    styleMask:theStyleMask backing:(current application’s NSBackingStoreBuffered) defer:false
  — set webWindow’s title to "WebView Created with AppleScript – " & theURLString
  
  
set theWebView to WebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, thisWindowWidth, thisWindowHeight)) ¬
    frameName:"WebKit Frame" groupName:"WebKit Group"
  set webWindow’s contentView to theWebView
  
  
tell webWindow to makeKeyAndOrderFront:(missing value)
  
  
— Start loading the URL
  
  
set theURL to NSURL’s URLWithString:theURLString
  
set theURLRequest to NSURLRequest’s requestWithURL:theURL
  
tell theWebView’s mainFrame to loadRequest:theURLRequest
  
  
webWindow
end _DisplayWebWindowWithURL:windowSize:

— The following two handlers exist to deal with running on a background thread.
— If we’re on a background thread, we have to run the UI code on the main thread.

on _DisplayWebWindowMainThread:parameterDictionary
  try
    set theURLString to parameterDictionary’s objectForKey:"url string"
    
set theWindowSize to parameterDictionary’s objectForKey:"window size"
    
    
set webWindow to my _DisplayWebWindowWithURL:theURLString windowSize:theWindowSize
    
    
tell parameterDictionary to setObject:webWindow forKey:"result"
  on error errMsg number errNum
    using terms from scripting additions
      display alert "Error!" message errMsg & " (" & errNum & ")"
    end using terms from
    
tell parameterDictionary to setObject:{errMsg, errNum} forKey:"error"
  end try
end _DisplayWebWindowMainThread:

on display URL theURLString window size theWindowSize
  — All UI methods must be invoked on the main thread.
  
if (NSThread’s isMainThread) then
    my _DisplayWebWindowWithURL:theURLString windowSize:theWindowSize
  else
    — Parameters, results and error information are communicated between threads via a dictionary.
    
set parameterDictionary to NSMutableDictionary’s dictionary()
    
tell parameterDictionary to setObject:theURLString forKey:"url string"
    
tell parameterDictionary to setObject:theWindowSize forKey:"window size"
    
    
its performSelectorOnMainThread:"_DisplayWebWindowMainThread:" withObject:parameterDictionary waitUntilDone:true
    
    
— Propagate errors from the other thread
    
    
set errInfo to parameterDictionary’s objectForKey:"error"
    
if errInfo is not missing value then error errInfo’s first item number errInfo’s second item
    
    
parameterDictionary’s objectForKey:"result"
  end if
end display URL

★Click Here to Open This Script 

Posted in GUI Internet URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSMutableDictionary NSScreen NSThread NSURL NSURLRequest NSWindow WebView | Leave a comment

正方形セルの表データで指定セルに隣接するセルブロックを検出

Posted on 3月 11, 2020 by Takaaki Naganoya

正方形セルの表を形成する1次元配列上で、指定セルに隣接する指定データの入っているセルブロックを検出するAppleScriptです。

テストデータは11×11のサイズで作ってみました。本Scriptを作ることが最終目的ではないので、実戦投入はしていませんが、それなりに動いているようです。11セルの対象データを検出するのに、0.002秒ぐらい(10回実行時の平均値)。

本プログラムではセルアドレス=58のセルと隣接する「9」のデータが入っているセルのアドレスをすべて求めています。基準セルの8方向のセルアドレスを計算したうえでデータにアクセスして、「9」が入っているセルを検出。それらをまとめてすべての検出セルの8方向のアドレスを検査し、それ以上検出セル数が増加しない状態までループ処理を続けています。

本プログラムは本番プログラムを作るための習作だったので、ものすごくオーソドックスな組み方をしています。本番のプログラムでは、この「無駄に長い」処理を大幅に簡略化して3分の1ぐらいの長さになりました。

AppleScript名:findBlock2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/03/10
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property dataWidth : 11
property dataHeight : 11
property dataMax : 121

property testData : {"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "9", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "9", "9", "9", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "9", "9", "9", "9", "1", "1", "1", "1", "1", "1", ¬
  
"1", "9", "9", "9", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1"}

set foundList to {58}

set prevFound to 1
repeat
  set foundList to findAllDirection(foundList) of me
  
set aLen to length of foundList
  
if aLen = prevFound then
    return foundList
  else
    copy aLen to prevFound
  end if
end repeat

return foundList
–> {58, 69, 68, 70, 80, 79, 81, 82, 91, 90, 92}

on findAllDirection(foundList)
  repeat with sCanCell in foundList
    
    
set nRes to findN(sCanCell) of me
    
set sRes to findS(sCanCell) of me
    
set eRes to findE(sCanCell) of me
    
set wRes to findW(sCanCell) of me
    
set nwRes to findNW(sCanCell) of me
    
set neRes to findNE(sCanCell) of me
    
set swRes to findSW(sCanCell) of me
    
set seRes to findSE(sCanCell) of me
    
    
if nRes is not equal to false then
      set newAddr to contents of (item 2 of nRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set nRes to false
      end if
    end if
    
    
if sRes is not equal to false then
      set newAddr to contents of (item 2 of sRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set sRes to false
      end if
    end if
    
    
if eRes is not equal to false then
      set newAddr to contents of (item 2 of eRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set eRes to false
      end if
    end if
    
    
if wRes is not equal to false then
      set newAddr to contents of (item 2 of wRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set wRes to false
      end if
    end if
    
    
if nwRes is not equal to false then
      set newAddr to contents of (item 2 of nwRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set nwRes to false
      end if
    end if
    
    
if neRes is not equal to false then
      set newAddr to contents of (item 2 of neRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set neRes to false
      end if
    end if
    
    
if swRes is not equal to false then
      set newAddr to contents of (item 2 of swRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set swRes to false
      end if
    end if
    
    
if seRes is not equal to false then
      set newAddr to contents of (item 2 of seRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set seRes to false
      end if
    end if
    
  end repeat
  
return foundList
end findAllDirection

—————————————

on findS(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to incLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findS

on findN(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to decLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findN

on findE(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to incCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findE

on findW(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to decCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findW

on findNW(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to decLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpAddr to decCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findNW

on findNE(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to decLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpAddr to incCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findNE

on findSW(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to incLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpAddr to decCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findSW

on findSE(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to incLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpAddr to incCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findSE

—————————————

on incLine(anAddress)
  if anAddress + dataWidth > dataMax then
    set anAddress to false
  else
    set anAddress to anAddress + dataWidth
  end if
  
return anAddress
end incLine

on decLine(anAddress)
  if anAddress – dataWidth < 1 then
    set anAddress to false
  else
    set anAddress to anAddress – dataWidth
  end if
  
return anAddress
end decLine

on incCell(anAddress)
  set tmpMax to anAddress div dataWidth
  
if ((anAddress + 1) div dataWidth) is not equal to tmpMax then
    set anAddress to false
  else
    if anAddress + 1 < dataMax then
      set anAddress to anAddress + 1
    else
      return false
    end if
  end if
  
return anAddress
end incCell

on decCell(anAddress)
  set tmpMax to anAddress div dataWidth
  
set tmp2Max to (anAddress – 1) div dataWidth
  
if anAddress – 1 > 0 then
    if (tmp2Max is equal to tmpMax) then
      set anAddress to anAddress – 1
    end if
  else
    set anAddress to false
  end if
  
return anAddress
end decCell

★Click Here to Open This Script 

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

Numbersの表の選択範囲をシーケンシャル番号で埋める

Posted on 3月 11, 2020 by Takaaki Naganoya

Numbersの最前面の書類で選択中の表の選択範囲を1からはじまるシーケンシャル番号で埋めるAppleScriptです。

Numbers書類のセルを埋めるのは、それなりにコストの高い(処理時間が長い)処理なので、数十とか百ぐらいの要素だと、このように悠長にループで埋めても大丈夫ですが、数千とか数万セルを相手にする場合には途方もない時間がかかります。

要素数が多い場合には、CSVのファイルを組み立ててオープンする処理方法をおすすめします(一瞬で終わるので)。

この手の処理は、ほぼ「書き捨て」で保存すらしないことが多いのですが、たまたま気が向いたので保存しておきました。

本ScriptはmacOS 10.14.6/10.15.3+Numbers v6.2.1、macOS 10.13.6+Numbers v6.2で動作確認しています。

AppleScript名:Numbersの表の選択範囲をシーケンシャル番号で埋める
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/03/10
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

tell application "Numbers"
  tell front document
    tell active sheet
      try
        set theTable to first table whose class of selection range is range
      on error
        display notification "Numbers: There is no selection"
        
return
      end try
      
      
tell theTable
        set aRes to value of cells of selection range
      end tell
      
      
set aLen to length of aRes
      
set newList to makeSequential1DList(aLen) of me
      
      
tell theTable
        set cList to cells of selection range
      end tell
      
      
repeat with i from 1 to aLen
        set anObj to contents of item i of cList
        
set aVal to contents of item i of newList
        
        
ignoring application responses
          set value of anObj to aVal
        end ignoring
        
      end repeat
    end tell
  end tell
end tell

on makeSequential1DList(itemLen)
  set outList to {}
  
repeat with i from 1 to itemLen
    set the end of outList to i
  end repeat
  
return outList
end makeSequential1DList

★Click Here to Open This Script 

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

mirroringの設定と解除

Posted on 3月 11, 2020 by Takaaki Naganoya

自分はディスプレイのミラーリング機能は日常的にあまり使っていません。実際にやってみたらどうだったのかをまとめてみました。

この手の処理をAppleScriptで書こうとしても、そのための命令が標準で内蔵されていないため、アプローチの方法はかぎられています。

 (1)思いっきりハードウェア寄りのプログラム(Cとかで書いた)を呼び出す
 (2)アクセシビリティ系の機能(GUI Scripting)を使ってシステム環境設定を操作する

の2つです。(2)は、画面上の要素の些細な変更によりプログラムを書き換える必要が出てくるうえに、信頼性が高くないので、あまりやりたくありません。もちろん、画面上の要素を検索しながら処理する方法もあるわけですが、それなりに(画面要素の検索に)時間がかかります。

そうなると、(1)を採用することになります。探すと………すぐにみつかりました。「mirror-displays」というコマンドラインアプリケーションです。ソースコードを読んでみると、CoreGraphics系の各種フレームワークを呼び出している、Objective-Cで書かれた(ほとんどCのコード)プログラムです。

これをスクリプトバンドルの中に入れて呼び出してみました。1回実行するとメインモニタの内容が他のモニタにミラーリングされます。もう1回実行すると、ミラーリングが解除されます。

–> Download mirroring_toggle (Script Bundle with executable command in its bundle)

mirrorコマンドのオプションには、「どのモニタをミラーリングさせるか」といった指定ができるようですが、試していないのでとくに凝った指定も何もしていません。

mirrorコマンドはmacOS 10.14でビルドして10.10以降をターゲットにしてみましたが、そこまで古い環境は手元に残っていないのでテストしていません。また、macOS 10.15のマシンには複数台のモニタをつないでいないので、macOS 10.15上でのテストも行っていません。

AppleScript名:mirroringの設定と解除
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/03/11
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

–https://github.com/hydra/mirror-displays
–バンドルの中に入れたmirrorコマンドをただ呼んでるだけ
set myPath to POSIX path of (path to me)
set comPath to myPath & "/Contents/Resources/mirror"
do shell script quoted form of comPath

★Click Here to Open This Script 

Posted in shell script System | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

ServerInformationで製品情報を取得

Posted on 3月 9, 2020 by Takaaki Naganoya

AppleのPrivate Frameworkである「ServerInformation.framework」を呼び出すAppleScriptです。

AppStoreを通じて配布するアプリケーションではPrivate Frameworkの使用は問題になる可能性がありますが、ユーザーの手元で動かしているAppleScriptでPrivate Frameworkを煮ようが焼こうが関係ないと思います。

「ServerInformation.framework」は割と利用価値が高そうなものであります。実際にGithub上で探したサンプルをAppleScriptに翻訳して試してみました。

本サンプルは、/System/Library/PrivateFrameworks/という、ふだんFrameworkを呼び出す先「ではない」ディレクトリに入っているFrameworkを呼び出すサンプルでもあり、NSBundleを通じてFrameworkを呼び出す実例でもあります。

この方法を利用すれば、最新のmacOSで(SIPを解除しないで)そのままでは呼び出せなくなっていたホームディレクトリ下のFrameworkとかアプレット内に同梱したFrameworkをローディングして呼び出すことができそうな雰囲気があります。

AppleScript名:ServerInformationで製品情報を取得.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/03/09
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
— https://gist.github.com/erikng/d90d21f502351d64a541600226626a28

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

set ServerInformation to current application’s NSBundle’s bundleWithPath:"/System/Library/PrivateFrameworks/ServerInformation.framework"
set ServerCompatibility to current application’s NSBundle’s bundleWithPath:"/System/Library/PrivateFrameworks/ServerCompatibility.framework"

set ServerInformationComputerModelInfo to ServerInformation’s classNamed:"ServerInformationComputerModelInfo"
set SVCSystemInfo to ServerCompatibility’s classNamed:"SVCSystemInfo"

set myInfo to SVCSystemInfo’s currentSystemInfo()

set exInfo to (ServerInformationComputerModelInfo’s attributesForModelIdentifier:(myInfo’s computerModelIdentifier())) as record

set anArchitecture to exInfo’s architecture
–> "x86_64"

set aMonoImageSel to exInfo’s monochromeSelectedHardwareImage
–> NSImage (Gray)

set aMonoImage to exInfo’s monochromeHardwareImage
–> NSImage (Gray)

set aDesc to exInfo’s |description|
–> "15インチMacBook Pro Retinaディスプレイを装備、デュアルコアIntel Core i7プロセッサ搭載(アルミニウムユニボディ)、2012年の中期に投入。"
–> "Mac mini Intelデュアルコアプロセッサおよび統合型グラフィックス搭載、2014年後期に投入。"
–> "MacBook Air 11インチディスプレイを装備、2011年の中期に投入。"

set aModel to exInfo’s model
–> "MacBook Pro"
–> "Mac mini"
–> "MacBook Air"

set aProcessor to exInfo’s processor
–> "Intel Core i7"
–> "デュアルコアIntel Core i5、デュアルコアIntel Core i7"
–> "Dual-Core Intel Core i5、Intel Core i7"

set aMarketModel to exInfo’s marketingModel
–> "15インチMacBook Pro, Retinaディスプレイ, Intel Core i7 (Mid 2012)"
–> "Mac mini(Late 2014)"
–> "11インチMacBook Air(Mid 2011)"

set aColorImage to exInfo’s hardwareImage
–> NSImage (Color)

★Click Here to Open This Script 

Posted in System | Tagged 10.14savvy 10.15savvy | Leave a comment

Post navigation

  • Older posts
  • Newer posts

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

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 15, Sequoia
  • 指定のWordファイルをPDFに書き出す
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • Numbersで選択範囲のセルの前後の空白を削除
  • メキシカンハットの描画
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AdobeがInDesign v19.4からPOSIX pathを採用
  • AppleScriptによる並列処理
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • Cocoa Scripting Course 続刊計画
  • macOS 14.xでScript Menuの実行速度が大幅に下がるバグ
  • AppleScript入門③AppleScriptを使った「自動化」とは?
  • macOS 15でも変化したText to Speech環境
  • Keynote/Pagesで選択中の表カラムの幅を均等割
  • デフォルトインストールされたフォント名を取得するAppleScript
  • macOS 15 リモートApple Eventsにバグ?
  • AppleScript入門① AppleScriptってなんだろう?
  • macOS 14で変更になったOSバージョン取得APIの返り値
  • Keynoteで2階層のスライドのタイトルをまとめてテキスト化

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (212) 13.0savvy (194) 14.0savvy (147) 15.0savvy (132) CotEditor (66) Finder (51) iTunes (19) Keynote (117) 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) 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
  • 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年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