How to catch display dialog/alert event?

asobjc

(Jonas Whale) #1

Is it possible to add a permanent event listener to the system to run a script each time a dialog or alert is triggered?


(Phil Stokes) #2

Can you be more specific? Alerts can come from all sorts of sources, and whether you can observe the initiating event directly (as a sys call) or indirectly (as a file read/open) is going to depend largely on whether your observer process has the privileges to observe the target process.

Ever since SIP a lot of stuff that might have been employed to try something like this is busted. You can’t attach a debugger to Finder to catch API calls to, say, NSAlert when SIP is on for example, nor can you use dtrace, opensnoop, or fs_usage to monitor file opens/reads system-wide any longer.

But even if you could, you’d still be only looking at one possible source of alerts out of many.

Hence, if you can narrow down your target to something more specific -why exactly do you want to do this? what problem are you trying to solve? what alerts specifically do you need to catch? - you might be in with a better chance of an answer.


(Phil Stokes) #3

Is it possible to add a permanent event listener to the system to run a script each time a dialog or alert is triggered?

I found a way to do this by combining lua (via Hammerspoon) with AppleScript.

The following is lua code, that Hammerspoon users add to their config file. It’ll run the applescript whenever a window with AXDialog subrole is created. However, note that not all Application alerts are AXDialogs, so whether this works or not will be heavily dependent on what events exactly you’re trying to catch.

function runApplescript(aWindow, anApp, anEvent)
	-- print(aWindow) -- logs the window to Hammerspoon's Console
	local fire = false
	local winrole = aWindow:subrole()
		-- print the subrole to the Console
	-- print("window is " .. winrole)
	
	if winrole == "AXDialog" then
		fire = true
	end
	
       -- possible other conditions to filter on
       -- if...then
            --fire = true
        -- end
       
        -- create and run the AppleScript if the window meets any of our conditions above
	if fire == true then
            -- create
            local osaCode = [[
                use AppleScript version "2.5"
                --your script goes here
                --
           ]]

        -- run
    	hs.osascript.applescript(osaCode)
	end
end

-- create a window filter
allWindowFilter = hs.window.filter.new()
-- callback to the runApplescript function whenever a new window is created
allWindowFilter:subscribe(hs.window.filter.windowCreated, runApplescript)

Since Hammerspoon just uses lua as a wrapper for Cocoa-Objective C calls, it might be possible to do this natively with AppleScript-ObjC.


(Phil Stokes) #4

Another subrole I’ve just noticed is AXSystemDialog, so you may want to add that (again, depending on what you’re looking for).

To filter out unwanted hits (e.g., the ‘Build Succeeded’ HUD style dialog from Xcode has AXSystemDialog role), you could add something like this immediately above the if fire == true then
line:

if anApp == "BBEdit" or anApp == "Xcode" then
		fire = false
	end