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

月: 2020年5月

Keynoteで選択中のスライドのタイトルを取得して改行区切りテキストに変換

Posted on 5月 8, 2020 by Takaaki Naganoya

Keynoteのselectionを利用して、複数選択中のスライドを取得した処理を書いてみました。

ウィンドウ左側でアウトライン表示されているスライド一覧で複数選択しているものを、順次タイトルを取得して改行コードをはさんで連結したテキスト化してクリップボードに内容を転送します。内容をテキストエディタに転送して加工するために作ったものです。

Keynote用のScriptは必要に迫られて書くことが多く、本Scriptも実際に必要に迫られて書いています。ほぼ書き捨てレベルの内容でもあり、各スライドからタイトルが取得できない(タイトルが存在しない)場合には対処していません。

マスタースライドの名称を取得してタイトルオブジェクトの有無を判定するとか、各スライド上のタイトルオブジェクトにエラートラップを仕掛けつつアクセスする(存在しない場合にはエラー発生するもトラップを仕掛けてあるので処理が中断しない)、とかいった実戦レベルのScriptも(別途)書いておきたいところです。

selectionが返してくるスライド(ページ)のリストは、GUI上で後ろ(スライド番号の大きい方)から連続選択しても、前(スライド番号の小さい)のほうから連続選択しても、結果は変わりませんでした。スライド番号が小さい方から大きい方へとソートされた状態で取得されます。

AppleScript名:選択中のスライドのタイトルを取得して改行区切りテキストに変換
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/08
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set tList to {}

tell application "Keynote"
  tell front document
    set aSel to selection
    
set aLen to length of aSel
    
if aLen < 2 then return
    
    
repeat with i in aSel
      tell i
        tell default title item
          set aTitleStr to object text
        end tell
        
        
set the end of tList to aTitleStr
      end tell
    end repeat
  end tell
end tell

set aStr to retArrowText(tList, return) of me
set the clipboard to aStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

★Click Here to Open This Script 

Posted in list | Tagged Keynote | Leave a comment

手軽な初心者向け同人誌?「アップルスクリプト Basic Magazine」

Posted on 5月 7, 2020 by Takaaki Naganoya

他団体の作品の紹介です。以前から、コミケでそういう本を売っているサークルがあるという情報は掴んでいたのですが、さすがに同人誌即売会に足を運ぶほどの元気はないので(並ぶのと暑いのと寒いのが無理)、存在が確認できていなかった「アップルスクリプト Basic Magazine」。サークル名「Empty Party」、作者=かのつ、イラスト=かじわとクレジットされています。

作者への連絡手段が販売サイトに用意されておらず、サークルのWebサイトやTwitterアカウントなども見当たらないため、作者本人が販売しているかといった確認は取れていません(販売サイトがサイトだけに、ちょっと、、、まあ、多分大丈夫だとは思うのですが、、、)。

「アップルスクリプト Basic Magazine」vol.1/vol.2ともに550円でオンライン販売されています。ファイル形式はPDFで、Vol.1がページ数不明、Vol.2が25ページとなっているようです。

Vol.1ではXcode上で時計アプリケーションを作る内容を紹介。Vol.2ではPhotoshopを操作する方法を紹介しているようです。

Piyomaru Softwareでも「マンガとかイラスト形式の初心者向け本」という企画を出しては、立ち消えになりました。そういうものの必要性はあるものの、技術的にイラストを描けず作れないことから企画がオクラ入りを繰り返すこと数度。そういうのを作るのは無理なので、作れる中でどういう選択肢があるかを考えた末に苦労してAppleScriptえほんシリーズを作ったという経緯があります。

Posted in news | 2 Comments

アラートダイアログ上にWebViewでGoogle Chartsを表示(Calendar Chart)

Posted on 5月 7, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを配置し、Google Chartsを用いてCalendar Chartを表示するAppleScriptです。

自分の開発環境(MacBook Pro Retina 2012, Core i7 2.6GHz)で100日間のアクセス履歴を処理して7秒強ぐらいで描画が終了します。

調子に乗って300日分のアクセス履歴を処理したところ、表示まで1分ほどかかりました。あまり長い期間の描画を行わせるのは(このプログラムの書き方だと)向いていないと感じます。いまのところテストしただけで実用性は考えていませんが、この程度のグラフなら自前でNSImage上にボックスを描画して表示しても大した手間にはならないでしょう。


