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

カテゴリー: AppleScript Application on Xcode

Xcode上のAppleScriptObjCのプログラムから、Xcodeのログ欄へのメッセージ出力を実行

Posted on 5月 13 by Takaaki Naganoya

Xcode上でAppleScriptによるアプリ開発を行なったときに、logコマンドによるXcodeのログ出力欄への出力が、最近になって行えなくなってしまいました。

そこで、テキストエディタにログ出力したり、NSLogでsyslogに出力したりと、いろいろな方法を試してみるわけですが……他のアプリに出力するのはできなくはないものの、手軽さに欠けますし、syslogに出力されたメッセージをコンソール.app上で検索するのも大変です。

ところが、他の言語処理系(Objective-Cなど)ではNSLogを用いてログ出力するとXcodeのログ表示欄にメッセージが表示されるとかで、教えていただいて腰を抜かしました。

そこで、以前に作ったデータの型と内容表示用のプログラムと合わせて、手軽にXcodeのログ表示欄にデータ内容を出力するプログラムを書いてみました。

set theResult to (current date) as string
Logger's logMessage_(theResult)
Logger's printObjectInfo_(sender)
Logger's printObjectInfo_({1,2,3})
Logger's printObjectInfo_({aLabel:1})
Logger's printObjectInfo_(1.2)
Logger's printObjectInfo_("Piyomaru")

さまざまなデータをXcodeのログ表示欄に出力できていることが見てとれます。

–> Download LogTest_V2

macOS 15.5+Xcode 16.3上で動作確認を行なっています。現在執筆中のこちら(↓)の本では、 Xcode+AppleScriptの多彩なサンプル・プロジェクトを紹介しており、本プロジェクトもその1つです。

Posted in AppleScript Application on Xcode | Leave a comment

XIBから作るステータスメニューUI

Posted on 4月 8 by Takaaki Naganoya

AppleScriptで作るステータスメニューは、プログラムで動的に作るケースが圧倒的に多いところですが、Xcode上でCocoa Applicationを作成する場合にはXIBで(=XcodeのInterface Builder上で)作ったほうが簡単だし使い勝手がいいので、作成方法を確認しておきました。


▲ステータスメニュー


▲Interface Builder上でメニューをCocoa binding(Xcode 16.3)

–> Download Archive

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— statusMenuFromXIB
—
— Created by Takaaki Naganoya2 on 2025/03/27.
—
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
property theStatMenu : missing value –xib上で作っておいたメニュー。Cocoa Binding
  
  
on applicationWillFinishLaunching:aNotification
    set theIcon to current application’s NSImage’s imageNamed:(current application’s NSImageNameComputer)
    
set statusItem to (current application’s NSStatusBar’s systemStatusBar())’s statusItemWithLength:(current application’s NSVariableStatusItemLength)
    
statusItem’s setTitle:("PIYOMARU")
    
statusItem’s setImage:theIcon
    
statusItem’s setHighlightMode:true
    
statusItem’s setMenu:theStatMenu
    
    
statusItem’s popUpStatusItemMenu:theStatMenu
  end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    — Insert code here to do any housekeeping before your application quits
    
return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode | Tagged 13.0savvy 14.0savvy 15.0savvy | Leave a comment

Dock Menu

Posted on 4月 5 by Takaaki Naganoya

Dock Menuを表示するAppleScriptアプリです。探すと意外と情報がまとまっていないので、掲載しておきます。

Dock Menuについては、スクリプトエディタやスクリプトメニュー、アプレットなどで動作する通常のAppleScriptでは利用できませんが、Xcode上で作成するアプリやCocoa AppleScript Applicationでは利用できます。このあたりは、どのぐらいAppleScriptの実行環境がアプリのイベントをAppleScript側に提供しているかどうかによります。

スクリプトエディタ上で作成するアプレットの一種、Cocoa-AppleScript Appletを用いると、Dock Menuを動的に作ることが可能です(後述)。

–> Download Xcode Project Archive

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— dock menu
—
— Created by Takaaki Naganoya2 on 2025/04/05.
—
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
property dockMenu : missing value
  
  
on applicationWillFinishLaunching:aNotification
    
  end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
  
–Dock Menu Enabled
  
on applicationDockMenu:(aNotification)
    return dockMenu
  end applicationDockMenu:
  
  
  
on clicked:aSender
    set aTag to (tag of aSender) as integer
    
display dialog (aTag as string)
  end clicked:
end script

★Click Here to Open This Script 

Cocoa-AppleScriptアプレット版はこちらです。macOS 12以降では、Finder上でRosettaを利用して実行するように指定する必要があります。

アプレット本体側のscriptではなく、ランタイム側の「CocoaAppletAppDelegate.scpt」を書き換える必要があります。これを読み返すと、つくづく「いきなりこの内容をScripterに使わせようとしたのは無理があった」と感じます。内容が、macOS 10.7当時のScripterのCocoaへの理解度を考えると難解すぎです。

–> Download Cocoa-AppleScript Applet

AppleScript名:CocoaAppletAppDelegate.scpt
—
— CocoaAppletAppDelegate.applescript
— Cocoa-AppleScript Applet
—
— Copyright 2011 {Your Company}. All rights reserved.
—

— This application delegate emulates the OSA script applet by loading "main.scpt" from the
— "Scripts" folder in the application resources and invoking the traditional run/open/reopen/quit
— handlers in response to Cocoa application delegate methods being called.
—
— This is provided in source form so that you may customize or replace it if your needs go
— beyond the basic applet handlers.
—
— Some of these methods must guard against re-entrancy, because invoking the main.scpt
— handler may end up invoking the event handler inherited from the current application,
— which calls the application delegate’s method again.

script CocoaAppletAppDelegate
  property parent : class "NSObject"
  
property mainScript : missing value — the applet’s main.scpt
  
property didOpenFiles : false — true = the application opened documents during startup
  
