SSブログ
AppleScript辞書はつくれるか? ブログトップ
前の10件 | 次の10件

XcodeのAppleScriptのテンプレートを使えるようにする [AppleScript辞書はつくれるか?]

以前にXcodeからAppleScriptのテンプレートが消えたことがあり、解決方法を探していたことがありましたが、自分なりに解決方法を探してなんとかしてたのですが、どうやったかまではブログでかいていませんでした。

まぁ、色々な人が解決方法を上げていますので、詳しくは書きませんが、古いXcode12以前のXcode内からテンプレートを探し、新しいXcodeのテンプレートフォルダ内にコピーをすると使えるようです。

ということで、以前に解決していたのですが、Mac本体やOSを新しくした時や、Xcodeのバージョンが変わるたびにAppleScriptのテンプレートを、いちいち探してコピーするのがめんどくさくなってきたので、テンプレートを探したり、コピー先を開いたりする動作を自動化してみたりするスクリプトを書いてみました。

さすがにアプリケーションフォルダ内にコピーすることまでは、セキュリティーの問題があるのでしませんでしたが、これでだいぶ楽になると思います。

 

Shellスクリプトを利用したら簡単ではないかと思って、まずは書いてみた。

 

do shell script "add=`system_profiler SPApplicationsDataType | grep 'Location:' | cut -d ':' -f2 | grep -e 'Xcode.app' -e 'Xcode-beta.app'| head -n 1 | cut -d ' ' -f2- ;` ; foo=`du -a $add/Contents/Developer/Library/Xcode/Templates/ | grep -e 'AppleScript App.xctemplate' | cut -d ' ' -f2- | sort | head -n 1 ;` ; cp -R \"$foo\" $HOME/Downloads/ ; echo $foo ;"

 

無理やり1行で収まるようにしてみましたが、ちゃんと探して見つかったテンプレートファイルをダウンロードフォルダにコピーするところまでやってます。

まぁ、乱暴な部分がありますので、見つからなかった場合など、不具合があればエラーを吐きますけどね。

 

それも含めてアップルスクリプトで書き直してみる。

 

 

(*全てのアプリケーション情報を取得*)

set systemProfilerList to do shell script "system_profiler SPApplicationsDataType ;" -- ここだけはShell使用

(*上で取得した中からXcode.appのアドレスを抽出*)

set addressList to {}

repeat with oneLine in (paragraphs of systemProfilerList)

set oneLine to oneLine as string

if oneLine contains "Location:" then

if (oneLine ends with "/Xcode.app") or (oneLine ends with "/Xcode-beta.app") then

set n to offset in oneLine of ":"

set add to text (n + 2) thru -1 of oneLine

set addressList to addressList & {add}

end if

end if

end repeat

if addressList = {} then return "Xcodeが見つけられませんでした。"

(*選択*)

set ans to choose from list addressList with prompt "対象となるXcodeを選択してください" OK button name "選択" cancel button name "中止"

if ans = false then return "中止しました"

(*テンプレートフォルダを開く*)

tell application "Finder"

set folderAdd to folder (((ans as string) & "/Contents/Developer/Library/Xcode/Templates/Project Templates") as POSIX file as string)

set itemList to every folder of folderAdd

repeat with aFolder in itemList

if (name of aFolder) contains "mac" then

activate

try

select folder "Other:AppleScript App.xctemplate" of aFolder

display dialog "テンプレートを選択しました" buttons "OK" default button 1

return "テンプレートを選択"

on error

select folder "Other" of aFolder -- 修正しました

display dialog "テンプレートフォルダを開きました" buttons "OK" default button 1

return "テンプレートフォルダ"

end try

end if

end repeat

end tell

display dialog "見つかりませんでした。" buttons "残念" default button 1

"End"

 (ミスがあり2023/3/28に修正しました)

Xcodeのテンプレートフォルダを探しAppleScriptのテンプレートがあれば選んで表示し、なければテンプレートフォルダを開きます。

image230327.jpg

1)古い(AppleScriptのテンプレートがある)Xcode.appを選び、テンプレートが表示されるので、それをどこか別な場所にコピーをしておく。

2)新しい(AppleScriptのテンプレートがある)Xcode.appを選び、開いたテンプレートフォルダに前のテンプレートを移動してくる。

これで使えるようになります。

 

もし、古いXcodeを持っていないのであれば下記からダウンロードできます。

 https://developer.apple.com/support/xcode/ 

  (AppleのDeveloperのサイトでAppleIDでのログインが必要となります)

 

image230327b.jpgimage230327c.jpg

nice!(0)  コメント(2) 
共通テーマ:パソコン・インターネット

ウインドウは端から端まで使いたい [AppleScript辞書はつくれるか?]

自作のアプリケーションでは、ウインドウの上部にタイトルバーがセットで表示されていると思います。

 

image230220a.jpg

 

このタイトルバーの部分を消して、端から端まで全部使いたい。と思ったことはありませんか?

それについてやり方をご紹介します。

 

(今回使用したコードの参考資料ページ)

・NSWindowStyleMask

   (https://applescript.web.fc2.com/reference2022/reference_NSWindowStyleMask.html)

 

1)タイトルバーの背景を消してみる

タイトルバーの背景を非表示にするというコードがある。

image230220b.jpg

上記のウインドウでは、ボタンが表示可能な領域の最上部に来るようにしてある。

 

 

tell theWindow

    setTitlebarAppearsTransparent_(true)

end tell

これを実行すると...

image230220c.jpg

ベースのウインドウの背景は、見やすいように濃いグレーにしてあるのですが、その背景が見えているだけで、オブジェクトがそこを使用していないのがわかる。

 

2)いっそのことウインドウからタイトルバーを完全に外してみる。