▲スクリプトエディタ上で実行したところ


▲Script Debugger上で実行したところ


▲スクリプトメニュー上で実行したところ

Safariのアクセス履歴は例によってsqliteのDatabaseにアクセスして取得していますが、AppleScriptのランタイム環境によっては、アクセス権限がないというメッセージが出てアクセスできないことがあります。ASObjC Explorer 4上では実行できませんでしたし、Switch Control上でも実行できません。

# 管理者権限つきで実行しても(with administrator privileges)実行できません → Switch Controlでも実行できるようになりました

最初に掲載したバージョンでは、グラフ化したときに表示月が1か月ズレるという問題がありました。

Google Chartsのドキュメントを確認したところ、

Note: JavaScript counts months starting at zero: January is 0, February is 1, and December is 11. If your calendar chart seems off by a month, this is why.

JavaScriptでMonthはJanuaryが0らしく、monthを-1する必要があるとdocumentに書かれていました。うわ、なにその仕様?(ーー;;;

AppleScript名:アラートダイアログ上にWebViewでGoogle Chartを表示(Calendar Charts)v1a.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/07
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0

script spd
  property aRes : {}
  
property bRes : {}
end script

–Calculate Safari access frequency for (parameter days)
set (aRes of spd) to calcMain(100) of safariHistLib

set (bRes of spd) to ""
repeat with i in (aRes of spd)
  set {item1, item2, item3} to parseByDelim(theName of (contents of i), "-") of me
  
set newLine to " [ new Date(" & (item1 as string) & ", " & ((item2 – 1) as string) & ", " & (item3 as string) & "), " & (numberOfTimes of i) & "]," & (string id 10)
  
set (bRes of spd) to (bRes of spd) & newLine
end repeat

set (bRes of spd) to text 1 thru -3 of (bRes of spd)

–Pie Chart Template HTML
set myStr to "<!DOCTYPE html>
<html lang=\"UTF-8\">
<head>
<div id=\"calendarchart\"></div>

<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>

<script type=\"text/javascript\">
// Load google charts
google.charts.load(’current’, {’packages’:[’calendar’]});
google.charts.setOnLoadCallback(drawChart);

// Draw the chart and set the chart values
function drawChart() {
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: ’date’, id: ’Date’ });
dataTable.addColumn({ type: ’number’, id: ’Web Access’ });
dataTable.addRows([
  %@
]);

var chart = new google.visualization.Calendar(document.getElementById(’calendar_basic’));

var options = {
title: \"Web Activity\",
height: 350,
};

chart.draw(dataTable, options);
}
</script>
</head>
<body>
  <div id=\"calendar_basic\" style=\"width: 1000px; height: 350px;\"></div>
</body>
</html>"

set aString to current application’s NSString’s stringWithFormat_(myStr, (bRes of spd)) as string

set paramObj to {myMessage:"Calendar Chart Test", mySubMessage:"This is a simple calendar chart using google charts", htmlStr:aString}
–my browseStrWebContents:paramObj–for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 1000
  
set aHeight to 300
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script type=\"text/javascript\">", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight – 100)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
  
set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— 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:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

script safariHistLib
  property parent : AppleScript
  
use scripting additions
  
use framework "Foundation"
  
  
property |NSURL| : a reference to current application’s |NSURL|
  
  
script spd
    property sList : {}
    
property nList : {}
    
property sRes : {}
    
property dRes1 : {}
    
property dRes2 : {}
  end script
  
  
  
on calcMain(daysNum)
    set (dRes1 of spd) to dumpSafariHistoryFromDaysBefore(daysNum) of me
    
    
set (dRes2 of spd) to {}
    
repeat with i in (dRes1 of spd)
      copy (first item of i) as string to dStr
      
set convDstr to first item of (parseByDelim(dStr, {" "}) of me)
      
set the end of (dRes2 of spd) to convDstr
    end repeat
    
    
–日付ごとに登場頻度集計
    
set cRes to countItemsByItsAppearance2((dRes2 of spd)) of me
    
return cRes as list
  end calcMain
  
  
  
–NSArrayに入れたレコードを、指定の属性ラベルの値でソート
  
