Turning on/off access for assistive devices

I have a script that uses GUI scripting, and attempts to turn on and off access for assistive devices. It seems a bit quirky, sometimes working, sometimes not. The not condition can range from an error message (Can’t continue <>) to just not doing anything. Sometimes (if Enable access for assistive devices is not already checked in System Prefs) it asks for a password, sometimes not. Needs to work on Snow Leopard and later.

If the user has access already enabled it’s flawless (so far).


global AppWasOpen, GUIScriptingWasEnabled, previousText

on run
    -- When the script starts up, note if App is running and GUI Scripting is enabled.
    tell application "System Events"
		setAppWasOpen to (application process "App" exists)
		set GUIScriptingWasEnabled to (UI elements enabled)
	end tell
	if not AppWasOpen) then
		tell application " App" to activate
		tell application "System Events"
			set  AppWasOpen to (application process "App" exists)
		end tell
	end if
	-- Enable GUI Scripting if necessary and give the 'previousText' variable an initial value.
	switchGUIScripting(true)
	set previousText to ""
end run
.
.
.
on switchGUIScripting(onOff) -- 'onOff' is 'true' for on, 'false' for off.
	if (not GUIScriptingWasEnabled) then
		tell application "System Events"
			activate
			set UI elements enabled to (onOff)
		end tell
	end if
end switchGUIScripting

-- When this applet's told to quit, restore the previous GUI Scripting state before it does.
on quit
	tell application "App2" to quit
	switchGUIScripting(false)
	continue quit
end quit

Hello.

This problem isn’t necessarily caused by UI scripting: maybe you should try to reference any handlers in your app by the keyword my first. You will get the can’t continue error, also if Applescript can’t find your handlers.

Please do try that, and let me still have the dream of not having users to enter passwords for enabling ui scripting uncrushed. :slight_smile:

Also: please pass GUIScriptingWasEnabled as a parameter to switchGUIScripting, and remove the activation of System Events, it is superfluos as System Events is a background only application.

I hope this helps.

Thanks.

I’m not sure what you mean by handlers and how to apply my. Could you give me an example?

We share a dream…

Is this right for your other suggestions?


 -- Enable GUI Scripting if necessary and give the 'previousText' variable an initial value.
   switchGUIScripting(GUIScriptingWasEnabled)
.
.
.
on switchGUIScripting(onOff) -- 'onOff' is 'true' for on, 'false' for off.
        set UI elements enabled to (onOff)
end switchGUIScripting

Hello.

I meant that within your run handler for instance, when you call switchGUIScripting or whatever other handler you use, you should prepend them with my so it reads my switchGUIScripting(.)

The other thing, instead of writing application “App” and application “App2”, me is a more concise form: If it is the current application, it is of course ok, if you are addressing two other different applications.

tell me to activate

tell me to quit etc.

There are some small errors/typos in the script you posted above, for instance “if not AppWasOpen)”

I suggest that you really try to run it from within the AppleScript editor, as that is a much more pleasant place to do debugging, as you can follow the execution trace in the console pane of the script window. It should work (almost ) as it does when compiled as an application.

When you have done that, and then runs it as an application, please come back, repost your code, and we’ll take it from there.

Thanks,

Here’s the whole script. App2 is the GUI one. On my box it now consistently runs asks for the password, quits and asks for the password again. Normal. I’m going to include a recommendation that users just tun accessibility on and leave it, until I can make it scriptable.

There is no functional advantage to using ‘me’ is there? seems like wit two apps, it would get confusing.


property checkInterval : 3 -- Number of seconds between checks. Adjust to requirement.

global AppWasOpen, GUIScriptingWasEnabled, previousText

on run
	-- When the script starts up, note if RUMlog is running and GUI Scripting is enabled.
	tell application "System Events"
		set AppWasOpen to (application process "RUMlog" exists)
		set GUIScriptingWasEnabled to (UI elements enabled)
	end tell
	if not ( AppWasOpen) then
		tell application " App" to activate
		tell application "System Events"
			set  AppWasOpen to (application process " App" exists)
		end tell
	end if
	-- Enable GUI Scripting if necessary and give the 'previousText' variable an initial value.
	my switchGUIScripting(true)
	set previousText to ""
end run