ウインドウスタイルから強制的にタイトルバーをなくす処理をしてみることにすると...

 

 

tell theWindow

    setStyleMask_(0)

end tell

これを実行すると...

image230220d.jpg

確かにバーはなくなり、一番上にボタンオブジェクトが来ているから成功か?

と思われるが、これは使わない方が良い。

というのも、実はタイトルバーの部分の分だけ狭くなっている上に、このウインドウを閉じるにはアプリケーションを終了する以外方法がなくなっている。

クローズボタンごと排除しているためだ。それでも良いというのであれば止めはしないが、お勧めはしない

 

3)タイトルバーの部分も表示領域として使えという命令で許可をする。

上の1)や2)のような無駄な話をあえてしましたが、ちゃんと使えるようになるコード(定数)があります。

 

 

    NSWindowStyleMaskFullSizeContentView

 

ウインドウのスタイルマスクにこの定数を送れば良いのですが、これを単独で送れば良いというわけではありません。

間違って送ると大変なことが起きます。

それは、スタイルマスクが他の部分も一緒に請け負っているため、それに配慮して他の情報も反映する必要があります。

 

ウインドウのスタイルマスクには、主に以下の情報が反映されています。

 

NSWindowStyleMaskTitled ・・・タイトルバー部分の表示

NSWindowStyleMaskClosable  ・・・タイトルバー部分のクローズボタンの有効化

NSWindowStyleMaskMiniaturizable ・・・タイトルバー部分の縮小化ボタンの有効化

NSWindowStyleMaskResizable ・・・タイトルバー部分のリサイズボタンの有効化

などがあります。

 

これをふまえ、

 