on sortRecListByLabel(aArray, aLabelStr as string, ascendF as boolean)
    –ソート
    
set sortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF
    
set sortDescArray to current application’s NSArray’s arrayWithObjects:sortDesc
    
set sortedArray to aArray’s sortedArrayUsingDescriptors:sortDescArray
    
    
–NSArrayからListに型変換して返す
    
set bList to (sortedArray) as list
    
return bList
  end sortRecListByLabel
  
  
  
on dumpSafariHistoryFromDaysBefore(daysBefore)
    –現在日時のn日前を求める
    
using terms from scripting additions
      set origDate to (current date) – (daysBefore * days)
    end using terms from
    
    
set dStr to convDateObjToStrWithFormat(origDate, "yyyy-MM-dd hh:mm:ss") of me
    
    
set aDBpath to "~/Library/Safari/History.db"
    
set pathString to current application’s NSString’s stringWithString:aDBpath
    
set newPath to pathString’s stringByExpandingTildeInPath()
    
    
set aText to "/usr/bin/sqlite3 " & newPath & " ’SELECT datetime(history_visits.visit_time+978307200, \"unixepoch\", \"localtime\"), history_visits.title || \" @ \" || substr(history_items.URL,1,max(length(history_items.URL)*(instr(history_items.URL,\" & \")=0),instr(history_items.URL,\" & \"))) as Info FROM history_visits INNER JOIN history_items ON history_items.id = history_visits.history_item where history_visits.visit_time>(julianday(\"" & dStr & "\")*86400-211845068000) ORDER BY visit_time ASC LIMIT 999999;’"
    
    
using terms from scripting additions
      set (sRes of spd) to do shell script aText
    end using terms from
    
    
set (sList of spd) to (paragraphs of (sRes of spd))
    
    
repeat with i in (sList of spd)
      set j to contents of i
      
      
–Parse each field
      
set j2 to parseByDelim(j, {"|", "@ "}) of me
      
      
set the end of (nList of spd) to j2
    end repeat
    
    
return (nList of spd)
  end dumpSafariHistoryFromDaysBefore
  
  
  
  
on parseByDelim(aData, aDelim)
    set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to aDelim
    
set dList to text items of aData
    
set AppleScript’s text item delimiters to curDelim
    
return dList
  end parseByDelim
  
  
  
–出現回数で集計
  
on countItemsByItsAppearance2(aList)
    set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
    
set bArray to current application’s NSMutableArray’s array()
    
set theEnumerator to aSet’s objectEnumerator()
    
    
repeat
      set aValue to theEnumerator’s nextObject()
      
if aValue is missing value then exit repeat
      
bArray’s addObject:(current application’s NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{"theName", "numberOfTimes"})
    end repeat
    
    
–出現回数(numberOfTimes)で降順ソート
    
set theDesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"theName" ascending:true
    
bArray’s sortUsingDescriptors:{theDesc}
    
    
return bArray
  end countItemsByItsAppearance2
  
  
  
on convDateObjToStrWithFormat(aDateO as date, aFormatStr as string)
    set aDF to current application’s NSDateFormatter’s alloc()’s init()
    
    
set aLoc to current application’s NSLocale’s currentLocale()
    
set aLocStr to (aLoc’s localeIdentifier()) as string
    
    
aDF’s setLocale:(current application’s NSLocale’s alloc()’s initWithLocaleIdentifier:aLocStr)
    
aDF’s setDateFormat:aFormatStr
    
set dRes to (aDF’s stringFromDate:aDateO) as string
    
return dRes
  end convDateObjToStrWithFormat
  
end script

★Click Here to Open This Script 

Posted in JavaScript shell script Sort | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding Safari WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

指定アプリケーションを指定言語環境で再起動 v3

Posted on 5月 6, 2020 by Takaaki Naganoya

指定アプリケーションを、現在のユーザーアカウントで指定可能な言語環境を指定して再起動するAppleScriptの改良版です。

初版では言語環境を選んでからアプリケーションを選んでいましたが、この順番を逆にしました。アプリケーションを選択し、そのバンドル内のローカライズ状況を調べ、一覧から選択して起動します。


▲最初にアプリケーションを選択


▲Keynoteのローカライズ言語一覧から対象言語コードを選択


▲アラビア語環境で起動させたKeynote