property isOpeningFiles : false — re-entrancy guard: true = in the process of opening files
  
property isReopening : false — re-entrancy guard: true = in the process of re-opening
  
property isQuitting : false — re-entrancy guard: true = in the process of quitting
  
  
on applicationWillFinishLaunching:aNotification
    — Insert code here to initialize your application before any files are opened
    
    
— Emulate an OSA Applet: Load the main script from the Scripts resource folder.
    
try
      set my mainScript to load script (path to resource "main.scpt" in directory "Scripts")
    on error errMsg number errNum
      — Perhaps this should silently fail if it can’t load the script; that way, a Cocoa applet
      
— can just have Cocoa classes and no main.scpt.
      
display alert "Could not load main.scpt" message errMsg & " (" & errNum & ")" as critical
    end try
  end applicationWillFinishLaunching:
  
  
on applicationDidFinishLaunching:aNotification
    — Insert code here to do startup actions after your application has initialized
    
    
if mainScript is missing value then return
    
    
— Emulate an OSA Applet: Invoke the "run" handler.
    
    
— If we have already opened files during startup, don’t invoke the run handler.
    
if didOpenFiles then return
    
    
try
      tell mainScript to run
    on error errMsg number errNum
      if errNum is not -128 then
        display alert "An error occurred while running" message errMsg & " (" & errNum & ")" as critical
      end if
    end try
    
    
— TODO: Read the applet’s "stay open" flag and quit if it’s false or unspecified.
    
— For now, all Cocoa Applets stay open and require the run handler to explicitly quit,
    
— which is arguably more correct for a Cocoa application, anyway.
    
(* if not shouldStayOpen then
      quit
    end if *)
  end applicationDidFinishLaunching:
  
  
on applicationShouldHandleReopen:sender hasVisibleWindows:flag
    — Insert code here to perform actions in response to a "reopen" event
    
    
if mainScript is missing value then return true
    
    
— Guard against re-entrancy.
    
if not isReopening then
      set isReopening to true
      
      
— Emulate an OSA Applet: Invoke the "reopen" handler. If there isn’t one, let the application object
      
— handle reopen (this is different from an OSA applet, which would do nothing if there is no handler;
      
— this way, the application will perform the usual "create untitled document" behavior by default).
      
try
        tell mainScript to reopen
        
set isReopening to false
        
        
return false
      on error errMsg number errNum
        if errNum is not -128 then
          display alert "An error occurred while reopening" message errMsg & " (" & errNum & ")" as critical
        end if
      end try
      
      
set isReopening to false
    end if
    
    
return true
  end applicationShouldHandleReopen:hasVisibleWindows:
  
  
on |application|:sender openFiles:filenames
    — Insert code here to perform actions in response to an "open documents" event
    
    
— Remember that we opened files, to avoid invoking the "run" handler later.
    
set didOpenFiles to true
    
    
— Guard against re-entrancy.
    
if not isOpeningFiles and mainScript is not missing value then
      set isOpeningFiles to true
      
      
try
        — Convert all the filenames from NSStrings to script strings
        
set theFilenameStrings to {}
        
repeat with eachFile in filenames
          set theFilenameStrings to theFilenameStrings & (eachFile as text)
        end repeat
        
        
tell mainScript to open theFilenameStrings
        
set isOpeningFiles to false
        
        
tell sender to replyToOpenOrPrint:(current application’s NSApplicationDelegateReplySuccess)
      on error errMsg number errNum
        if errNum = -128 then
          tell sender to replyToOpenOrPrint:(current application’s NSApplicationDelegateReplyCancel)
        else
          display alert "An error occurred while opening file(s)" message errMsg & " (" & errNum & ")" as critical
          
tell sender to replyToOpenOrPrint:(current application’s NSApplicationDelegateReplyFailure)
        end if
      end try
      
      
set isOpeningFiles to false
    else
      tell sender to replyToOpenOrPrint:(current application’s NSApplicationDelegateReplyFailure)
    end if
  end |application|:openFiles:
  
  
on applicationShouldTerminate:sender
    — Insert code here to do any housekeeping before your application quits
    
    
— Guard against re-entrancy.
    
if not isQuitting and mainScript is not missing value then
      set isQuitting to true
      
      
— Emulate an OSA Applet: Invoke the "quit" handler; if the handler returns, it has fully
      
— handled the quit message and we should not quit, otherwise, it calls "continue quit",
      
— which returns error -10000.
      
try
        tell mainScript to quit
        
set isQuitting to false
        
        
return current application’s NSTerminateCancel
      on error errMsg number errNum
        — -128 means there is no quit handler
        
— -10000 means the handler did "continue quit"
        
if errNum is not -128 and errNum is not -10000 then
          display alert "An error occurred while quitting" message errMsg & " (" & errNum & ")" as critical
        end if
      end try
      
      
set isQuitting to false
    end if
    
    
return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
  
–Dock Menu Enabled
  
on applicationDockMenu:(aNotification)
    set aMenu to current application’s NSMenu’s alloc()’s init()
    
set aMenuItem to (current application’s NSMenuItem’s alloc()’s initWithTitle:"Dock Menuだよ" action:"actionHandler:" keyEquivalent:"")
    (
aMenuItem’s setTarget:me)
    (
aMenu’s addItem:aMenuItem)
    
return aMenu
  end applicationDockMenu:
  
  
on actionHandler:sender
    set aTag to (tag of sender) as string
    
set aTitle to (title of sender) as string
    
    
display dialog (aTitle as string)
  end actionHandler:
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode Cocoa-AppleScript Applet | Tagged 13.0savvy 14.0savvy 15.0savvy | Leave a comment

AppleScript Explored 最新OS&Xcode対応 日本語版?

Posted on 2月 18 by Takaaki Naganoya

個人的な資料として、Shane Stanleyの電子書籍「AppleScript Explored」を日本語訳して使っておりました。部分的にmacOS最新版+Xcode最新版にスクリーンキャプチャを入れ替えて。