set aStyle to (current application's NSWindowStyleMaskTitled as integer)

set aStyle to aStyle + (current application's NSWindowStyleMaskClosable as integer)

set aStyle to aStyle + (current application's NSWindowStyleMaskMiniaturizable as integer)

set aStyle to aStyle + (current application's NSWindowStyleMaskResizable as integer)

set aStyle to aStyle + (current application's NSWindowStyleMaskFullSizeContentView as integer)

tell theWindow

    setStyleMask_(aStyle)

end tell

として、実行すると

image230220e.jpg

おっと、うまくいったのだけど、ボタンオブジェクトが、タイトルバーの後ろに隠れてしまったようだ。

タイトルバーの背景の非表示を追加で

 

tell theWindow

    setTitlebarAppearsTransparent_(true)

end tell

 

image230220f.jpg

 

おっと、ウインドウタイトルが表示されたままなので邪魔になっているじゃないか。

 

 

tell theWindow

    setTitleVisibility_(current application's NSWindowTitleHidden)

end tell

 

image230220g.jpg

これで完成です。

 

 

追記)ちなみに、クローズボタンの後ろにも配置ができるようになる。

image230220h.jpg


nice!(0)  コメント(0) 
共通テーマ:パソコン・インターネット

グラデーションを使ってみよう。 [AppleScript辞書はつくれるか?]

Apple Scriptでグラデーションを扱いたいと思い、基本的なやり方をまとめてみた。

 

(今回使用したコードの参考資料ページ)

NSImageView (https://applescript.web.fc2.com/reference2022/reference_NSImageView.html)

NSImage (https://applescript.web.fc2.com/reference2022/reference_NSImage.html)

NSGradient (https://applescript.web.fc2.com/reference2022/reference_NSGradient.html)

NSBezierPath (https://applescript.web.fc2.com/reference2022/reference_NSBezierPath.html)

 

グラデーション(1)長方形内に直線的なグラデーションを作成

 

-- |カレントアプリケーションの登録|

set myApp to current application

-- |イメージビュー(NSImageView)の設置|

set theRect to theWindow's contentView()'s frame() -- メインウインドウ(theWindow)の表示可能部分全面のサイズを取得

set imageView1 to myApp's class "NSImageView"'s alloc()'s initWithFrame:theRect --オブジェクトを作成

tell imageView1

setImageFrameStyle_(myApp's NSImageFrameNone) -- フレームの表示は無し

setImageAlignment_(myApp's NSImageAlignCenter) -- イメージをフレーム内の中心に表示

setImageScaling_(myApp's NSImageScaleNone) -- イメージの拡大縮小はしない

end tell

theWindow's contentView()'s addSubview:imageView1 -- theWindowに作ったイメージビューを貼り付け

-- |グラデーションを作成して表示|

set {x, y, w, h} to {0, 0, 500, 300}

set theSize to myApp's NSMakeSize(w, h)

set anImage to myApp's class "NSImage"'s alloc()'s initWithSize:theSize -- 画像(NSImage)を作成

anImage's lockFocus() -- 画像の編集を開始

set aColor1 to myApp's class "NSColor"'s yellowColor() -- aColor1を黄色として登録

set aColor2 to myApp's class "NSColor"'s redColor() -- aColor2を赤色として登録

set theGradient to myApp's class "NSGradient"'s alloc()'s initWithStartingColor:aColor1 endingColor:aColor2

--aColor1aColor2からグラデーションを作成

set theRect to myApp's NSMakeRect(x, y, w, h)

set aAngle to 0 -- 角度用(中心から真右が0度で、数字が増えると反時計回りに回転する)

theGradient's drawInRect:theRect angle:aAngle -- theRectの大きさの長方形に、aAngleの角度でグラデーションを描画

anImage's unlockFocus() -- 画像の編集を終了

--

imageView1's setImage:anImage --画像をイメージビューに表示させる

 

image230215a.jpg

 

 

グラデーション(2)イメージビューの中心に円形のグラデーションを作成

 ※ グラデーション(1)の黄色い地の部分のみを編集(以下同様)

 

anImage's lockFocus()

set startPoint to myApp's NSMakePoint(w / 2, h / 2) --1つ目の円の中心位置

set startRadius to 20 --1つ目の円の大きさ

set aColor1 to myApp's class "NSColor"'s yellowColor() --1つ目の円の色(黄色)

set endPoint to myApp's NSMakePoint(w / 2, h / 2) --2つ目の円の中心位置

set endRadius to 150 --2つ目の円の大きさ

set aColor2 to myApp's class "NSColor"'s redColor() --2つ目の円の色(赤色)

set theGradient to myApp's class "NSGradient"'s alloc()'s initWithStartingColor:aColor1 endingColor:aColor2

set aOptions to 0 --円の外のはみ出し設定(はみ出し無し)

theGradient's drawFromCenter:startPoint radius:startRadius toCenter:endPoint radius:endRadius options:aOptions

--円状のグラデーションを描画

anImage's unlockFocus()

 

image230215b.jpg

 

オプション:

 aOptionsNSGradientDrawsBeforeStartingLocation を設定すると一つ目の円の内側に一つ目の色が入り、

  NSGradientDrawsAfterEndingLocationを設定すると2つ目の円の外側に2つ目の色が入ります。

 

set aOptions to ((myApp's NSGradientDrawsBeforeStartingLocation) as integer) ¬ 

+ ((myApp's NSGradientDrawsAfterEndingLocation) as integer

 

image230215c.jpg

 

グラデーション(3)部分部分でグラデーションの色を変える

 

anImage's lockFocus()

set colorArray to {(myApp's class "NSColor"'s blueColor()), (myApp's class "NSColor"'s yellowColor()), (myApp's class "NSColor"'s redColor())} -- グラデーションで採用したい色のリスト化

set theGradient to myApp's class "NSGradient"'s alloc()'s initWithColors:colorArray

set theBezierPath to myApp's class "NSBezierPath"'s bezierPath()

set theRect to myApp's NSMakeRect(x, y, w, h)

theBezierPath's appendBezierPathWithRect:theRect

set aAngle to 0

theGradient's drawInBezierPath:theBezierPath angle:aAngle -- カラーリストを元にグラデーションの描画

anImage's unlockFocus()

 

image230216a.jpg

 

 

グラデーション(4)自由な図形の中にグラデーションを描く

 

anImage's lockFocus()

-- |雨だれの図形を作成|

set theBezierPath to myApp's class "NSBezierPath"'s bezierPath()

tell theBezierPath

-- 始まりの点

set aPoint to myApp's NSMakePoint(250, 300)

moveToPoint_(aPoint)

-- 直線

set aPoint to myApp's NSMakePoint(350, 150)

lineToPoint_(aPoint)

-- 曲線

set aPoint to myApp's NSMakePoint(150, 150)

set aControlPoint1 to myApp's NSMakePoint(350, 5)

set aControlPoint2 to myApp's NSMakePoint(150, 5)

curveToPoint_controlPoint1_controlPoint2_(aPoint, aControlPoint1, aControlPoint2)

-- 最初と最後の点を繋いで図形の線を閉じる

closePath()

end tell

-- |グラデーションで塗りつぶす|

set aColor1 to myApp's class "NSColor"'s whiteColor()

set aColor2 to myApp's class "NSColor"'s cyanColor()

set aAngle to 90

set theGradient to myApp's class "NSGradient"'s alloc()'s initWithStartingColor:aColor1 endingColor:aColor2

theGradient's drawInBezierPath:theBezierPath angle:aAngle

-- |枠の罫線を描く|

set strokeColor to myApp's class "NSColor"'s blueColor()

strokeColor's |set|()

theBezierPath's setLineWidth:2

theBezierPath's stroke()

anImage's unlockFocus()

 

image230216b.jpg

 

nice!(0)  コメント(0) 
共通テーマ:パソコン・インターネット

URLエンコード&デコードを簡単に [AppleScript辞書はつくれるか?]

image220823b.jpg

 

URLエンコード(%エンコード)を簡単にエンコードやデコードしたいと思い、いろいろ調べてみた。

なんと、それぞれ1行で作れるようだ。

 

Applescript

 

 

set inputText to "ユーリ・ガガーリンの名言「地球は青かった」"

set percentEncodeText to "%E3%81%98%E3%81%A4%E3%81%AF%E3%80%81%E5%9C%B0%E4%B8%8A%E3%81%AB%E3%81%84%E3%82%8B%E6%99%82%E3%81%AB%E8%80%83%E3%81%88%E3%82%89%E3%82%8C%E3%81%9F%E8%A8%80%E8%91%89%E3%81%A7%E3%81%82%E3%82%8B"

 

 

(* javascriptで%エンコード *)

set outputText1 to run script ("encodeURIComponent(\"" & inputText & "\")") in "Javascript"

log outputText1

 

(* shellデコード *)

set outputText2 to do shell script ("str='" & percentEncodeText & "' ; printf '%b\\n' \"${str//%/\\x}\" ;")

log outputText2

 

JavaScriptだったりShellスクリプトだったりと統一感がないが、簡単にするためだ、許してほしい。

 

参考サイト:

https://qiita.com/sa9ra4ma/items/358c936bc481a4c54866

https://inokara.hateblo.jp/entry/2020/12/06/090828

 
今回の記事を含めて『資料のページ』を作ってます。
 
 今回の記事についてコメントをいただきましたので、記事を追加させていただきました。 
 

(続きはここから)


nice!(0)  コメント(2) 
共通テーマ:パソコン・インターネット

入力ソースを切り替える(MacOS12.x版) [AppleScript辞書はつくれるか?]

image220823a.jpg

 

以前にも言語切り替えの入力メニューをApplescriptから操作するスクリプトを組んでいました。

 

『システムイベントを使って入力モードを変更する』 > https://start-mac.blog.ss-blog.jp/2019-03-27 

 

Mac OS 10.13では今でも使えているのですが、現在のMac OS 12.4では使えなくなっていましたので、新しいものを考えてみます。

 

 概要   

 MacOS 12.x環境で、Applescriptを使って入力ソースを『日本語』に変更したい

 

 Contents  

 1)ショートカットがあれば疑似入力でできるのでは?

 2)キーボードについている『かな』キーを擬似的に押した状態を作ったら?

 3)メニューを擬似クリックしてみる

 4)メニューを座標でクリック

 5)入力ソースをキーボードショートカットで変更する

 

1)ショートカット入力で切り替える  

仕方がないのでSystem Events経由でショートカットの疑似入力に変更しようかと思ったのですが、

公式サイトに書いてあるやり方

(https://support.apple.com/ja-jp/guide/japanese-input-method/jpimf6ffb247/6.3/mac/12.0)

『キーボード: Control+Shift+Jキー、またはOption+Shift+Zキーを押す』とあるのですが、なぜかこれでは動かなかった。

 

2)キーボードについている『かな』キーを擬似的に押した状態を作る  

キーの番号を調べれば使えるかもしれないが、ふと思いました。

キーボード配列が変わってしまったら使えなくなるのでは?

この方法では環境によっては誤動作の原因になる可能性があるのでボツ。

 

3)システムイベントでメニューのクリックしてみる  

どうやら"SystemUIServer"ではなく、"TextInputMenuAgent"にかわっているようだったので、変更した。

click menu bar item  を利用して直接に擬似クリックしてみる。

 

tell application "System Events"

tell process "TextInputMenuAgent"

click menu item "日本語" of menu 1 of menu bar item 1 of menu bar 2 --  

end tell

end tell

 

※ 右から menu bar 2(デスクトップ上部のメニュー右側) 

  menu bar item 1(メニューバー本体のアイテム) 

  menu 1(メニューバーの一つ目のメニューアイテムグループ(まぁ、一つしかないのだが...)) 

  menu item "日本語"(メニューアイテムの中の一つ) 

 となる。

 

結果は、動作しなかった。

どうやら、メニューアイテムグループを表示してからでないと反応しないらしい。

なので、追加してみた。

 

tell application "System Events"

tell process "TextInputMenuAgent"

click menu bar item 1 of menu bar 2

click menu item "日本語" of menu 1 of menu bar item 1 of menu bar 2

end tell

end tell

  

これで動作はしたのだが、何と動作が終わるまでに6秒もかかってしまった。(なぜ?)

 

4)座標でクリックしてみる  

クリックメニューバー命令が時間がかかるのか?と考え、座標を求めクリックしてみることにした。

 

tell application "System Events"

tell process "TextInputMenuAgent"

set {x, y} to position of menu bar item 1 of menu bar 2

click at {x + 8, 5}

set aList to every UI element of menu 1 of menu bar item 1 of menu bar 2

repeat with lineNo from 1 to (count of aList)

set obj to item lineNo of aList

set aName to (name of obj) as string

if aName = "日本語" then

set {x, y} to position of obj

click at {x + 50, y + 8}

exit repeat

end if

end repeat

end tell

end tell

  

これでも動作したのだが、やはり6秒もの時間がかかった。(残念!)

 メニューバーのアイコンをクリックした後に、瞬時にメニューは表示されているのだけれど、

そこで6秒間ほど動きがピタッと止まってしまう。(原因不明)

 

5)キーボードショートカットで入力ソースを切り替える方法でやってみる  

MacOS12.xではキーボードショートカット『control + スペース』で入力ソースの切り替えができる。

何だ、最初からこれでやればいいのでは? と思ったかもしれないが、じつはこのショートカットでは、切り替えた先の入力ソースが『日本語』なのか違うのかの判断ができないのです。

それを判断するためにTextInputMenuAgentのメニュー項目を読み込む必要があるのです。

入力ソースが『日本語』であるかどうかはメニューの中に日本語ソースに存在する「再変換」の項目があるかどうかで判断しています。

(中国語や韓国語など他のソースにあるかは調べていません。(すまん。)少なくとも英語には無い。)

 

tell application "System Events"

tell process "TextInputMenuAgent"

set aList to name of UI elements of menu 1 of menu bar item 1 of menu bar 2

if not ((aList as text) contains "再変換") then

key code 49 using control down

end if

end tell

end tell

   

日本語になっていなければ、key code 49 using control downを実行します。

この時、なぜkeystroke " " using control downの直接半角スペース文字を直接入力する方法を取らず、キーコードを使用したのかというと、キーストローク命令ではスペースはバグるので、使用しませんでした。(原因は不明)

※キーコードに関しては(サイト:https://eastmanreference.com/complete-list-of-applescript-key-codes)を参考にしました。

 

人によっては入力ソースが英語[ABC]と日本語ではない3つ以上の入力ソースがある人もいますが、それには対応していません。

メニューアイテムグループの内容が開かないと更新されないみたいで、それをしようとすると、魔の6秒間のフリーズが発生してしまうので、これは今後の課題とします。


nice!(0)  コメント(0) 
共通テーマ:パソコン・インターネット

スタートアッププログラムの情報を見る [AppleScript辞書はつくれるか?]

/Library/LaunchDaemons

~/Library/LaunchAgents

~/Library/LaunchDaemons

/System/Library/LaunchAgents

/System/Library/LaunchDaemons

にある、スタートアッププログラムを調べてリスト化してためのプログラムを作ってみました。

image1.jpg

ついでに、ダブルクリックで選択した項目の情報を表示したり、ファイルのある場所を開くこともできるようにもしてみました。

image3.jpg

ソースはこちら

 

ファイルを見つけることができるのですが、不用意にシステムで使っているファイルを消さないように注意してください。

 

 

(解決していました)


nice!(0)  コメント(0) 
共通テーマ:パソコン・インターネット

テキスト(String)を画像(NSImage)化する [AppleScript辞書はつくれるか?]

image220627a.jpg

簡単にテキストを画像化する方法は2つある。

・drawAtPoint

  決められたポイントから文字を書き出す

 

set aText to "Abcひら漢字"

set {{x, y}, {w, h}} to imageView1's frame()

 

set myApp to current application

set theSize to myApp's NSMakeSize(w, h)

--set fontObj to myApp's class "NSFont"'s userFontOfSize:24.0  --|Font A|

set fontObj to myApp's class "NSFont"'s fontWithName:"Osaka" |size|:24.0  --|Font B|

set sizeValue to fontObj as list

set fontAttribute to (myApp's NSFontAttributeName) as list

set attributes to myApp's class "NSDictionary"'s dictionaryWithObjects:sizeValue forKeys:fontAttribute

set aString to myApp's class "NSString"'s stringWithString:aText

set anImage to myApp's class "NSImage"'s alloc()'s initWithSize:theSize

anImage's lockFocus()

aString's drawAtPoint:(myApp's NSMakePoint(1, 1)) withAttributes:attributes

anImage's unlockFocus()

imageView1's setImage:anImage

 

・drawInRect

  決められた範囲内に文字を書き出す

 

set aText to "Abcひら漢字"

set setSize to 48

set myApp to current application

set {{x, y}, {w, h}} to imageView1's frame()

set theSize to myApp's NSMakeSize(w, h)

--set fontObj to myApp's class "NSFont"'s userFontOfSize:setSize  --|Font A|

set fontObj to myApp's class "NSFont"'s fontWithName:"Osaka" |size|:setSize  --|Font B|

set sizeValue to fontObj as list

set fontAttribute to (myApp's NSFontAttributeName) as list

set attributes to myApp's class "NSDictionary"'s dictionaryWithObjects:sizeValue forKeys:fontAttribute

set aString to myApp's class "NSString"'s stringWithString:aText

set {width:w, height:h} to aString's sizeWithAttributes:attributes  --|大きさを計測|

set anImage to myApp's class "NSImage"'s alloc()'s initWithSize:theSize

anImage's lockFocus()

aString's drawInRect:(myApp's NSMakeRect(1, 1, w, h)) withAttributes:attributes

anImage's unlockFocus()

imageView1's setImage:anImage

 

drawAtPointは範囲を気にしなくても書き出せるが、drawInRectは書き出す範囲を指示しなければいけない。

逆に言えば、drawAtPointでは結果がどこまで書き出しているかを把握できないが、drawInRectなら把握することができる。

 

どちらを使うかは、その時の状況によるのでしょう。

<今回の確認用ソースはこちら>


nice!(0)  コメント(0) 
共通テーマ:パソコン・インターネット

TabViewの研究 [AppleScript辞書はつくれるか?]

https://applescript.web.fc2.com/reference2022/reference_tabView.html

 

新しくTabViewを作る(TabViewItemが2つあるタイプ)

 

set theRect to current application's NSMakeRect(50, 70, 400, 320)

set tabView1 to current application's class "NSTabView"'s alloc()'s initWithFrame:theRect

theWindow's contentView()'s addSubview:tabView1

--

set tabViewItem1 to current application's class "NSTabViewItem"'s alloc's initWithIdentifier:"tab1"

tabViewItem1's setLabel:"タブ1"

tabView1's addTabViewItem:tabViewItem1

--

set tabViewItem2 to current application's class "NSTabViewItem"'s alloc's initWithIdentifier:"tab2"

tabViewItem2's setLabel:"タブ2"

tabView1's addTabViewItem:tabViewItem2

 

・通常タイプのTabView表示なら

 

tell tabView1

setTabViewType_(current application's NSTopTabsBezelBorder)

end tell

 NSTopTabsBezelBorder.jpg

TabViewタイプの"NSTopTabsBezelBorder"の部分を下記に変更すると

 

 

NSBottomTabsBezelBorder

NSBottomTabsBezelBorder.jpg

 (下に付く)

  

 

NSLeftTabsBezelBorder

NSLeftTabsBezelBorder.jpg

 (左に付く)

 

 

NSRightTabsBezelBorder

NSRightTabsBezelBorder.jpg

 (右に付く)

 

 

NSNoTabsBezelBorder

NSNoTabsBezelBorder.jpg

 (ベゼルな枠だけ残る)え?タブの意味はどこへいったの?

 

 

NSNoTabsLineBorder

NSNoTabsLineBorder.jpg

 (枠線だけ残る)ええぇ!?タブの意味...(省略)

 

 

NSNoTabsNoBorder

NSNoTabsNoBorder.jpg

 (枠線すら無い)はぁ?タブビューですら...(省略)

  

  

タブビューアイテムの追加(一番後ろ)

 

addTabViewItem_(theTabViewItem)

 

タブビューアイテムの挿入(0が一番前で、あとは数字ぶんのタブの後ろに挿入される) 

 

set aIndexNo to 1

insertTabViewItem_atIndex_(theTabViewItem, aIndexNo)

 

アイテムに該当するタブを削除

 

removeTabViewItem:theTabViewItem

 

指定番号のタブを削除(一番前は0)

 

set aIndexNo to 1

tabView1's removeTabViewItem:(tabView1's tabViewItemAtIndex:aIndexNo)

  (あれ?一度アイテムを呼び出さないといけない、この方法しかないのかなぁ?)

 

前のタブを選択

 

selectPreviousTabViewItem:me

 

次のタブを選択

 

selectNextTabViewItem:me

 

指定された番号のタブを選択

 

set aIndexNo to 1

selectTabViewItemAtIndex:aIndexNo

 

指定された識別子のタブを選択

 

selectTabViewItemWithIdentifier:"tab2"

 

選択されているタブのタイトル(label)を取得

 

set aTitle to ({} & ((tabView1's selectedTabViewItem())'s label())) as text

  変な方法で求めています。

 

選択されたタブのインデックス(番号)を取得

 

set aIndex to tabView1's indexOfTabViewItem:(tabView1's selectedTabViewItem())

 

タブの表示フォントを変更する

 

tabView1's setFont:(current application's class "NSFont"'s fontWithName:"HiraMinProN-W6" |size|:24.0)

   ちなみにフォント名はFont Book.appでフォントの情報から『PostScript名』を参考に

setFont.jpg

タブビューアイテムにオブジェクトを配置する(例はtextField1というオブジェクトを貼り付けている)

 

tabViewItem1's view()'s addSubview_(textField1)

   タブビューアイテムのビューの上に貼り付ける指示をしなければならない

 

などなど。

 

nice!(0)  コメント(0) 
共通テーマ:パソコン・インターネット

スクリーンセーバーの起動やスリープを阻止する [AppleScript辞書はつくれるか?]

自作のAppが起動している間だけ、スクリーンセーバーの起動をさせたくなかったり、スリープをさせないようにしたい場合があったとしたら、どうしたら良いのでしょう?

システム環境設定で動かないように設定したら、それで動かなくなりますが、自作のAppが起動している、していないにかかわらず、ずっとその状態になってします。

Appから環境設定を変更して、終了時には戻すというプログラムを組んだとしても、意図していない時にAppが強制終了してしまうと、元に戻らない場合が発生したりします。

つまり、Appに常に管理させておく必要があると思われます。

 

ではどのように管理をするかいくつか試してみよう。

 

image220610a.jpg

 

1)定期的にスクリーンセーバーの停止命令を送ってみたら?

 定期的に

 

on idle

tell application "System Events" to stop current screen saver

return 30

end idle

 という、スクリーンセーバーを停止するシステムイベントを送り続けてみる方法があります。

 しかし、これでは起動しているスクリーンセーバーを止めるだけなので、一度スクリーンセーバーが起動してしまいます。しかも、スクリーンセーバーの起動までの時間を延長させるものではないので、環境設定で入力されている時間がくれば毎回画面がちらつく事になります。

 

 さらに、スリープに関してはスルーなので、時間がくればコンピューターがスリープ状態に入ってしまうでしょう。

 

2)常にAppが演算状態にしたらどうか?

  これは意味がありません。Appが何かの演算を延々としていたとしても、スクリーンセーバーはお構いなしで動いてしまいます。もし演算状態でスクリーンセーバーが起動しないのであれば、バックグラウンドで動いている、システムのアプリケーションにも反応するはずなのですが、そんなことがないのは言うまでの無いことだと思います。

 

3)スクリーンセーバーが起動しない条件を探してみる。

スクリーンセーバーが起動しない状態とは、ユーザーが何かしらのキーボード作業やマウス作業をしている場合か、インターネットブラウザーや動画のプレーヤーで動画を見ている状態などが考えられます。

まぁ、延々と動画を流しておくというのは、今回適切では無いので省きます。

 

4)疑似的にキーボード入力をしている状態を作る。

・システムイベントで疑似的に入力をし続けてみた場合

 

tell application "System Events" to keystroke "a"

 Appで他にどんな作業をしているのかが不明な状態で、文字の入力を繰り返すのは、Appでさせている別の処理を阻害してしまう可能性があるので、これは無理があるでしょう。

 

・システムイベントで疑似的にシフトキーを押した状態にしてみた場合。

 

tell application "System Events" to keystroke using shift down

 シフトキーではスクリーンセーバーの起動を阻止はできませんでした。

 

5)マウスポインターを移動してみる。

・システムイベントで疑似的にクリックをさせる

 

tell application "System Events" to click at {100, 100}

 マウスポインターを移動させるものでは無く、そのポイントをクリックした場所の処理をさせるだけで、実際はマウスをクリックした動作をさせているわけでは無いようで、スクリーンセーバーの起動を阻止できなかった。

アップルメニューなどのメニューバーをクリックしておけばいけるかもしれないが、メニューが開いて画面がチラついてしまうので使えるとは思えない。

 

・Objective-Cの力を借りてポインターを移動してみる

 

tell current application

CGPostMouseEvent({x:mouseX, y:mouseY}, 1, 1, 0)

end tell

 

これで初めてスクリーンセーバーの起動を阻止することができました。

CGPostMouseEventを使うと、実際にマウスポインターが動きます。そしてシステムもマウスを動かした作業をしたと認識してくれているようです。

このイベントはCGPostMouseEvent({x:100, y:100}, 1, 1, 1)とすると、デスクトップの座標{x:100,y:100}でマウスの左ボタンを押した状態を再現します。

CGPostMouseEvent({x:100, y:100}, 1, 1, 0)とすると、マウスの左ボタンを離した状態を再現します。

つまり、押した状態の後に離した状態を作ってあげればクリックしたことを再現したことになります。

今回はクリックする必要はなく、離したままの状態で移動だけをすれば、なんの処理も邪魔せずスクリーンセーバーの起動を阻止できるようになるのではないでしょうか。

 

とは言うものの、ただマウスポインターが無差別に動いてしまう動作をしてしまうと、ユーザーが別の作業している時に邪魔になる可能性があります。

ユーザーが作業している状態、マウスが盛んに移動している場合はプログラムでは動かさないという回避行動が必要でしょう。

常にマウスポインターの位置を監視し、位置が変わっていない時のみ実行するようにします。

 

set {x:mouseX, y:mouseY} to current application's class "NSEvent"'s mouseLocation()

 これで、現在のマウスポインターがいる座標を取得し監視します。

 

では、実際にユーザーが作業していない(マウスが動いていない)状態になったら、マウスポインターを動かすわけですが、

マウスポインターをどのように動かすか考えてみましょう。

例えば、座標 {x:0, y:0} (画面左上)のような決まった位置に移動してしまうと、ユーザーが作業に戻ってきた時に、迷ったり困ってしまうかもしれません。

今のポインターの位置から少し右か左に動かすとした方が良いでしょう。ですが画面の端にポイントがいた場合はポインターがそれ以上動かないと言う場合がある可能性もあります。

なので、右と左に2箇所に動かしてみる方が良いと思います。

できれば、最後に元に戻っていた方が良いと思いますので、これを含めた3ヶ所ほどマウスポインターを動かしてみましょう。

 

CGPostMouseEvent({x:mouseX + 2, y:mouseY}, 1, 1, 0)

CGPostMouseEvent({x:mouseX - 2, y:mouseY}, 1, 1, 0)

CGPostMouseEvent({x:mouseX, y:mouseY}, 1, 1, 0)

 1行目で元の位置からX方向の +2 移動(右)

 2行目で元の位置からX方向へ -2 移動(左)

 3行目で元の位置に戻る動作をさせています。

 

以上で、マウスポインターを動かしてスクリーンセーバーが動くのを阻止することができるようになるのですが、OSのバージョンによっては不具合が発生することがあります。

 

不具合(1)

プログラミングをしていく上で避けられない状況での問題となるのですが、繰り返しコードを作り直して保存をし直す、入力作業&デバグ作業をすると、最初は動いていたCGPostMouseEventが、なぜか動作しなくなってしまう不具合。

これは、最初にプログラムを実行するとセキュリティーのアクセシビリティが反応して実行しても良いプログラムですか?とお伺いのダイアログが出てくると思います。

ですが、2回目以降は聞いてこないのですが、コードを変更して保存し直すとApp名は残ってるものの、実行して良いプロセスではないと静かに除外され実行されなくなります。

改善するには、一度アクセシビリティからApp名を外し再登録し直さなければいけません。

image220610b.jpg

でも、気づかずになっている場合があるので実行されているかのチェックが必要になります。

 

if (my security()) then quit me

 

on security()

set {x:mouseX, y:mouseY} to current application's class "NSEvent"'s mouseLocation()

tell current application

CGPostMouseEvent({x:mouseX + 2, y:mainScreenHeight - mouseY}, 1, 1, 0)

end tell

set {x:mouseX2, y:mouseY2} to current application's class "NSEvent"'s mouseLocation()

if {mouseX, mouseY} = {mouseX2, mouseY2} then

display alert "アクセシビリティをの再設定が必要です" message "システム環境設定のセキュリティー>アクセシビリティに、Appを再登録する必要があります" as warning buttons "cancel" default button 1

return true

end if

return false

end security

 試しにマウスを動かしてみたけど座標が変わっていなかった(CGPostMouseEventが動作することができなかった)場合にアラートを表示して終了するとコードを作ります。

 この後ユーザーが手動で登録し直すわけですが、将来的には安全なAppとして登録するか、又は、安全な証明書を作ってみるのも良いでしょう。

 

不具合(2)

 古いOS(MacOSX10.13~10.14)で発生するCGPostMouseEventが認識されない現象への対応。

最近のOSでは解消されていますが、Apple developerのサイトではCGPostMouseEventが非推奨扱いになっています。そのため一度外れたのか何かは不明ですが使えなくなっていた頃がありました。

ですが、今後、再発する可能性が無いとは言い切れませんので、回避させるコードを追加しておきます。

 

set codeText to "import sys; from Quartz.CoreGraphics import CGEventCreateMouseEvent,CGEventPost,CGPointMake; "

set codeText to codeText & "x = float(" & (mouseX - 2) & "); y = float(" & (mainScreenHeight - mouseY) & "); po = CGPointMake(x, y); event = CGEventCreateMouseEvent(None, 2, po, 0); CGEventPost(0, event); "

do shell script "python -c " & quoted form of codeText

 python言語でコードを作り、シェルスクリプト経由で実行をします。CGPostMouseEventで動作しないと分かった時点で切り替えて実行します。

 これなら、最初からCGEventCreateMouseEventを使えば良いと思われるかもしれませんが、このコードは動作が遅いので避難措置用です。

 

不具合(3)

不具合というのとは違うかもしれませんが、mouseLocation()で取得するY座標と、CGPostMouseEventで疑似クリックをするためのY座標が逆という仕様が存在します。

mouseLocation()ではメインスクリーンの左が{x:0, y:0}の原点で上にのぼるほど座標が加算されていきます。

CGPostMouseEventではメインスクリーンの左が原点で下へ降りるほど加算されます。

この逆向きの座標の数値を調整してやる必要があります。

 

set mainScreenHeight to item 2 of item 2 of ((item 1 of (current application's class "NSScreen"'s screens()))'s frame())

 class "NSScreen"'s screens()メインやサブを含むデスクトップのすべてのフレーム情報を取得します。

 (複数のモニターがあった場合にも対応します)

 (item 1 of ...)'s frame()メインのスクリーン(主となるデスクトップ)のフレームサイズを取得します。

 (複数のモニターがあってもメインのスクリーンの原点がすべてのモニター原点となります)

  フレームのサイズの情報は{{原点のx座標, 原点のy座標}, {横幅, 高さ}}(例:{{0.0, 0.0}, {1920.0, 1080.0}})と二重の階層で収められています。

   item 2 of item 2 of ... で2番目の情報を取得して、さらに2番目の数値を取得すると、メインスクリーンの高さが求められます。

 そこから引き算でY座標を求めればクリックするy座標が得られます。

 

mainScreenHeight - mouseY

 

 

とりあえず、ようやくこれですべて解決です。

 

 

最後に全てをまとめたソースを載せておきます。


nice!(0)  コメント(0) 
共通テーマ:パソコン・インターネット

AppleScriptで取得する時間を操ってみる-NSDate- [AppleScript辞書はつくれるか?]

AppleScriptでオブジェクトを使うと、日時の値がまちまちな時がある。

あるときは『スタンダードなDate値』だったり、『NSDate型』だったりと変化してしまいます。

しかも、NSDateの値だとそのままではAppleScriptで使うことができない。時間などを直接に取り出すことができない。

なので、どの型であっても自動で統一させてみようかと思った。

 

スクリプトエディタ.app

use scripting additions

use framework "Foundation"

 

set aDate to current date -- "12:05" でも、date "2022/5/24" でも、NSDate形式でも可能

set output to my dateTextFormatter(aDate)

output

 

on dateTextFormatter(aDate)

(* date形式、日時テキスト、NSDate形式 に対応した フォーマッター経由の日時テキストへの変換 *)

try

if (class of aDate) = text then set aDate to date aDate --"12:34"のようなTEXTで入力された場合に対応

on error

log "日時への変換に失敗しました"

return false

end try

set aFormatter to current application's class "NSDateFormatter"'s alloc()'s init()

aFormatter's setLocale:(current application's class "NSLocale"'s alloc()'s initWithLocaleIdentifier:"ja_JP")

aFormatter's setDateFormat:"yyyyMd EEEE H:m:s"

set theTimeString to (aFormatter's stringFromDate:aDate) as string

return theTimeString --テキスト形式で返します

end dateTextFormatter

 

-- 結果:"20220524 火曜日 12:34:46"

 

上記では、入力がどんな形のDate値でもテキストとして出力できるようにした一例だが、下記のような設定を

色々いじれば、さまざまなカタチで作れるはずだ。

 

(色々な設定のしかた)

--set aDate to current application's class "NSDate"'s alloc()'s init()  --(current date) NSDateの初期化時に現在の日時が入る

set aDate to current application's class "NSDate"'s |date|()  --(current date)現在の日時の取得

 

set aFormatter to current application's class "NSDateFormatter"'s alloc()'s init()

                         -- ×:YYYY ◯:yyyy --YYYYはなぜか年末に年の数字だけが変わる場合がある (*1)

-- aFormatter's setDateFormat:"yyyyMd H時間ms --"20220524 11時間4244"

-- aFormatter's setDateFormat:"yyMd H時間ms --"220524 11時間4244"

-- aFormatter's setDateFormat:"yyyy/M/d H:m:s"  --"2022/05/24 11:42:44"

-- aFormatter's setDateFormat:"yyyy/M/d H:m:s.SSS"  --"2022/05/24 11:42:44.789"

aFormatter's setDateFormat:"yyyyMd EEEE H:m:s"  --"20220524 火曜日 11:42:44"

-- aFormatter's setDateFormat:"E"  -- "E""EEE" --> ""

-- aFormatter's setDateFormat:"EEEE"  --"火曜日"

 

aFormatter's setTimeZone:(current application's class "NSTimeZone"'s timeZoneWithAbbreviation:"JST")

                                            --日本時間に設定

 

--aFormatter's setLocale:(current application's class "NSLocale"'s systemLocale())

                              --"20220524 Tue 11:42:44" (システム)

aFormatter's setLocale:(current application's class "NSLocale"'s alloc()'s initWithLocaleIdentifier:"ja_JP") 

                           --"20220524 火曜日 11:42:44" (日本語)(*2)

 

-- (*1) 参考-日付がずれる:https://www.mt-megami.com/article/295203529

-- (*2) 参考-Localehttps://colo-ri.jp/develop/2011/12/ios-objective-c-get-each-locale-information.html (*2)

 

 

(Formatterで使える記号)

用途

文字

説明   例

紀元

G

西暦 AD H S T M

GGGG

令和 平成 昭和 大正 明治

*和暦は和暦用Locateを指定

yy

年の2桁     09

yyyy

年の4桁     2009

M MM

数字2桁   01 12

MMM

数字2桁   英字3字 Jan Dec

MMMM

1月 ~ 12

英字 January ~ December

d

数字2桁 0131

曜日

E

日 月 火 水 木 金 土

Sun Mon Tue Wed Thu Fri Sut

EEEE

日曜日 ~ 土曜日

Sunday, Monday, Tuesday, Wednesday

Thursday, Friday, Saturday

午前/午後

a

午前 午後 PM

(023)

H

 

(124)

k

 

午前/午後の時(011)

K

 

午前/午後の時(112)

h

 

m

00 59

s

00 59

ミリ秒

S

0 999

タイムゾーン

z

zzzz

JST

Japan Standard Time

年における週

w

1月第1週からの週

月における週

W

当月の第何週か

年における日

D

11日からの日数

月における曜日

F

当月の何回目の曜日か

 

 

 

 

一度覚えてしまえば、他にも色々と使い所があるかもしれない。

 


nice!(0)  コメント(0) 
共通テーマ:パソコン・インターネット
前の10件 | 次の10件 AppleScript辞書はつくれるか? ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。