▲タイ語環境で起動させたKeynote


▲ロシア語環境で起動させたKeynote


▲中国語(簡体字)環境で起動させたKeynote

個人的には割と実用性が高いScriptです。

AppleScript名:指定アプリケーションの指定言語環境で再起動 v3.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/06
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSBundle : a reference to current application’s NSBundle
property NSWorkspace : a reference to current application’s NSWorkspace

set anApp to path to (choose application)

tell application "Finder"
  set aBundle to properties of anApp
  
set targID to id of aBundle –Get Bundle ID
end tell

set bRes to getLocalizationsFromBundleID(targID) of me
set cRes to my sort1DList:bRes ascOrder:true

set dRes to (choose from list cRes)
if dRes = missing value or dRes = false then return

set targLanguage to first item of dRes

set appPath to retPathFromBundleID(targID) of me

set sText to "open -n -a " & quoted form of appPath & " –args -AppleLanguages ’(\"" & targLanguage & "\")’"
do shell script sText

on getLocalizationsFromBundleID(aBundleID)
  set aRes to retPathFromBundleID(aBundleID) of me
  
if aRes = false then error "Wrong Bundle ID."
  
return getSpecifiedAppFilesLocalizationListWithDuplication(aRes) of me
end getLocalizationsFromBundleID

–指定アプリケーションファイルの、指定Localeにおけるローカライズ言語リストを求める。重複を許容
on getSpecifiedAppFilesLocalizationListWithDuplication(appPOSIXpath)
  set aURL to (|NSURL|’s fileURLWithPath:appPOSIXpath)
  
set aBundle to NSBundle’s bundleWithURL:aURL
  
set locList to aBundle’s localizations()
  
return locList as list
end getSpecifiedAppFilesLocalizationListWithDuplication

on retPathFromBundleID(aBundleID)
  set aURL to NSWorkspace’s sharedWorkspace()’s URLForApplicationWithBundleIdentifier:aBundleID
  
if aURL = missing value then return false –Error
  
return aURL’s |path|() as string
end retPathFromBundleID

–1D Listをsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DList:theList ascOrder:aBool
  set aDdesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"self" ascending:aBool selector:"localizedCaseInsensitiveCompare:"
  
set theArray to current application’s NSArray’s arrayWithArray:theList
  
return (theArray’s sortedArrayUsingDescriptors:{aDdesc}) as list
end sort1DList:ascOrder:

★Click Here to Open This Script 

Posted in Locale | Tagged 10.13savvy 10.14savvy 10.15savvy Finder NSBundle NSURL NSWorkspace | Leave a comment

Keynoteのselectionの使い方が判明

Posted on 5月 4, 2020 by Takaaki Naganoya

AppleScriptにおける「selection」という予約語は割と重要で、選択中のオブジェクトや選択中のテキストを特定したり、選択中のオブジェクトへの処理を行うといった、一歩踏み出した処理が行えます。

KeynoteのAppleScript用語辞書に「selection」が追加されたのは、2019年3月にリリースされたv9.0のこと。

「list of iWork item」を返してくると記載されていることから、スライド(ページ)上で選択中の各種iWork item(shapeとかimageとかtext itemなどの各種オブジェクト)の選択状態を取得できることが期待されたわけですが、実際に試してみるとAppleScript用語辞書のようにiWork itemsを取得できるわけではありませんでした(当時のガッカリ感が半端ない)。

ところが、些細なことからこのKeynoteのselectionが「何を」選択しているかを返すかが分かってきました。

この、ウィンドウ左側のアウトライン表示されている各スライド(ページ)。ここを複数選択した状態でselectionを実行すると、このスライドがlistで返ってくることがわかりました。

この動作を知らずに(KeynoteのAppleScriptの用語辞書を信用して)試すと、現在表示中のスライド(ページ)のオブジェクトがリストで返ってくるという動作になります。なので、このselectionは現在表示中のスライド(ページ)のオブジェクトを返す(超使えない)コマンドだと判断していました。

ウィンドウ内容の表示ポップアップから「Light Table」を選択すると、

各スライドのサムネールが一覧表示されますが、

ここで複数スライドを選択しても「selection」で選択状態を取得できるわけではないようです。

