Classic Mac OSの頃は「しかたなく」クリップボードを使って行う処理がありましたが、最近(Mac OS X移行後)では極力使わないようにしています。文字コード変換、スタイル付きテキストのプレーンテキスト化などクリップボードを経由しないとできない処理がたくさんありました。画像の形式変換ですらクリップボードを経由して処理していた記憶があります。
クリップボードにデータを入れる「set the clipboad」、クリップボードからデータを取り出す「the clipboard」、クリップボードの情報を取得する「clioboard info」などがあります。スピードも遅くないのですが、本コマンドでクリップボード内容を捕捉できるまでに(クリップボードの内容が反映されるまでに)若干時間がかかります。
–Created 2015-08-03 by Shane Stanley use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "AppKit" — for NSPasteboard
my restoreClipboard:{"ABC"}
–クリップボードに内容を設定する on restoreClipboard:theArray — get pasteboard set thePasteboard to current application’s NSPasteboard’s generalPasteboard()
— clear it, then write new contents thePasteboard’s clearContents() thePasteboard’s writeObjects:theArray end restoreClipboard:
make new document activate end tell
–Main Loop repeat set leftF to my checkModifier:"control" set rightF to my checkModifier:"shift" set upF to my checkModifier:"option" set downF to my checkModifier:"command"
set quitF to my checkModifier:"caps"
if quitF = true then return
if leftF = true then if curPosX > 1 then set curPosX to curPosX – 1 end if else if rightF = true then if curPosX ≤ curMax then set curPosX to curPosX + 1 end if end if
if upF = true then if curPosY > 1 then set curPosY to curPosY – 1 end if else if downF = true then if curPosY < curMax then set curPosY to curPosY + 1 end if end if
–make display text set aText to "" repeat with i from 1 to curMax + 1 if i = curPosX then set aText to aText & "🛑" else set aText to aText & "㍳" end if end repeat
set bText to "" repeat with y from 1 to curMax if y = curPosY then set bText to bText & rText & return else set bText to bText & aText & return end if end repeat
my displayText(bText)
end repeat
–テキスト画面描画 on displayText(aText) tell application "CotEditor" tell front document set contents to aText end tell end tell end displayText
–複数同時検出に対応 on checkModifier:keyName if keyName = "option" then set theMask to current application’s NSAlternateKeyMask as integer else if keyName = "control" then set theMask to current application’s NSControlKeyMask as integer else if keyName = "command" then set theMask to current application’s NSCommandKeyMask as integer else if keyName = "shift" then set theMask to current application’s NSShiftKeyMask as integer else if keyName = "caps" then set theMask to current application’s NSEventModifierFlagCapsLock as integer else if keyName = "num" then set theMask to current application’s NSEventModifierFlagNumericPad as integer else if keyName = "help" then set theMask to current application’s NSEventModifierFlagHelp as integer else if keyName = "fn" then set theMask to current application’s NSEventModifierFlagFunction as integer else return false end if
set theFlag to current application’s NSEvent’s modifierFlags() as integer if ((theFlag div theMask) mod 2) = 0 then return false else return true end if end checkModifier:
— Created 2020-09-27 by Takaaki Naganoya — 2020 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation"
–指定文字列の前後に存在するスペースと、文字列本体中に存在する2個以上の連続するスペースを削除して返す set a0Str to " First model, with mechanical scroll wheel. 10 GB model released later ." set aRes to removeWhiteSpaceRepeatation(a0Str, " ") of me –> "First model, with mechanical scroll wheel. 10 GB model released later ."
–クリーニング対象文字(たぶんスペース)が処理対象文字列の前後にあったり、途中に2つ以上連続して存在している場合には削除 on removeWhiteSpaceRepeatation(a0Str as string, aChar as string) if length of aChar is not equal to 1 then return false
set a1Str to trimFromHeadAndTail(a0Str, aChar) of me –> "First model, with mechanical scroll wheel. 10 GB model released later ."
set sucList to detectSuccsessionOfSpace(a1Str, aChar) of me –> {{43, 53}, {80, 108}}
if sucList = {} then return a1Str
set allRes to removeRepeatedSpaceChar(a1Str, sucList)
return allRes end removeWhiteSpaceRepeatation
–同一文字(スペース)の連続出現リスト({{start pos 1, end pos 1}, {start pos 2, end pos 2}……})をもとにテキストを切り抜く on removeRepeatedSpaceChar(a1Str as string, sucList as list) set aList to characters of a1Str
set aLen to length of aList set outStr to "" set aCount to 1 copy contents of item aCount of sucList to {sItem, eItem}
repeat with i in sucList copy i to {tmpS, tmpE} if aCount = tmpS then –Skip copy tmpE to aCount else set tmpStr to text (aCount) thru tmpS of a1Str set outStr to outStr & tmpStr copy tmpE to aCount end if end repeat
if tmpE < aLen then set tmpStr to text (tmpE + 1) thru -1 of a1Str set outStr to outStr & tmpStr end if
return outStr end removeRepeatedSpaceChar
–対象文字列で、2個以上同一文字(スペースを想定)が連続して存在する場合には削除する on detectSuccsessionOfSpace(a1Str as string, sucTargChar as string) set aList to characters of a1Str set aLen to length of aList set newList to {}
set tmpS to 0 set tmpE to 0 set spcF to false –false:spaceではない。true:spaceをみつけた set spcCount to 0
repeat with i from 1 to aLen set j to contents of item i of aList
if j = sucTargChar then –Space 1 char (must be a char)
if spcF = true then –スペースが連続している最中 set spcCount to spcCount + 1 else –スペースの連続部分(?)の先頭をフェッチした状態 set spcF to true set spcCount to 1 copy i to tmpS end if
else –連続スペースの末端部分 if spcF = true then copy i to tmpE if spcCount > 1 then set the end of newList to {tmpS, tmpE – 1} end if set spcCount to 0 set spcF to false else –何もしない end if end if
end repeat
return newList end detectSuccsessionOfSpace
–文字列の先頭と末尾から連続するスペースを検索して削除する on trimFromHeadAndTail(aStr as string, trimChar as string) set aLen to length of aStr set aList to characters of aStr
–Find not target character from head to tail set aCount to 1 repeat with i in aList set j to contents of i if j is not equal to trimChar then exit repeat end if set aCount to aCount + 1 end repeat
if aLen ≤ aCount then return ""
–Find not target character from tail to head set bCount to 1 repeat with ii in (reverse of aList) set jj to contents of ii if jj is not equal to trimChar then exit repeat end if set bCount to bCount + 1 end repeat
set resStr to text aCount thru (aLen – bCount + 1) of aStr return resStr end trimFromHeadAndTail
–Written By Philip Aker –文字置換ルーチン on repChar(origText as string, targStr as string, repStr as string) set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr} set temp to text items of origText set AppleScript’s text item delimiters to repStr set res to temp as text set AppleScript’s text item delimiters to txdl return res end repChar
on dispDiff(aStr, bStr, aSize) using terms from scripting additions set mePath to path to me set resPath to (mePath as string) & "Contents:Resources:index.html" set myStr to (read (resPath as alias) as «class utf8») as string end using terms from
set aString to current application’s NSString’s stringWithFormat_(myStr, aStr, bStr) as string set paramObj to {myMessage:"Browse diff", mySubMessage:"This is an mergely test", htmlStr:aString, viewSize:aSize}
webD’s displayWebDialog(paramObj) end dispDiff end script
–Works with Keynote v10.2 or later set aTagFile to ((path to desktop) as string) & "testOut.m4v"
tell application "Keynote" set exOpt to {compression factor:1.0, movie format:native size, class:export options} –set exOpt to {compression factor:1.0, movie format:native size, movie codec:h.264, class:export options}–this cause error export document 1 to file aTagFile as QuickTime movie with properties exOpt
個人的には信頼度の問題からmacOS 10.15は「パス」なので、macOS 11.0 Big SurがRelease時にコケないことを祈るのみです(メールが消えるとかいう話が一番OSの信頼度を下げる)。macOS 10.13, “Vista”という史上最悪・最低の大失敗をやらかして以来、「Release版のOSがBetaよりも低品質」という昨今のmacOS。10.13もBetaの時にはよかったのに、Release版で大崩壊を起こして見るも無残な姿に成り果てました。10.14もBetaの段階でGUI Scriptingの認証系でひどいバグがあって、「とても使えない」と判断。10.14.6まで待ってようやく手を出す気になったほど。
macOS 11.0, Big SurはBeta段階でも珍しく好印象で(GUIまわりの仕様はコロコロ変わるけど)、macOS 10.15みたいにBeta段階で「もう、これはダメ!」という話も聞きません(Relase時に紹介記事を書かなかったOSは10.15がはじめてです。10.15の崩壊度はひどかった)。macOS 11.0, Big Surには、macOS 10.13のような「Release版の大崩壊」を起こしてほしくないものです。
— Created 2016-03-12 by Takaaki Naganoya — Modified 2019-02-27 by Takaaki Naganoya — Modified 2020–09-21 by Takaaki Naganoya — 2020 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "AppKit" use framework "SFPSDWriter" –https://github.com/shinyfrog/SFPSDWriter
property |NSURL| : a reference to current application’s |NSURL| property NSString : a reference to current application’s NSString property NSUUID : a reference to current application’s NSUUID property NSImage : a reference to current application’s NSImage property SFPSDWriter : a reference to current application’s SFPSDWriter property NSWorkspace : a reference to current application’s NSWorkspace
property SFPSDResolutionUnitPPI : 1 property SFPSDResolutionUnitPPC : 2
set anWriter to (SFPSDWriter’s alloc()’s initWithDocumentSize:(current application’s CGSizeMake(1200, 400)) andResolution:72.0 andResolutionUnit:(SFPSDResolutionUnitPPI))
set aCount to 1
repeat with yPos from 0 to 400 by 110 repeat with xPos from 0 to 1024 by 110 set aImage to (current application’s NSImage’s alloc()’s initWithSize:{100, 100}) set aColor to current application’s NSColor’s redColor() my drawCircleOnNSIMage(aImage, 100, 0, 0, aColor)
(anWriter’s addLayerWithNSImage:aImage andName:("Layer_" & aCount as string) andOpacity:1.0 andOffset:{x:(xPos as real), y:(yPos as real)}) set aCount to aCount + 1 end repeat end repeat
set aPSD to anWriter’s createPSDData()
set theName to NSUUID’s UUID()’s UUIDString() set pathString to NSString’s stringWithString:("~/Desktop/output_" & theName & ".psd") set newPath to pathString’s stringByExpandingTildeInPath()
aPSD’s writeToFile:newPath atomically:true
# MARK: Call By Reference on drawCircleOnNSIMage(aImage, aRadius, aXpos, aYpos, aColor) set aBezier to generateCircle(aRadius, aXpos, aYpos) of me (aImage)’s lockFocus() aColor’s |set|() aBezier’s fill() –ぬりつぶし (aImage)’s unlockFocus() end drawCircleOnNSIMage
# MARK: circleのBezier曲線を作成して返す on generateCircle(theRadius, x, y) set aRect to current application’s NSMakeRect(x, y, theRadius, theRadius) set aCirCle to current application’s NSBezierPath’s bezierPath() aCirCle’s appendBezierPathWithOvalInRect:aRect return aCirCle end generateCircle
指定アプリケーションのAppleScript用語辞書(sdef)をHTMLに書き出すツール「AS Dictionary」は有用なツールです。もともと、hasがScriptingのための独自機構「objc-appscript」を作ったときの補助ツールでしたが、そのobjc-appscriptそのものは見るべきものがありませんでした(OS X 10.7あたりのOS側の構造改変で動かなくなってプロジェクト終了)。
Mac App StoreではBeta版のXcodeからのバイナリ提出を認めていないため、Universal Binary版のAppleScriptアプリケーションをMac App Storeに提出するためには、このXcode 12.2正式版のリリースを待つ必要があることでしょう。
現時点で先行して、macOS 11.0 Big Sur対応をIntel Mac向けのみで(ARMバイナリなしで)行うことは不可能ではありませんが、あまり意味がないことでしょう。まだRelease前ということもあって、Betaごとに仕様が変わってきています。とくにGUIまわりで。細かなバグもBetaごとに異なるものが見られます。
さて、コンテストに話を戻します。Pixelmator Pro v1.8の試用版を使うことで、同アプリケーションのScriptを書いて試せるとのこと(やっています)。辞書内容は事前に確認していましたが、ツッコミどころがあまりないぐらい、さまざまな機能が載っていました。「え、こんな機能まで乗せてるの?」という謎の充実度を見せており(Pixelmator Pro本体に搭載されていないQRコードの検出機能とか)、AS機能の開発に元AppleのSal Soghoianが協力したという話もうなづけます。
……巨大Scriptで一部のScripterがコンテストを蹂躙することを避けつつ、「このあたり、穴場だよね?」という箇所を埋めてあります。あっと驚く参加者(たぶん、最年少参加者)が優勝をもぎ取って、真の実力者(Edama2さんみたいな)が投稿したScriptが全力でスルーされつつPixelmator Pro Scriptingの肥やしになりそうな、よく考えられたレギュレーションです(コンテストってそういうもんなんで)。
tell front document set allNum to count every slide if allNum < 2 then return –slideの枚数が少なかった場合に処理終了
set curSlide to current slide if allNum = curSlide then return –current slideが末尾だった場合処理終了
set sNum to slide number of curSlide set nextSlide to slide (sNum + 1)
–最初のページ(スライド)からオブジェクトを収集 tell current slide set curObj1 to every image set curObj2 to every group set curObjList to curObj1 & curObj2 if curObjList = {} then return end tell
–次のページ(スライド)からオブジェクトを収集 tell nextSlide set nextObj1 to every image set nextObj2 to every group set nextObjList to nextObj1 & nextObj2 if nextObjList = {} then return end tell
set nexObjRes to calcOverlappedObj(curObjList, nextObjList) of me repeat with i in nexObjRes copy i to {origID, targID} set aOrigObj to contents of item origID of curObjList set aTargObj to contents of item origID of nextObjList set origPos to position of aOrigObj set position of aTargObj to origPos end repeat
set current slide to slide sNum end tell end tell
–与えられた2つのリストに入っているKeynoteオブジェクトの矩形座標が重なっているものをIDペアで出力する –同時に複数のオブジェクトが重なっていないことが前提 on calcOverlappedObj(objList1, objList2) tell application "Keynote" –最初のページのオブジェクトからオブジェクトIDとNSRectからなるリストを作成 set objRecList1 to {} set aCount to 1 repeat with i in objList1 if contents of i is not equal to {} then set {x1, y1} to position of i set aRect to {origin:{x:x1, y:y1}, |size|:{|width|:(width of i), |height|:(height of i)}}
set the end of objRecList1 to {objID:aCount, rect:aRect} end if set aCount to aCount + 1 end repeat
–次のページのオブジェクトからオブジェクトIDとNSRectからなるリストを作成 set objRecList2 to {} set aCount to 1 repeat with i in objList2 if contents of i is not equal to {} then set {x1, y1} to position of i set aRect to {origin:{x:x1, y:y1}, |size|:{|width|:(width of i), |height|:(height of i)}}
set the end of objRecList2 to {objID:aCount, rect:aRect} end if set aCount to aCount + 1 end repeat
–最初のページのオブジェクトと次のページのオブジェクトで矩形エリアが重なっているオブジェクトを抽出してそれぞれのIDをペアにしたリストを作成 set matchList to {} repeat with i in objRecList1
set origRect to rect of i set origID to objID of i
repeat with ii in objRecList2
set targRect to rect of ii set targID to objID of ii set tRes to detectRectanglesCollision(origRect, targRect) of me
if tRes = true then set the end of matchList to {origID, targID} end if end repeat
end repeat
return matchList end tell end calcOverlappedObj
–NSRect同士の衝突判定 on detectRectanglesCollision(aRect, bRect) set a1Res to (current application’s NSIntersectionRect(aRect, bRect)) as {record, list} set tmpClass to class of a1Res
if tmpClass = record then –macOS 10.10, 10.11, 10.12 return not (a1Res = {origin:{x:0.0, y:0.0}, |size|:{width:0.0, height:0.0}}) else if tmpClass = list then –macOS 10.13 or later return not (a1Res = {{0.0, 0.0}, {0.0, 0.0}}) end if end detectRectanglesCollision