MacOS – Toggling screensaver password with script

applescriptmacosscreensaver

I am using a rather old application called Proximity to trigger applescripts when my phone goes in and out of bluetooth range of my mac. Along with other tasks, I want to secure my laptop when the phone goes out of range (enable screensaver and password), then disable the password requirement when my phone comes back in to range.

Prior to 10.9

I had this working (mostly) in OS 10.8 and earlier. When my phone went out of range, I could run:

do shell script "defaults -currentHost write com.apple.screensaver askForPassword -int 1"
do shell script "/Users/Chris/Library/Scripts/Proximity/notifyScreensaver"

tell application "System Events"
    set ss to screen saver "Soundstream"
    start ss
end tell

The notifyScreensaver is a compiled C program that makes the screensaver reread the password requirement preferences (from this forum post).

This would enable the requirement for a password, and then immediately run the screensaver. This was the correct behavior for if my laptop was in a public environment. However, when at home, I didn't want to have to type in password everytime I walked out of the room and came back in a minute later. So adding another layer of complexity:

do shell script "defaults -currentHost write com.apple.screensaver askForPassword -int 1"
do shell script "/Users/Chris/Library/Scripts/Proximity/notifyScreensaver"

set ssid to getWifiSSID()
if ssid is equal to "RouterName" then
    (* if at home, only enable password requirement without triggering screensaver *)
else
    (* if not at home, lock screen immediately *)
    tell application "System Events"
        set ss to screen saver "Soundstream"
        start ss
    end tell
end if

on getWifiSSID()
    set theWiFi to do shell script "wifi=`/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | awk '/ SSID/ {print substr($0, index($0, $2))}'`
echo $wifi
"
    return theWiFi
end getWifiSSID

Using this, when I'm at home I only need to type in my password if my phone is out of range AND if my computer has been idle for long enough to trigger the screensaver timeout (~20 minutes).

When my phone came back in to range I would run:

do shell script "defaults -currentHost write com.apple.screensaver askForPassword -int 0"
do shell script "/Users/Chris/Library/Scripts/Proximity/notifyScreensaver"

If the screensaver was already running, one would still need to type in the password to unlock the computer, but the password would not be required if the screensaver was started again later.

There was a bit of a glitch here: occasionally (I believe when there was no user input between the time the out-of-range script ran and the in-range script ran, and the screensaver had been enabled), the screen would just be completely black instead of showing the password prompt to unlock the computer. However in this case I could tab into the password field and type the password blindly to unlock the computer.

In 10.9

The most significant change I've encountered in 10.9 occurs when the password and screensaver are enabled and then the password is disabled, without any user input in between. When I then come back to unlock the computer, the screensaver does not require a password and immediately jumps back to the desktop. However, the keyboard is still trapped by the screensaver: I can interact with programs with the mouse, but any keystrokes just cause a warning alert sound ("Funk" from the standard alerts).

A minimum example that causes this behavior is:

do shell script "defaults -currentHost write com.apple.screensaver askForPassword -int 1"
do shell script "/Users/Chris/Library/Scripts/Proximity/notifyScreensaver"

tell application "System Events"
    set ss to screen saver "Soundstream"
    start ss
end tell

delay 5

do shell script "defaults -currentHost write com.apple.screensaver askForPassword -int 0"
do shell script "/Users/Chris/Library/Scripts/Proximity/notifyScreensaver"

The main way I've found to get out of this semi-locked state is to re-enable the password requirement and rerun the screensaver, and then enter the password manually.

The most ideal behavior (in my opinion) would be to lock my computer as soon as my phone goes out of range, then automatically unlock it (without a requirement for typing in a password) when my phone comes back in to range. However, since earlier OS versions I have been working under the assumption that user input is required to unlock the computer after the screensaver and password requirement have been engaged. With this constraint, the desired behavior is just to restore the functionality that was present prior to 10.9 – being able to type in the password to unlock the computer when back in range, but not require a password again until the phone goes out of range.

Any suggestions on how to accomplish this?

Best Answer

The same thing happens to me in 10.9. I also tried changing require password to wake of security preferences and putting displays to sleep instead of starting a screen saver:

tell application "System Events"
    set require password to wake of security preferences to true
    --start screen saver "Random"
    do shell script "pmset displaysleepnow"
    delay 5
    set require password to wake of security preferences to false
end tell

Neither of them helped though.

You might log out to the fast user switching screen instead of locking the screen though:

/System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -suspend