Keynoteに対するAppleScriptの処理で、スライド上の各種オブジェクトの位置やサイズを統一するようなものがありますが、そういう範囲で使うのであれば有効に使えるといったところでしょうか。

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

Early access program : ebook “Switch Control with AppleScript”

Posted on 5月 4, 2020 by Takaaki Naganoya


This is an early access program. This ebook is in progress, not finished. The early access reader can read it with agreement. The early access readers can make request to author during works (every request will be discussed, without 100% guarantee to be realized). 65 pages (today). Price: JPY 3,000.

This ebook “Switch Control with AppleScript” is a book about Switch Control. It is one of accessibility function for people with disabiulities. But it is very useful for every macOS users specially for the scripters.

Switch Control can launch AppleScript or run keyboard shortcut sequence. We can make button-based simple GUI for AppleScript. It is the easiest environent to make GUI.

This book will contain author’s sample Switch Control. It is useful and gives you a power of automation for macOS users.

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

Switch Controlがオンになっているか調べる

Posted on 5月 3, 2020 by Takaaki Naganoya

Switch Controlが起動中かどうかをNSWorkspace経由で調べるAppleScriptです。

いろいろなAppleScriptをSwitch Controlのパネルに盛り込んで利用していますが、けっこう使いでがあっていい感じです。Script MenuにAppleScriptを入れて呼び出すのも実用性が高くてよいのですが、Switch Controlのパネルに入れると常時フローティングパネルで表示される(消したり最小化も可)ため、アプリケーションの機能が不完全であると感じるところをユーザーが自分で勝手に補える感覚がとてもいい感じです。

ただ、1つ問題があるとすれば、Switch Controlをプログラム側から起動する方法が公開されていないようである点。本Scriptのように、起動中であることを判定する方法は提供されているのですが。

Switch Control(=AssistiveControl)がオンになっていると、InputManager側から見えるので

このあたりに解決の鍵がありそうな気もします。ただ、文字入力に介在できる機能でもあるため、セキュリティ上の懸念から「あえて」そうしたAPIを公開していないのかも。

現状では唯一、GUI Scriptingで野蛮にチェックボックスをクリックするか、あるいいはチェックボックスの値を変更するぐらいでしょう。実際に試してはいないので、これもできるか100%の保証があるものではありませんけれども。

AppleScript名:スイッチコントロールがオンになっているか調べる.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/02
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

current application’s NSWorkspace’s sharedWorkspace()’s isSwitchControlEnabled()
–> true / false

★Click Here to Open This Script 

Posted in System | Tagged 10.13savvy 10.14savvy 10.15savvy NSWorkspace Switch Control | Leave a comment

Kamenoko、Mac App Storeで販売開始

Posted on 5月 3, 2020 by Takaaki Naganoya

Mac App Storeでリジェクトをくらうこと3回。ようやくKamenokoがMac App Storeで販売開始になりました。本アプリケーションは、Piyomaru SoftwareがAppleScriptで開発し、Mac App Storeで販売したアプリケーションの2作品目になります。

# Mac App Storeからちゃんと買えることを確認しました。こういうの、1つ1つ確認しないと怖いです

1つやらかしたのは、検索キーワードにアプリケーション名を入れておかなかったので、アプリケーション名で検索できないという「お可愛らしい」ミス。

些細な機能のアップデートをリリースしてキーワードを追加しておくほかなさそうです。

# v1.1のリリース時にいろいろ宣伝を(人力で)行うことにします。このv1.1で安定性と速度が大幅に向上し(このあたりはプログラム以外の要素による)、簡易Undoや入力ダイアログの文字化け抑止など、完成度が大幅に増しています。Mac Pro 2019で計算間違いが起こる現象についても対処を行なっています(実機がないので検証は行えないんですけれども)

最初のバージョンなので、メニューなどは日本語ローカライズしていません。

また、中身がほぼ99.9%AppleScriptで書いてあるものの、

Scriptableではありません。このアプリケーションの特性からいって、アプリケーションの書類を操作(読み書き)できるAppleScriptライブラリをアプリケーションバンドル内に入れることで、アプリケーション自体をScriptableにしなくても書類を操作できてよいのではないかと考えています。

主要機能をコンテクストメニューから呼び出すので、ワンボタンマウスを使うと手も足も出ません。その点のみ要注意です。

