How to stop the launch agent from repeatedly launching a given AppleScript
I'm trying to create a launch agent, which launches an AppleScript whenever a mouse is connected. Similar to these two questions:
- LaunchEvents key unrecognized in launchd plist (detecting USB device)
- Execute an application on Mac OS X when a particular type of USB device is connected?
However, once I load my launch agent (via launchctl load
), it keeps getting started every 5-or-so seconds. How do I ensure that the agent runs only once, when the mouse is connected?
Here is my agent (plist):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<false/>
<key>Label</key>
<string>com.automations.switchscrolldirection</string>
<key>ProgramArguments</key>
<array>
<string>osascript</string>
<string>/Users/lirik/Documents/Automation/SwitchScrollDirectionOnMouseEvent.scpt</string>
</array>
<key>LaunchEvents</key>
<dict>
<key>com.apple.iokit.matching</key>
<dict>
<key>com.apple.device-attach</key>
<dict>
<key>idProduct</key>
<integer>49277</integer>
<key>idVendor</key>
<integer>1133</integer>
<key>IOProviderClass</key>
<string>IOUSBDevice</string>
<key>IOMatchStream</key>
<true/>
<key>IOMatchLaunchStream</key>
<true/>
</dict>
</dict>
</dict>
</dict>
</plist>
The AppleScript in question:
on gamingMouseIsAttached()
tell application "System Preferences"
activate
set current pane to pane "com.apple.preference.mouse"
end tell
tell application "System Events" to tell process "System Preferences"
repeat until exists checkbox 1 of window "Mouse"
end repeat
tell checkbox 1 of window "Mouse" to if value is 1 then click
end tell
tell application "System Preferences" to quit
end gamingMouseIsAttached
on TrackpadIsAttached()
tell application "System Preferences"
activate
set current pane to pane "com.apple.preference.trackpad"
end tell
tell application "System Events" to tell application process "System Preferences"
repeat until exists checkbox 1 of tab group 1 of window "Trackpad"
end repeat
tell checkbox 1 of tab group 1 of window 1 to if value is 0 then click
end tell
tell application "System Preferences" to quit
end TrackpadIsAttached
tell current application
delay 15
set internalTrackpad to (do shell script "system_profiler SPUSBDataType | awk '/Trackpad:/ { print \"Internal Trackpad\" }'")
set gamingMouse to (do shell script "system_profiler SPUSBDataType | awk '/Gaming Mouse G502:/ { print \"Gaming Mouse\" }'")
if gamingMouse is equal to "" then
if internalTrackpad is equal to "Internal Trackpad" then
my TrackpadIsAttached()
return
end if
end if
if gamingMouse is equal to "Gaming Mouse" then
my gamingMouseIsAttached()
return
end if
end tell
Solution 1:
The answer is usually that you need to call xpc_set_event_stream_handler.
I found this amazing utility that will call xpc_set_event_stream_handler to remove the event from the queue, and then call your desired application. It allowed me to solve the problem you are having without writing/compiling any code. Check out github.com/snosrap/xpc_set_event_stream_handler and have it then call your osascript. Should solve your problem.