▲あくまで自分用の私的な資料として作成した日本語版


▲自分用だったので、装飾のたぐいはほとんどなし


▲いつもの感じでレイアウトを作るとこんな感じ?

最初の版から、購入して読んでいましたが……実にいい本です。「もうちょっと画面キャプチャが多いとわかりやすいのに」とは思っていましたが、自分には書けないタイプの本です。

# そのフィードバックをもとに、画面キャプチャ主体の本「AppleScript+XcodeでつくるMacアプリ Xcode 14対応」を出したわけで

冗談半分でShaneに「日本語訳版を出してもいい?」と聞いてみたところ、快諾。えっ? いいの?!(^ー^;;;

いまXcodeで作っているAppleScriptのプロジェクトがあるのですが、こうした資料が充実していないと本当に辛いので、日本語版を出せることは個人的に素直に嬉しいです。

ただ、本書がOS X 10.8ぐらいの時代に書かれたという時代背景があり、そのあたりの状況認識を大幅に変更する必要はあると思います。当時はShaneがAppleScriptObjC Explorerを作っていたので、そうしたツールの存在を前提として書かれた部分もあるので、macOS 15時代+Xcode 16環境に合わせてアップデートする必要もあることでしょう。

Posted in AppleScript Application on Xcode Books news | Tagged 15.0savvy Xcode | Leave a comment

OSAScriptViewのじっけん#2

Posted on 1月 9 by Takaaki Naganoya

OSAScriptViewの実験の続編です。#1ではSingle Windowのアプリを作って実験してみました(モノ自体は作ってあったので)。macOS 15.3 beta+Xcode 16.2でテストしました。

#2ではDocumentベースのアプリを作って、そこにOSAScriptViewを載せました。余計なテキストフィールドが載っているのは、いろいろ野望があるためです。

–> Download Fake Script Editor

#1と同様にコピペでAppleScriptを入力して、実際に動かして、結果を受け取れます。

ただし、この段階ですでに問題山積の状態です。Compile操作を行うと、ひさしぶりのビーチボール表示になって返ってきません。

Run Scriptはできるのに、Compile(Check Syntax)動作で落ちます。

この段階でかなり「どうすんの、これ?」という状態です。普通に部品を並べて普通につないで動かしたらクラッシュするというのは……

Posted in AppleScript Application on Xcode | Tagged 13.0savvy 14.0savvy 15.0savvy OSAScriptView | Leave a comment

OSAScriptViewのじっけん#1

Posted on 1月 9 by Takaaki Naganoya

OSASCriptViewを試してみましょう。自前でScript Editorをどの程度作れるのかという確認作業です。Xcode 16.2+macOS 15.3betaで確認を行なっています。

–> Download Xcode Project osascript_test

とはいえ、これは2017年にすでに調査してありました。OSASCriptControllerとOSAScriptViewをCocoa Bindingでつないで、さらにいくつかの必要なボタンをOSASCriptControllerにつないで、簡単なAppleScript記述+実行のテストプロジェクトを作成。

この実行環境は、AppleScriptライブラリを認識して呼び出せますし、OSの構文色分け設定を認識します。

ただし、Apple純正のスクリプトエディタ同様、Cocoa Objectのログ表示は行えません。

また、かなり致命的な問題なのですが、バンドル形式のAppleScriptはこの状態では編集・実行できません。

Appleが配布していたサンプルコードで、AppleScriptObjCが出たての頃にスクリプトエディタをASOCで組んだプロジェクトを見かけたのですが、それを探して編集するのが手っ取り早そうです。ただ、あれもバンドル形式のAppleScript書類を編集・実行できなかった記憶があります。

Posted in AppleScript Application on Xcode OSA | Tagged 13.0savvy 14.0savvy 15.0savvy OSAScriptController OSAScriptView | Leave a comment

NSObjectのクラス名を取得 v2.1

Posted on 1月 6 by Takaaki Naganoya

いろいろ調べて、NSObjectのクラス名を正確に文字列として取得するAppleScriptのXcode Projectのアップデート版です。

上のテキストフィールドにAppleScriptで各種Objectの生成を書いて「Exec」ボタンをクリックすると、それを実行して解釈プログラムに渡して下のテキストフィールドに表示します。

前バージョンでは値をNSObjectのdescriptionそのままでしたが、ChatGPTに「NSObjectをAppleScript形式で、文字列として返すAppleScriptFormatterというプログラムを書け」と指示したら、わりとちゃんと動くObjective-Cのコードを吐き出してきました。内容を再帰でさらっているようです。

とりあえず、叩き台を作ってみたのでいろいろなCocoa Objectのデータを突っ込んでためしてみるかというところでしょう。

–> Download Xcode Project runtime test_v2_1

Posted in AppleScript Application on Xcode | Leave a comment

NSObjectのクラス名を取得 v2

Posted on 1月 6 by Takaaki Naganoya

いろいろ調べて、NSObjectのクラス名を正確に文字列として取得するAppleScriptのXcode Projectです。

上のテキストフィールドにAppleScriptで各種Objectの生成を書いて「Exec」ボタンをクリックすると、それを実行して解釈プログラムに渡して下のテキストフィールドに表示します。

Script Debuggerのない世界が来ても大丈夫なように、いろいろ調査を行なっていますが、なくなると割とダメージが大きいのがCocoa Object(NSObject)のログ表示です。

# 個人的には、デバッグ機能は全部いらないので、結果表示とFramework呼び出しのあたりを実現したい

これまでにも何度か調査したことがあったのですが、Mac系開発者の知り合いに聞いてみたところ、Objective-C Runtime系のAPIを使えば取れるのでは? とのこと。

最終的には、エディタ的なものになるのかもしれませんが、とりあえず実行結果がNSObjectだったときに備えて、そのクラス名を正確に取得できるようにしてみました。

過去に、既知のクラスであればループでclassOfで調べてクラス名を取得するAppleScriptを書いたことはありましたが、未知のクラスだと手も足も出ませんでした。本プロジェクトでは、対応可能です。

–> Download runtime test_v2(Xcode Project)

クラス名はなんとか文字列として取得できていますが、値についてはまだNSObjectのdescriptionを取得しているだけです。本プロジェクトの叩き台はChatGPTに問い合わせて書いてみた(ただ、山のように修正する必要があった)ものなので、案外ヒントぐらいはChatGPTに聞いてみるといいのかもしれません。処理内容については、データを文字列で表現するというありきたりなものなので。

Posted in AppleScript Application on Xcode | Leave a comment

ステータスメニューからアプリ本体を最前面に(改2)

Posted on 12月 24, 2024 by Takaaki Naganoya

GUIアプリのステータスメニュー上に置いたアイコン>メニューからアプリ本体のウィンドウをアクティブにできないという問題が発生していました。

macOS 13、14、15とずーーっとこの動作なので、全世界的に困らされている状況があって……久しぶりにXcodeでGUIアプリをAppleScriptで作って、この問題に例外なく自分も悩まされていました。macOS 15.2上ではこれで動いていたのですが、

-> ステータスメニューからアプリ本体を最前面に(改)

edama2さんから情報を教えていただき、ここで用いていた「activateIgnoringOtherApps」がmacOS 15.2でDeprecated扱いになったとのこと。

ただ、Appleのdocumentで紹介されていたNSApplicationのactivate()メソッドを使っても、この場合にはまともに動作しませんでした。代替手段を紹介しておきながら、それがまともに動かないというのはいかがなものでしょう。

昨今のWWDCでは、さっぱり地に足のついた情報が紹介されておらず、見るだけ時間の無駄といった印象を持っています。あてにならない大本営発表ばかりではなく、まともな情報を期待したいところですが、それは難しいところなのでしょうか。

一応、AppleScriptのactivateコマンドが動作するようになったので(macOS 14ではactivateでも最前面に持っていけませんでした)、そのように修正を行いました。

–> Download process Control test Project

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— process Control test
—
— Created by Takaaki Naganoya2 on 2024/11/01.
—
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
  
property NSMenu : a reference to current application’s NSMenu
  
property NSMenuItem : a reference to current application’s NSMenuItem
  
property NSStatusBar : a reference to current application’s NSStatusBar
  
property NSVariableStatusItemLength : a reference to current application’s NSVariableStatusItemLength
  
  
  
on applicationWillFinishLaunching:aNotification
    my initializeMenu:(aNotification)
  end applicationWillFinishLaunching:
  
  
  
on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
  
on clicked:aSender
    my activateMe:(me)
    
set aTag to (tag of aSender) as integer –Important!!
    
set aTitle to (title of aSender) as string
    
    
if aTag is in {41, 42, 43, 44, 45, 46} then
      –my activateMe:aSender
      
current application’s NSApplication’s |activate|
    else if aTag = 100 then
      display dialog "Clicked"
    end if
    
    
if aTitle = "Quit" then quit
  end clicked:
  
  
  
on activateMe:aSender
    –macOS 13から15.0あたりまでactivateができなかった(多分バグ)
    
–current application’s NSApplication’s |activate|
    
tell current application to activate
    
–theWindow’s makeKeyAndOrderFront:(me)
    
theWindow’s orderFrontRegardless()
  end activateMe:
  
  
  
–Status Menu Structure
  
on initializeMenu:aSender
    set aList to {"Piyomaru", "Software", "", "Function", {"1", "2", "3", "4", "5"}, "", "Quit"}
    
    
set aStatusItem to current application’s NSStatusBar’s systemStatusBar()’s statusItemWithLength:(current application’s NSVariableStatusItemLength)
    
    
aStatusItem’s setTitle:" TEST "
    
aStatusItem’s setHighlightMode:true
    
aStatusItem’s setMenu:(createMenu(aList) of me)
  end initializeMenu:
  
  
  
  
on createMenu(aList)
    set aMenu to current application’s NSMenu’s alloc()’s init()
    
set aCount to 10
    
    
set prevMenuItem to ""
    
    
repeat with i in aList
      set j to contents of i
      
set aClass to (class of j) as string
      
      
if j is equal to "" then
        set aMenuItem to (current application’s NSMenuItem’s separatorItem())
        (
aMenu’s addItem:aMenuItem)
      else
        if (aClass = "text") or (aClass = "string") then
          
          
if j = "Quit" then
            set aMenuItem to (current application’s NSMenuItem’s alloc()’s initWithTitle:j action:"clicked:" keyEquivalent:"")
          else
            set aMenuItem to (current application’s NSMenuItem’s alloc()’s initWithTitle:j action:"clicked:" keyEquivalent:"")
          end if
          
          (
aMenuItem’s setTag:aCount)
          (
aMenuItem’s setTarget:me)
          (
aMenu’s addItem:aMenuItem)
          
          
set aCount to aCount + 10
          
copy aMenuItem to prevMenuItem
          
          
        else if aClass = "list" then
          –Generate Submenu
          
set subMenu to current application’s NSMenu’s new()
          (
aMenuItem’s setSubmenu:subMenu)
          
          
set subCounter to 1
          
          
repeat with ii in j
            set jj to contents of ii
            
            
set subMenuItem1 to (current application’s NSMenuItem’s alloc()’s initWithTitle:jj action:"clicked:" keyEquivalent:"")
            (
subMenuItem1’s setTarget:me)
            (
subMenuItem1’s setTag:(aCount + subCounter))
            (
subMenu’s addItem:subMenuItem1)
            
            
set subCounter to subCounter + 1
          end repeat
          
        end if
        
      end if
      
    end repeat
    
    
return aMenu
  end createMenu
  
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode Bug | Leave a comment

ステータスメニューからアプリ本体を最前面に(改)

Posted on 11月 6, 2024 by Takaaki Naganoya

GUIアプリを作ったときに、ステータスメニュー上に置いたアイコン>メニューからアプリ本体のウィンドウをアクティブにできないという問題が発生しています。

macOS 13、14、15とずーーっとこの動作なので、全世界的に困らされている状況があって……久しぶりにXcodeでGUIアプリをAppleScriptで作って、この問題に例外なく自分も悩まされていました。

その解決を行ったAppleScriptプロジェクトです。macOS 13.7.1上でXcode 15.2で試しています。

# 本記事投稿後にプログラムの見直しを行い、掲載リストおよびXcodeプロジェクトの差し替えを行いました。

–> Download Xcode Projet

GUIアプリ内から生成したステータスバー上のステータスアイテム。ステータスアイテムからメニュー表示。表示されたメニューから項目選択でメインウィンドウを最前面に表示する。

tell current application to activate

では何も起こりません(macOS 12まではこれで大丈夫だった)。

そういう操作を行なってもメインウィンドウが最前面に表示されず、メインウィンドウを強制的にアクティブにするようなコードを入れても、「UIがないプロセスから他のプロセスをアクティブにできない」といったワーニングが表示されるだけで、何も起こりません。

メチャクチャ困ります。

そこで、edama2さんに相談していろいろ試してみたところ、強制的にGUIアプリを最前面に持っていけました。

こちらの議論を参考にしています。


on activateMe:aSender
  theWindow's makeKeyAndOrderFront:(me)
  theWindow's orderFrontRegardless()
end activateMe:

当初、ウィンドウの生成を動的に行なっていましたが、その部分を削除しても動作することを確認できたため、削除しています。

なお、macOS 15.2+Xcode 16.1でビルドして実行してみたら、「tell current application to activate」だけでウィンドウを最前面に持っていけています。ここで紹介している処理は、macOS 13、14で同様の処理ができるように必要になってしまうようです。

macOS 13/14(+15.0〜15.1?)のバグと言って差し支えないでしょう。

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— process Control test
—
— Created by Takaaki Naganoya2 on 2024/11/01.
—
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
  
property NSMenu : a reference to current application’s NSMenu
  
property NSMenuItem : a reference to current application’s NSMenuItem
  
property NSStatusBar : a reference to current application’s NSStatusBar
  
property NSVariableStatusItemLength : a reference to current application’s NSVariableStatusItemLength
  
  
  
on applicationWillFinishLaunching:aNotification
    my initMenu:me
  end applicationWillFinishLaunching:
  
  
  
on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
  
on clicked:aSender
    my activateMe:(me)
    
set aTag to (tag of aSender) as integer –Important!!
    
set aTitle to (title of aSender) as string
    
    
if aTag is in {41, 42, 43, 44, 45, 46} then
      my activateMe:aSender
    else if aTag = 100 then
      display dialog "Clicked"
    end if
    
    
if aTitle = "Quit" then quit
  end clicked:
  
  
  
on activateMe:aSender
    current application’s NSApp’s activateIgnoringOtherApps:(true)
    
theWindow’s makeKeyAndOrderFront:(me)
    
theWindow’s orderFrontRegardless()
  end activateMe:
  
  
  
–Status Menu Structure
  
on initMenu:aSender
    set aList to {"Piyomaru", "Software", "", "Function", {"1", "2", "3", "4", "5"}, "", "Quit"}
    
    
set aStatusItem to current application’s NSStatusBar’s systemStatusBar()’s statusItemWithLength:(current application’s NSVariableStatusItemLength)
    
    
aStatusItem’s setTitle:" TEST "
    
aStatusItem’s setHighlightMode:true
    
aStatusItem’s setMenu:(createMenu(aList) of me)
  end initMenu:
  
  
  
  
on createMenu(aList)
    set aMenu to current application’s NSMenu’s alloc()’s init()
    
set aCount to 10
    
    
set prevMenuItem to ""
    
    
repeat with i in aList
      set j to contents of i
      
set aClass to (class of j) as string
      
      
if j is equal to "" then
        set aMenuItem to (current application’s NSMenuItem’s separatorItem())
        (
aMenu’s addItem:aMenuItem)
      else
        if (aClass = "text") or (aClass = "string") then
          
          
if j = "Quit" then
            set aMenuItem to (current application’s NSMenuItem’s alloc()’s initWithTitle:j action:"clicked:" keyEquivalent:"")
          else
            set aMenuItem to (current application’s NSMenuItem’s alloc()’s initWithTitle:j action:"clicked:" keyEquivalent:"")
          end if
          
          (
aMenuItem’s setTag:aCount)
          (
aMenuItem’s setTarget:me)
          (
aMenu’s addItem:aMenuItem)
          
          
set aCount to aCount + 10
          
copy aMenuItem to prevMenuItem
          
          
        else if aClass = "list" then
          –Generate Submenu
          
set subMenu to current application’s NSMenu’s new()
          (
aMenuItem’s setSubmenu:subMenu)
          
          
set subCounter to 1
          
          
repeat with ii in j
            set jj to contents of ii
            
            
set subMenuItem1 to (current application’s NSMenuItem’s alloc()’s initWithTitle:jj action:"clicked:" keyEquivalent:"")
            (
subMenuItem1’s setTarget:me)
            (
subMenuItem1’s setTag:(aCount + subCounter))
            (
subMenu’s addItem:subMenuItem1)
            
            
set subCounter to subCounter + 1
          end repeat
          
        end if
        
      end if
      
    end repeat
    
    
return aMenu
  end createMenu
  
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode Bug GUI | Leave a comment

Uni DetectorをUniversal Binaryビルドして最新OSで動くように改修

Posted on 6月 19, 2021 by Takaaki Naganoya

すべてAppleScriptで組んである、アプリケーションのバイナリアーキテクチャ判定ツール「Uni Detector」。

macOS 11上でCPUアーキテクチャのグラフ表示を行おうとするとクラッシュするという現象を横目に、さすがに開発環境として9年落ちのMacBook Pro Retina 2012が辛くなっていたので、M1 Mac miniに入れ替えてソースコードの改修に着手してみました。

M1 Native動作ほかOSのバグへの対処など

まずは、UniversalバイナリでビルドするようにXcode projectを設定。瞬殺。実機確認ができていないだけで、すでにUniversal Binary化については方法を確認してありました。「Check All」でアプリケーション情報を収集する際のパフォーマンスはIntelバイナリをRosetta 2上で実行したときよりは良好でした。

次に、CPUアーキテクチャのグラフ表示を修正。NSStringのstringWithFormat:メソッドを呼び出すと100%クラッシュするというバグをmacOS 11で仕込まれたことが発覚。同じ働きを行う「回避ルーチン」を作成。さっそく、Uni Detectorに組み込んでみました。

Universal Binary化したら、CPUアーキテクチャの移り変わりを表示したグラフ上の実行中のマシンアーキテクチャ表示インジケータの修正もOK。そして、OSバージョン番号の取得を修正して、現在実行中のOSインジケータも修正。

おおよそ、バージョンアップ前のIntel Mac用バイナリと同等の動作を行うレベルになりました。

ただし、全体的に動作が速くなったりはしません。CPUの速度が速くなっていたとしても、OSの内部機能の呼び出しがmacOS 10.15以降で遅くなっているとのこと。並列処理を行いにくいAppleScriptの処理において、M1 Mac上でアホみたいに速度向上することは(本アプリを試しに動かした感じでは)ありません。

M1 Mac各機種において、SSDへのアクセス速度は大幅に向上しているため(MacBook Pro Retina 2012比)、CPU速度の向上と合わせて大幅な速度向上があるはずでしたが、macOS 10.15以降のOS機能呼び出し(Scripting Bridge経由)が遅くなっており、全体として見るとプラスマイナス・ゼロといった印象。逆にmacOS 11+M1 MacとmacOS 10.14.6+Intel Macでは後者の方が高速という笑えない状況も見えてきました。

GUIアプリケーションの動作およびそれをAppleScriptから動かすやり方については、だいたい期待どおりの速度が出ている感じです。

# その後、macOS 12でAppleScriptの処理速度が回復&向上したことで、M1 Mac上で大幅に実行速度が向上しました

M1対応の「その次」へ

M1対応、macOS 11対応などを行い、Appleが新たに作ったメーカー謹製のありがたーーいバグを回避したあとで、実際に1ユーザーとして使ってみるといろいろ感じることがあります。

macOS 11+M1 MacではiOSのアプリケーションをApp Storeからダウンロードでき、実際にiOSアプリケーションが、macOSアプリケーションと一緒に/Applicationsフォルダに入ります。

iOSアプリも、Zip圧縮されたipa形式ではなく、展開された状態でFinderに表示されます。Finder上に並んでいる様子を見るかぎりではMacアプリケーションと違和感がありません。

ひるがえってUniDetector上に表示されるiOSアプリケーションたち。カテゴリ情報がInfo.plist内に書かれていない(メタデータは別管理)ため、空欄になっています。

また、iOSアプリのカテゴリとMacアプリケーションのカテゴリの整合性も調整する必要があります。サポートする最小限のOSの情報などもiOSのものを表示する必要があることでしょう。

→ iOSアプリのジャンル判定を行う処理を書いて、スクリプトエディタ上では動作しているのですが、Xcode上のCocoa-AppleScriptアプリケーションに組み込むと、Sandboxの制限により機能しませんでした。残念!

Posted in AppleScript Application on Xcode | Tagged 11.0savvy | 1 Comment

Window表示とMenu表示を切り替える

Posted on 10月 26, 2020 by Takaaki Naganoya

Xcode上で記述するCocoa AppleScriptアプリケーションで、通常のWindow表示とステータスバーから呼び出すメニュー内に表示するスタイルの切り替えテストプログラムです。

macOS 10.14.6上でXcode 11.3.1を動かして確認しています。

–> Download toggleWindow.zip (Xcode Project Archive)

この機能は実際に使いたいと思っていたものの、なかなかうまく実装できていませんでした。

個人的に、GUIベースのアプリケーションを作っていると、環境設定まわりの機能を実際に組む段階でやたらと時間がかかって大変でした。

アプリケーションのメインウィンドウ上に表示している部品を環境設定ウィンドウにも同様に出す必要が出てくるわけで、その場合同じものを2度作ることは避けたいところです。通常表示している部品と、環境設定ウィンドウで表示する部品は同じものを使いまわしたいところです。

それをどのように共通化してGUI部品のかたまりを「使い回す」かについては、頭の痛い問題でした。なかなか過去形で表現するのがはばかられる状況ですが(未解決)、ここをクリアしないことには話になりません。

本テストプログラムでは、Window上に表示するビュー(NSView)とメニュー内に表示するビューに同じものを指定しています。これで、複数の場所に同じビューを使いまわしやすくなるだろうか、というところです。

NeXTstepにティアオフ・メニューという、メニューをドラッグ&ドロップするとメニューから切り離してフローティングパレットのように運用できる機能がありました。Macのアプリケーションでもこれを実装したものを見たことはありますが、使い勝手がいいかと言われると「それほどでも」といった印象でした

途中、NSMenuを閉じる処理で行き詰まっていたところ、Twitter上で@masakihoriさんに解決策を教えていただきました(aMenu’s cancelTracking())。ありがとうございます。

実際に、Window表示されているViewをメニューに入れてみたところ、いろいろ挙動が変わってくることを確認できました。ポップアップメニューについては操作できず、NSTabViewを配置して切り替えてみても、切り替えたことが内部のビューに通知されない様子。メニューに入れて使うべきではないと思われました。

テキストビューも、一応入力はできるもののコピー&ペーストなどの操作は行えません。もともと、メニューにテキストビューが入っていると違和感がすごいので、するべきではないでしょう。

セグメントビューについてはまともに使えますし、スライダーもまともに動作します。試してはいませんが、Date Picker(カレンダー表示)あたりが限界ではないでしょうか。WebViewもメニューに入れられると思いますが、どの程度インタラクティブに操作できるかについては未確認です。

本サンプルについて、当初はステータスバー上のステータスアイテムからPopoverを表示させようかと考えたのですが、menu bar extra(ステータスアイテム)からPopoverは表示できないんですね(Uni Detectorのときに実験してうまく行かず、github上で公開している人のコードも眺めてみましたが……上から下まで全部自前で作っているようでした)。

そのうえ、Appleからも「menu bar extra(ステータスアイテム)からPopoverを表示するんじゃねえ」と釘を刺されているとのことで、ステータスアイテムからメニューを表示、その中にカスタムビューを入れてみた次第です。

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— Toggle Window test
—
— Created by Takaaki Naganoya on 2020/10/26.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
property theView : missing value
  
property aButton : missing value
  
  
property aFlag : true
  
property aStatusItem : missing value
  
  
property aMenu : missing value
  
property bMenuItem : missing value
  
  
on applicationWillFinishLaunching:aNotification
    aButton’s setTitle:"–> Status Menu"
    
set aFlag to true
    
theWindow’s setContentView:theView
  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
    set aTag to (tag of aSender) as integer
    
    
if aTag = 100 then
      if aFlag = true then
        –通常Window表示→Menu表示
        
my makeStatusItem()
        
theWindow’s performClose:aSender
        
aButton’s setTitle:"–> Window"
      else
        –Popup表示→通常Window表示
        
        
bMenuItem’s setHidden:true
        
theView’s setHidden:true
        
aMenu’s cancelTracking()
        
        
theWindow’s setContentView:theView
        
theView’s setHidden:false
        
theWindow’s makeKeyAndOrderFront:aSender
        
        
current application’s NSStatusBar’s systemStatusBar()’s removeStatusItem:aStatusItem
        
        
aButton’s setTitle:"–> Status Menu"
        
        
–自分を最前面に
        
current application’s NSApp’s activateIgnoringOtherApps:true
      end if
      
      
set aFlag to not aFlag –Flip Flap
      
    else if aTag = 110 then
      display notification "Clicked 1"
      
    else if aTag = 120 then
      display notification "Clicked 2"
      
    else if aTag = 130 then
      display notification "Clicked 3"
      
    end if
    
    
  end clicked:
  
  
on actionHandler:aSender
    –Do nothing
  end actionHandler:
  
  
  
on makeStatusItem()
    –if aStatusItem = missing value then return
    
    
set aStatusItem to current application’s NSStatusBar’s systemStatusBar()’s statusItemWithLength:(current application’s NSVariableStatusItemLength)
    
    
aStatusItem’s setTitle:"🍎"
    
aStatusItem’s setHighlightMode:true
    
aStatusItem’s setDelegate:me
    
aStatusItem’s setAction:"statusclicked:"
    
    
set aMenu to current application’s NSMenu’s alloc()’s init()
    
    
set bMenuItem to (current application’s NSMenuItem’s alloc()’s initWithTitle:"" action:"actionHandler:" keyEquivalent:"")
    
bMenuItem’s setView:theView
    (
bMenuItem’s setTarget:me)
    (
aMenu’s addItem:bMenuItem)
    
    
aStatusItem’s setMenu:aMenu
  end makeStatusItem
  
  
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy | 2 Comments

自分のウィンドウのフルスクリーン化 v3

Posted on 5月 22, 2020 by Takaaki Naganoya

Xcode上で作成したAppleScriptアプリケーションのウィンドウをフルスクリーン化するAppleScriptです。

–> download fullScreenTestv3 (Xcode project archive)

前バージョンを実際にアプリケーションに組み込んで実行してみたところ、メニューバーを表示しないうえにツールバー(NSToolbar)も非表示状態でフルスクリーン化したうえに、通常表示状態に戻ってこれませんでした。戻ってくるにはアプリケーションを終了(Command-Q)するしかありませんでした。

ゲームならこれでいいと思うのですが、通常のアプリケーションでフルスクリーンモードから戻ってこられないのは困りますし、メニューやツールバーが使えないのは困ります。

そこで、複数あるうちの別のやりかたを試してみました。本テストアプリケーションのツールバー上の左側のボタンが前バージョンと同じ働きをするもの、右側が新規に試したものです。

ツールバーの右側のボタンをクリックすると、ウィンドウの緑色のボタンをクリックして全画面表示させたのと同じ動きを行います。


▲ビルドして起動したところ


▲ツールバー左側のボタンをクリックして全画面表示させたところ。全画面表示されるが、ツールバーもメニューも表示されない。Command-Qで終了しないと解除されない


▲ツールバー右側のボタンをクリックして全画面表示させたところ。もう一度クリックすると通常表示モードに戻る


▲自分のアプリケーション(Kamenoko)のツールバーに組み込んで実験したところ(制作中のv1.1)

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— fullScreenTest
—
— Created by Takaaki Naganoya on 2020/05/21.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
property theWindowView : missing value
  
  
on applicationWillFinishLaunching:aNotification
  
end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
on clicked:aSender
    set aTag to (tag of aSender) as integer
    
    
if aTag = 10 then
      set curScreen to theWindow’s screen()
      
set fMode to (theWindowView’s inFullScreenMode) as boolean
      
      
if fMode = true then
        –Can not return from Full Screen Mode. Quit this test app to return from full screen mode
        
theWindowView’s exitFullScreenModeWithOptions:(missing value)
      else
        –Enter Full Screen Mode
        
theWindowView’s enterFullScreenMode:(curScreen) withOptions:(missing value)
      end if
      
    else if aTag = 20 then
      set fMode to (theWindowView’s inFullScreenMode) as boolean
      
      
if fMode = true then
        –Exit Full Screen Mode
        
theWindow’s toggleFullScreen:(missing value)
      else
        –Enter Full Screen Mode with Toolbar
        
theWindow’s toggleFullScreen:theWindow
      end if
    end if
    
  end clicked:
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode | Tagged 10.13savvy 10.14savvy 10.15savvy NSView NSWindow | Leave a comment

ダブルクリックとコンテクストメニュー表示をサポートするボタン

Posted on 5月 22, 2020 by Takaaki Naganoya

Xcode上で作成するAppleScriptアプリケーションで、ダブルクリックとコンテクストメニュー表示を受け入れるボタンのプロジェクトの試作品です。

–> Download Xcode Projext (doubleClick v2)

ボタンでシングルクリックを受け付けるのは簡単ですが、ダブルクリックを受信するためには、少し手間がかかります。まして、コンテクストメニュー表示は、、、、、

この試作品では、クリックされたボタンを識別できていません。ダブルクリックされたボタンのTagとか、コンテクストメニュー表示させたボタンのTagを取得できるように改変したいところです。

こうした(↑)テーマセレクタで、ダブルクリックでそのままテーマ選択を行えるように対処したいところです。テーマセレクタとか環境設定なんて、アプリケーション開発の最後のほうでやっつけ的に行うので、それほど気合いを入れて作っているものではありません(個人の見解です)。

当初はもっと仕様的に「盛った」ものを作ろうとデザインしたのですが、いざ作ってみたら技術的に難しすぎたので、技術的な難易度を大幅に下げて実装してみました(ここで妥協ができないとモノが仕上がりません)。

自分はRadio Buttonに画像を載せて「選択状態だけとれればいい」と割り切って実装しましたが、たしかにダブルクリックぐらいは受け付けたほうがよいでしょう。Keynoteのテーマセレクタのように。

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— doubleClick
—
— Created by Takaaki Naganoya on 2020/01/29.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  
  
property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
property theView : missing value
  
property DCButton : missing value
  
property aConMenu : missing value
  
  
on applicationWillFinishLaunching:aNotification
    —
  end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
on clicked:aSender
    display dialog "Clicked"
  end clicked:
  
  
on dispContextual:aEvent
    current application’s NSMenu’s popUpContextMenu:(aConMenu) withEvent:(aEvent) forView:(theView)
  end dispContextual:
  
  
on action:aSender
    display dialog (tag of aSender) as string
  end action:
  
end script

★Click Here to Open This Script 

AppleScript名:DCButton.applescript
—
— DCButton.applescript
— Kamenoko
—
— Created by Takaaki Naganoya on 2020/05/18.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script DCButton
  property parent : class "NSButton"
  
  
on mouseDown:aEvent
    set buttonNum to aEvent’s buttonNumber()
    
set aEtype to aEvent’s type()
    
set aCount to aEvent’s clickCount()
    
    
if aCount = 3 then –Triple Click
      display dialog "Triple Click"
      
    else if aCount = 2 then –Double Click
      display dialog "Double Click"
      
    end if
  end mouseDown:
  
  
on mouseMoved:theEvent
    log {"mouseMoved", aEvent}
  end mouseMoved:
  
  
on mouseUp:aEvent
    log {"mouseUp", aEvent}
  end mouseUp:
  
  
on mouseDragged:aEvent
    log "mouseDragged"
  end mouseDragged:
  
  
on rightMouseDown:aEvent
    –Display Contextual Menu
    
current application’s NSApp’s delegate()’s performSelector:"dispContextual:" withObject:(aEvent)
  end rightMouseDown:
  
  
on rightMouseUp:aEvent
    log {"rightMouseUp", aEvent}
  end rightMouseUp:
  
  
on clicked:aSender
    continue clicked:(missing value)
  end clicked:
  
  
(*
  on mouseEntered:theEvent
    log {"mouseEntered", theEvent}
  end mouseEntered:

  on mouseExited:theEvent
    log {"mouseExited", theEvent}
  end mouseExited:
*)
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode | Tagged 10.13savvy 10.14savvy 10.15savvy NSButton NSMenu | Leave a comment

自分のウィンドウのフルスクリーン化 v2

Posted on 5月 21, 2020 by Takaaki Naganoya

Xcodeで作成したAppleScriptアプリケーションの、メインウィンドウ上のビューをフルスクリーン表示させるAppleScriptです。

→ Download Xcode Project

AppleScriptのProjectだとoptionにmissing value以外が使えないみたいなのですが、、、、

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— fullScreenTest
—
— Created by Takaaki Naganoya on 2020/05/21.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
property theWindowView : 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 NSTerminateNow
  end applicationShouldTerminate:
  
  
on clicked:aSender
    set fMode to (theWindowView’s inFullScreenMode) as boolean
    
if fMode = true then
      theWindowView’s exitFullScreenModeWithOptions:(missing value)
    else
      theWindowView’s enterFullScreenMode:(current application’s NSScreen’s mainScreen()) withOptions:(missing value)
    end if
  end clicked:
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode | Tagged 10.14savvy 10.15savvy NSScreen NSWindow | 1 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 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

common elements Libの評価アプリケーションを配布

Posted on 3月 5, 2020 by Takaaki Naganoya

ライブラリのインストール方法やらスクリプトエディタの使い方やらがわかっていないとcommon elements Libを実際に使って試すことができないので、実際に機能を評価できるよう最低限のGUIをつけてみました。

–> Download GUI App Executable(Zip archive, 57KB)

macOS 10.13,10.14, 10.15上で動作します。実行にはインターネット接続を必要とします。

Posted in AppleScript Application on Xcode Script Libraries | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

Post navigation

  • Older 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