本アプリケーションで苦労した点

もともと、この6角形の図形を使ってKeynote上でいろいろアイデアを練ったり説明のための図を作っていろいろ試してみたら「この図を作るアプリケーションは便利だし、自分でも作れそうだ」と思いついたのがきっかけです。


▲LGやPanasonicが出している透明有機ELディスプレイに表示させるとこんな感じに?(想像図)

ハリウッド映画に出てくるハリウッド的な未来風のインタフェースを実際に実装してみるとこんな感じになるだろうか、というコンセプトでデザインしています。


▲Panasonic様のショールームを訪問して、実機で表示してみたところ

透明ディスプレイでは、明暗差を大きく確保しないとオブジェクトの視認性が下がるとか、グラデーション表現を行うと視認性が下がるといった「仮説」を立て、なるべく一色でベタ塗りするように味付けしています。このあたりは、透明ディスプレイに合わせたチューニングです。グリーンバック表示機能も、どの程度使えるか不明ですが、黒色バック透過モードで使い勝手がよくなかった場合への備えでもあります(一説には、黒色バック透過が一番きれいに透過するもよう)。

濃い色を積極的に使っているのも、透明ディスプレイの透過モード時には全体的に白っぽく表示される傾向があるようなので、「白飛び」を避けることが目的です。

1月中旬ぐらいに作り始め、1月末には初期バージョンが動いていました。


▲初期バージョン


▲セルのダブルクリックで文字入力が可能に(2月中旬)


▲指定セル内キーワードのタクソノミー展開を実装(2月中旬)


▲ビューの拡大・縮小表示、コンテクストメニュー表示が可能に(2月末)


▲ブロック認識、ブロック削除が可能に(3月中旬)


▲AirDrop共有、データ埋め込みPNG書き出し(3月中旬)


▲テーマセレクタが完成(3月下旬)


▲大型文字入力ダイアログを追加(4月)

正直なところ、こんなストロングスタイルのGUIアプリケーションを作ろうと思ったことはなかったので、いろいろと未知の現象に直面しました。

一番真っ青になったのは、開発途上でド派手なメモリリークに直面したときです。たいていのAppleScriptアプリケーションは、まとまった処理を行うためのパラメータ選択をGUI画面上で行い、メイン処理が動いたらまとまった処理を行って終了という動き方をするものでした。つまり、GUIアプリケーションといいつつもメモリリークに苦しめられることが少なかったのです。

こんな風にユーザーと対話動作をたえず行い、結果をグラフィックとして画面に描画する(=メモリリークの危険性の高い)アプリケーションを作るのははじめてです。

まずは、些細な処理でWindow Serverのメモリを大量に消費してクラッシュするという現象に直面。開発初期にこの現象の対策が行えたことはラッキーでした(Edama2さんにはこの段階でいろいろ助言をいただきました)。

次に、プレビュー作成時にメモリリークを行う現象に直面。いくぶん緩和していますが、ここは解決できていません。クラッシュしても、作業中の内容を定期的に保存し、強制終了後の再起動時にデータをリカバリする機能を追加。クラッシュしにくくする方向の努力はしつつも、クラッシュしてもデータを失いにくい方向に機能強化しました。

環境設定まわりの機能はけっこう実装に苦労しています。実装が間に合わなかったので、仕様的には幾分日和りました。

そして、毎度毎度のことながらSandbox化には苦しみました。コード署名するのに、Mac App Installerの署名とMac App IDの署名があり、間違ってMac App Installerで署名したり。あとは、コマンドラインから起動するタイプのツールをアプリケーションバンドル内に同梱して呼び出していたのですが(display mirror)、コードサインで問題が出たので分離せずにアプリケーション内に組み込むように変更しました(リジェクトされている間に機能改変)。

本アプリケーションでプログラム的に一番苦労したのは、ブロック認識プログラムです。データ上の1つの塊をまとめて処理するのに、この独特のヘックス構造のコマのせいで、前例がないような独創的な処理をいろいろと書かなくてはなりませんでした。

作りたかったけどv1.0にはあきらめた機能 ほか

アルファテスターからの指摘もありましたが、Undoがないのはけっこう辛いです。結局、Undoの実装のためには内部データを改変のたびに時系列順に保存し、保存した最新-1の状態に戻すといった実装になると思います。この、無段階Undoを実装することは可能と思われましたが、割と大掛かりな機能になりそうな(1か月ぐらいかかりそう)気配がしたので初版では見送りました。

