Unlocking a screen saver

Hi!

I’m trying to write a script for Salling Clicker, to unlock my computer when my phone comes in to range. Right now, the best I’ve got is this:

	on process entering proximity a_terminal
		tell application "System Events"
			set the process_flag to (not (exists process "ScreenSaverEngine"))
		end tell
		if the process_flag then
			return
		else
			tell application "System Events" to keystroke space
			delay 1
			tell application "System Events" to keystroke a
			tell application "System Events" to keystroke b
			tell application "System Events" to keystroke c
			tell application "System Events" to keystroke enter
			return
		end if
	end process entering proximity

It compiles fine, and when my phone comes in to range of the computer, the keystroke space seems to end the screensaver well enough. I expected the next few lines, then, to type “abc” in the password box, and enter it. Unfortunately, it’s not typing or entering anything. I don’t want to bother typing my password all the time, since if my phone is near my computer, then so am I. Any suggestions for making this script work?

Hi Bondy.

Your main problem seems to be that you’re trying to keystroke a sequence of variable names (a, b, c…) - rather than strings (“a”, “b”, “c”). There are also a couple of additional points about tell statements and keystrokes that you might like to note.

If you have several statements that target the same application, then you can abbreviate your code by using a compound tell statement (more commonly known as a tell block). So instead of saying:

… you can say:

Apart from cases where you may need to introduce, say, a short delay, a sequence of keystrokes can also be reduced to a single command by using an entire string:

tell application "System Events" to keystroke "abcdefg"

That said, I’d probably approach your script by starting at the top level with a password property - and then, at the beginning of your run handler, a statement that sets it:

property accountPassword : missing value

if accountPassword is missing value then set accountPassword to text returned of (display dialog "Please enter your account password:" default answer "" with hidden answer)

Later, in your ‘process entering proximity’ handler, you should be able to avoid most keystrokes - by using something like this:

on process entering proximity a_terminal
	tell application "System Events" to if exists process "ScreenSaverEngine" then
		keystroke space
		tell window "Authenticate" of application process "SecurityAgent"
			repeat until exists
				delay 0.1
			end repeat
			set value of text field 2 of group 1 to accountPassword
			click button "OK" of group 2
		end tell
	end if
end process entering proximity

Since this tests for the existence of the password dialog before entering the password, you should find it more responsive and reliable than using an arbitrary delay.

Edit: I see that, while I was writing this, Jacques beat me to it with a very similar approach. :slight_smile:

In addition to all this wisdom, you may want to avoid textual passwords in your scripts.
You can fetch a password with the following call to your keychain app (that Apple secretly repaired since OSX 10.4.3) :


to getPassw()
tell application "Keychain Scripting"
		launch
		tell current keychain to ¬
			tell (some generic key whose name is "Salling screensaverpass")
				return password
		end tell
end tell
end getPassw

assuming that you have earlier defined your password in the entry “Salling screensaverpass” in your current keychain

Thank you all very, very much for your help! I feel like such a fool for not catching that I should’ve been keystroking strings! I have the script working, as long as I use keystrokes to enter the password:

keystroke space
delay 1
keystroke "abc"
delay 0.1
keystroke return

Unfortunately, I can’t make this work using the “set value of text field 2 …” approach, either the way Jaques described it, or the way kai described it. I’ll paste the whole applescript below. Can any of you tell me what’s wrong with this?

property left_message : "Good Bye!"
property back_message : "Welcome Back!"

---

using terms from application "SEC Helper"
	
	on process leaving proximity a_terminal
		tell application "System Events"
			set the process_flag to (exists process "ScreenSaverEngine")
		end tell
		if the process_flag then
			return
		else
			tell application "Finder"
				activate
				beep
				set results to display dialog "Lost contact with phone. Do you really want to activate the screen saver? (will auto-activate in 5 seconds)" buttons {"Yes", "No"} default button "No" with icon caution giving up after 5
				
				if (gave up of results is true) or (button returned of results is "Yes") then
					tell application "SEC Helper"
						show screen message left_message duration 2.5
					end tell
					launch application "ScreenSaverEngine"
					return
				end if
			end tell
		end if
	end process leaving proximity
	
	on process entering proximity a_terminal
		tell application "System Events" to if exists process "ScreenSaverEngine" then
			keystroke space
			tell window "Authenticate" of application process "SecurityAgent"
				repeat until exists
					delay 0.1
				end repeat
				set value of text field 2 of group 1 to "abc"
				click button "OK" of group 2
			end tell
			tell application "SEC Helper"
				show screen message back_message duration 2.5
			end tell
		end if
		return
	end process entering proximity
end using terms from

This stops the screen saver and brings up the authentication window when my phone comes back in to range, but doesn’t enter the password.

Don’t feel bad about it, Bondy. Most of us are quite capable of little slips like that, believe me! :slight_smile:

Works here in OS 10.4.3. I’ve noticed several changes in UI scripting recently - so it may not work quite so well on an earlier system. What are you currently running?

Since the ‘keystroke space’ command is what causes the password dialog to appear, it’s not clear whether the script then fails because the “Authenticate” window isn’t recognised (causing us to get stuck in the repeat loop) - or because text field 2 of group 1 just can’t be set successfully.

You could try a variation, like:

set value of attribute "AXValue" of text field 2 of group 1 to "abc"

Failing that, you may have to revert to keystroke “abc” - which wouldn’t be so bad. However, if the problem is a failure to recognise the “Authenticate” window, that would be a pity… :confused:

( Bearing in mind that we’re testing here. For the final version, a more secure variation is worth considering.)

Good point, Jacques.

I guess it would be safer to use:

window 1 of application process "SecurityAgent"

… which seems to work for the various languages I’ve just tested it with.

so i guess this explains why a simple

   do shell script "killall ScreenSaverEngine"

doesn’t work, and i assume SecurityAgent is owned by root, so i can’t kill it;-) i’ll give the SecurityAgent passwd entry a try when i get home…

never got around 2 using keychain…if i don’t use passwds i forget 'em…but now i have a reason;-)

Model: 1.25ghz powerbook
AppleScript: 10.4.4
Browser: seamonkey
Operating System: Mac OS X (10.4)