on idle
	-- Each time the script's polled by the system, check that RUMlog's open.
	tell application "System Events" to set RUMlogIsOpen to (application process "RUMlog" exists)
	
	if (RUMlogIsOpen) then
		--tell application "LRotor" to launch
		-- If RUMlog's open, update the "was open" flag to indicate that it's been open while the script's been running.
		set  AppWasOpen to true
		-- Get the latest value for 'beam'.
		tell application " App"
			set hdg to getHeading
			set beam to hdg as string
		end tell
		if ((count beam) < 3) then set beam to text -3 thru -1 of ("000" & beam)
		
		-- If it's changed since the last check, enter it into RotorDCU and keep it for later checks.
		if (beam is not previousText) then
			--display dialog "Opening Rotor" buttons {"OK"}
			tell application "App2" to activate
			--activate application "App2"
			tell application "System Events"
				
				set startTime to current date
				repeat until exists (text field 1 of window "App2" of application process " App2")
					if (current date) - startTime is greater than 3 then
						error "Could not find text field 1 of window App2 of application process  App2r"
						exit repeat
					end if
					delay 0.2
				end repeat
				tell application process " App2"
					try
						set value of text field 1 of window " App2" to beam
					end try
				end tell
			end tell
			set previousText to beam
		end if
		
		-- Request the next 'idle' event in 'checkInterval' seconds' time.
		return checkInterval
	else if ( AppWasOpen) then
		--  Appwas open at the last check, but isn't now. Tell this script applet to quit.
		quit
		-- It'll actually quit on the next idle event, so request a short interval.
		return 1
	end if
end idle

-- Unless GUI Scripting was already on when the script started to run, turn it on or off as per the parameter.
on switchGUIScripting(onOff) -- 'onOff' is 'true' for on, 'false' for off.
	tell application "System Events"
		--display dialog "GUIScripting is: " & GUIScriptingWasEnabled buttons {"OK"}
		set UI elements enabled to (onOff)
	end tell
end switchGUIScripting

-- When this applet's told to quit, restore the previous GUI Scripting state before it does.
on quit
	--display dialog "Quitting" buttons {"OK"}
	tell application " App2" to quit
	my switchGUIScripting(false)
	continue quit
end quit

Hello.

I want you to try something in order to circumvent the problem, it is at least worth a try:

Save this script as an app.

set a to path to resource "gui.scpt"

tell application "AppleScript Runner"
	run script a
end tell


Save this script somewhere, and the move it to the Resources folder inside the app as gui.scpt

tell application "System Events"
	set UI elements enabled to true
end tell

Run the app with the script in the Contents:Resources folder, and see if it works, I really hope it does. I have SnowLeopard, so I can’t really test this properly for you. :slight_smile:

And please report back.

I hopes this works, as I have read this article and I see no reason, that gatekeeper or anything else should kick in, as long as the app is run on the users machine (yours for now).

Interesting concept, but no joy, it still triggers the prompt. I tried it from Library\Scripts and from Library\Application scripts. I agree that the article says it will work, but it doesn’t. I’m a hobbyist and I’m not gonna pay Apple to be able to do this.

So what’s your take on using ‘me’ in my script?

Hi.

I see you’re still fooling around with the script from your queries of 12th and 23rd February. Have you really renamed the applications " App", “App2”, and " App2"?

It seems likely that the “Can’t continue «event AEtsGHdg»” error comes from the ‘set hdg to getHeading’ line and that application " App" has never heard of ‘getHeading’. But then ‘getHeading’ wouldn’t have been compiled as an event token. :confused:

Other errors may come from the casual juxtaposition of the strings “App2” and " App2".

Hello.

Did I mention I was stubborn?

Try saving this as an app, and see if it runs without the password prompt, and see if you then get the error dialog I have created.


# Save this as an app, and run it and see what happens, with your ui elements disabled.
set defaulted to false
try
	tell application "System Events"
		set UI elements enabled to true
	end tell
on error
	display alert "You'll eventually have to enter the password to run this app, hopefully you'll have to do it only once"
	set defaulted to true
end try
if not defaulted then
	display alert "We do our stuff here...."
end if

Now I am anxious. :slight_smile:

(I also like to know if you have to reenter the password, if you entered it once.

Edit
My general take on using my and me in scripts and applications, is to use them as often as necessary to be able to reference different objects. I use them a bit more liberally in applications, as I can’t see what is going on runtime, and the execution environment is a bit different from running it in the editor.

Seeing Nigel’s comment. :slight_smile: Let me add to that, if those apps are applications in reality, then you have maybe jailbroken them, or done something else to them, especially if there is a mismatch between that name, and the name in the plist file. According to Nigel, it is a probability that you have managed to do that.

I’d still like you to try my applet, and see what kind of result it gives. :slight_smile:

No, they’re not really named App or App2. That was just obsfucation. :slight_smile:

I agree that’s the likely source of the error. Assuredly App has heard of ‘getHeading’, only one user is reporting the error. My theory is that it’s tied up with trying to turn on accessibility, but I can’t reproduce the error on my box. The difference in “App2” and " App2" is a typo, not in the real script. I can’t help but think of Gatekeeper in terms of the movie Ghostbusters…

EDIT:

User has access enabled, sent another screen shot of error, and it hit me. He may be running an older version of the app that doesn’t expose ‘getHeading’. I just asked him…

Stubborn is a ™GoodThing.

Starting with access off, a password is still needed, and I get the “We do our stuff here…”.

Leaving access enabled and running the script again, no password prompt, and I get the “We do our stuff here…” dialog.

The error message didn’t display either way. Maybe one solution would be once the option has been set, don’t turn it off when the script quits. I had turned it on manually when I started this project, and forgot about it. I can’t see that leaving it on has caused any problems.

I don’t think there has been a jailbreak, nor has the sandbox been fouled. The names of the apps have been changed to protect the innocent… Sorry if that caused a problem.

I get the "my’ usage, ‘me’ is still unclear. Using my script, can you show me an example?

Hello.

me is the application, which should be the same as the current application when you execute the main.scpt in an applet, but may differ from the active application/ application process whose frontmost is true.

The current application is the parent of the AppleScript “object” you are using, fx. AppleScript Editor when you run a script from there or AppleScript Runner when you execute it via it, the Applet when the script is run from an applet. Me always refers to the current script.

A contrived example:
All this is described in the AppleScript Language Guide

on run
	tell application "Finder"
		activate
	end tell
	tell me to activate
	display alert "I'm in the foreground of the events"
	tell application "Finder"
		tell me to quit
	end tell
end run

on quit
	continue quit
end quit

I allways leave the UI scripting on, as I believe that you have to do some extra things like acknowledging in order to run remote scripts, and use ard. I rip out the ard frameworks as I see fit anyway. :slight_smile: ( I don’t take any responsibility for an consequences of attempting to remove the ard frameworks.)

If it’s someone other than yourself getting the error, then it’s their application which isn’t recognising the «event AEtsGHdg» event compiled into the script. Do they perhaps have an older (or even newer) version of the app where ‘getHeading’ isn’t implemented?

I can’t see anything in your script which requires you to worry about ‘my’ or ‘me’.

Hello.

I was thinking in the same orbit as Nigel: you must have your users to physically click on any new application, in order to register that version. When you deploy new applets/applications, you must also increase the number in the version string in the property list file in the app(let). Then OS X will see to that the latest version is in use.

You can also check the version of the Application from your script, but I think it delivers the short version string.

set verApp2 to version of application "App2"

User has access enabled, sent another screen shot of error, and it hit me. DOH! He may be running an older version of the app that doesn’t expose ‘getHeading’. I just asked him…

Re ‘my’ and ‘me’ I think McUSerII was doing some extra tutoring.

That answered a question (registration) I had some time back when something got scrambled and the script was opening an older version of the app. I couldn’t find what the link was. It was opening from the folders that Xcode puts the built prg. in.

Yep, that line returns 5.1.3 which is correct. I think the short and long version are the same in this case. That would be a nice addition.

Hello

I just discover this thread.

For years, I use :


my activateGUIscripting()

#=====

on activateGUIscripting()
	(* to be sure than GUI scripting will be active *)
	tell application "System Events"
		if not (UI elements enabled) then set (UI elements enabled) to true
	end tell
end activateGUIscripting

#=====

If GUIScripting was not enabled, a password is asked.
It’s no longer asked on following calls.

Yvan KOENIG (VALLAURIS, France) mardi 26 mars 2013 17:00:50

I don’t think the check is needed. If it’s already on, I think it’s just called with no result. If it’s set manually, the script doesn’t turn it off either.

OK, just heard from the user, he did have an older version, got the new one and SHAA ZAAAAAAAM! It works.

Thanks McUsrII, Nigel and Yvan. As always, I learned something.