本アプリケーションはScriptableではありません。将来的には、書類の読み取りと変更を行う機能を持つScript Libraryを同梱する方向でAppleScript対応を考えています(たぶん、これが一番楽で実用的)。

キャンバスの回転機能は単体で動くものが出来上がっていますが、まだアプリケーションに組み込んで動作させるところまでは行っていません。

「2つのキーワードの共通要素をリストアップする」プログラムはこのKamenokoの部品用に作ったもので、単体ではそれなりに有用な部品ではあるものの、本アプリケーションにどのように組み込むかのいいアイデアが出ませんでした。データとして処理すると有用さがわかるものの、それをどのように可視化するかが課題です(多すぎるアイデアにつぶされない戦い)。

本アプリケーションには検索機能が実装されていません。検索系の部品として、類義語展開したうえで検索を行う「スタークエリー」という部品をAppleScriptで作ってあるので、組み込むとしたらこれだと(指定のキーワードだけでなく、類義語でもヒットする)思っているのですが、英語+日本語の類義語(シソーラス)辞書が200MBぐらいあるのとGUI的にどうやってヒット状況を表示するかのアイデアがなかったので実装を見送りました。あとから考えると200MBぐらい昨今のアプリケーションでは問題ではないレベルなので、悩む必要はなかったようです。

開発中はフォントメニューのキャッシュ機能を有効にしていましたが、リリース版ではこれをオフにしました。Kamenokoを起動していない間にフォントの変更(追加、削除)が行われたことを検出する方法が思いつかなかったので、フォントメニューのキャッシュが危険に思われたためです。フォントパネルを表示させてフォントを指定する方法も試してみたものの、あまりピンとこなかったので使いませんでした。

目下、メインScriptが3,000行を超えるぐらいのサイズで、全体では5,000行ぐらいは行っていると思います。メンテナンス性があまりよくないので、機能追加を行うためにはメイン部分のスリム化が必須な状況でしょう。

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

Post navigation

  • Newer posts

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

Google Search

Popular posts

  • macOS 13, Ventura(継続更新)
  • アラートダイアログ上にWebViewで3Dコンテンツを表示(WebGL+three.js)v3
  • Xcode 14.2でAppleScript App Templateを復活させる
  • macOS 13 TTS Voice環境に変更
  • UI Browserがgithub上でソース公開され、オープンソースに
  • 2022年に書いた価値あるAppleScript
  • ChatGPTで文章のベクトル化(Embedding)
  • 新発売:AppleScriptからSiriを呼び出そう!
  • iWork 12.2がリリースされた
  • 従来と異なるmacOS 13の性格?
  • 新発売:CotEditor Scripting Book with AppleScript
  • macOS 13対応アップデート:AppleScript実践的テクニック集(1)GUI Scripting
  • AS関連データの取り扱いを容易にする(はずの)privateDataTypeLib
  • macOS 13でNSNotFoundバグふたたび
  • macOS 12.5.1、11.6.8でFinderのselectionでスクリーンショット画像をopenできない問題
  • ChatGPTでchatに対する応答文を取得
  • 新発売:iWork Scripting Book with AppleScript
  • Finderの隠し命令openVirtualLocationが発見される
  • macOS 13.1アップデートでスクリプトエディタの挙動がようやくまともに
  • あのコン過去ログビューワー(暫定版)

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1390) 10.14savvy (586) 10.15savvy (434) 11.0savvy (277) 12.0savvy (185) 13.0savvy (57) CotEditor (60) Finder (47) iTunes (19) Keynote (98) NSAlert (60) NSArray (51) NSBezierPath (18) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (51) NSDictionary (27) NSFileManager (23) NSFont (18) NSImage (41) NSJSONSerialization (21) NSMutableArray (62) NSMutableDictionary (21) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (117) NSURL (97) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (56) Pages (37) Safari (41) Script Editor (20) WKUserContentController (21) WKUserScript (20) WKUserScriptInjectionTimeAtDocumentEnd (18) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • Clipboard
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • drive
  • 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
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • 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)
  • 未分類

アーカイブ

  • 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