OSX: Lock the screen programmatically - macos

I'm looking for a way to lock the user screen programmatically without putting the Mac asleep.
Right now, i'm able to trigger the lock screen with the kAESleep event but it's more a hack and it put the computer asleep.
Is it possible ?
Thanks

Configure the screensaver to require a password immediately after it starts, then start the screensaver programmatically. I have it programmed to a keyboard shortcut to help my Windows folks transition to using real computers ;).

The following AppleScript will do it for you. Note that because of security limitations of OSX, AppleScript pauses for five seconds before it executes an UI function, so it takes a small while to function. I'm using Quicksilver to bind it to a hotkey.
(As a bonus, this script will also pause a couple of your music players. Feel free to remove those lines.)
#
# Tell our noisy programs to shut up
#
tell application "Spotify"
pause
end tell
tell application "iTunes"
pause
end tell
#
# Lock up the screen without going to sleep. Needs that Keychain Access
# is set up properly.
#
tell application "System Events" to tell process "SystemUIServer" to click (first menu item of menu 1 of ((click (first menu bar item whose description is "Keychain menu extra")) of menu bar 1) whose title is "Lock Screen")
You will need to set up Keychain Access so that it has the lock icon on screen though.

I was successfully able to lock the screen on macOS in python with the following
import ctypes, ctypes.util
login = ctypes.CDLL( '/System/Library/PrivateFrameworks/login.framework/login' )
login.SACLockScreenImmediate()
I discovered this by scarce information on the Internet and trial-and-error. As far as I know, Apple doesn't document the SACLockScreenImmediate() function at all.
If anyone can find the official reference documentation for the "Login Framework" library, please drop it in the comments :)
Source
The is used in the BusKill app, which locks the screen when a magnetic breakaway connection in a USB Dead Man Switch is severed:
https://github.com/BusKill/buskill-app/tree/master/src/packages/buskill

Related

AppleScript tell application "System Events" extremely slow only on 1 account of my Mac

I'm baffled by this. Any AppleScript which uses tell application "System Events" runs slow only on 1 account of my Mac but fine on the other account.
Just as a simple example, tell application “System Events” to display dialog “Hello World” displays the dialog almost instantly on account 1, but will take up to 6 or 7 seconds to display the dialog on account 2.
EDIT: Just to clarify, As user3439894 mentioned in the comment below. I understand that display dialog doesn't need to be called by System Events. This issue has nothing to do with display dialog. I'm using it as a simple example to demonstrate the issue. As I mention below ANY code I call inside system events is slow (eg. sent frontmost to true, click menu items, etc.).
Its only system event calls though. A simple display dialog “Hello World” or any other code that does not involve system events will run fast on both accounts.
A few more notes:
It's not just display dialogs in tell application "System Events", it's ANY code I attempt to run in tell system events (e.g. click menu items, set frontmost to true, ect.). I'm just using the display dialog as a simple example.
The delay is actually inconsistent. For example, with the display dialog command, most of the time it takes about 6 or 7 seconds for the dialog to appear, but occasionally the dialog will appear instantly. Other times, the dialog will appear instantly but then clicking the "OK" button will cause a 6 or 7 second delay (with the beachball).
Both accounts on same Mac are admin accounts.
The delay occurs in script editor, osascript, or apple script applications.
I'm lost. Any ideas?
EDIT 2 - More clarifications based on comments:
I've been trouble shooting this for several days and at this point I'm fairly certain of the following:
This has NOTHING to do with my code or how I am calling the script. It also is not AppleScript in general, or the account being slow.
Scripts NOT involving tell application "System Events" run fine on both accounts. Both accounts are generally running fast.
It's specifically tell application "System Events"on ONE account.tell application "System Events"runs fine on one of my user accounts. The SAME exact script, called the EXACT same way is taking 6 to 7 even 10 seconds to run on the second user account on the same computer. Both accounts have admin access.
#TedWrigley provided several recommendations in the comments of my main post that allowed me to identify the issue. So full credit goes to him! Thank you #TedWrigley! I'm posting here and marking this as the correct answer incase others encounter an issue similar to this.
EDIT: It was a specific Elgato Stream Deck Plugin; the Zoom Plugin!
Booting in safe-mode allowed me to initially identify that Elgato Stream Deck Software (VERSION 4.9.2) I have installed appeared to be causing the issues. I don't understand why that was interfering with System Events because SE did not appear to have any issues in Activity Monitor and I have the Stream Deck Software on both accounts, but it was only causing issues with System Events on one account.
After un-installing and re-installing that software, AppleScripts calling tell application "System Events" was running as expected on both accounts...
UNTIL I re-installed my plugins. I discovered that is was not actually the Stream Deck application itself that was interfering with System Events but a specific plugin, the Zoom Plugin V2.1 11/16/20
https://lostdomain.org/stream-deck-plugin-for-zoom/. I only use this plugin on one account which is why I was only seeing the System Event issue on that account.

Allow JavaScript from Apple Events in Safari through Terminal Mac

I'm writing a program that executes do javascript in Safari. The only problem is that I'm trying to make the app give its self permission to do it. I'm trying to locate the file that handles the Safari developer preferences so that I can do this. Does anyone have any idea where this might be or how to change these settings?
It's in Safari's preferences plist at ~/Library/Preferences/com.apple.Safari.plist. The key you want is AllowJavaScriptFromAppleEvents. You can set it using defaults:
#to turn it on
defaults write -app Safari AllowJavaScriptFromAppleEvents 1
#to turn it off
defaults write -app Safari AllowJavaScriptFromAppleEvents 0
The virtual keyboard thing did not work for me. As StarPlayr at apple's develepoer forum has found out the problem is in something else.
For me problem occurred when i tried to do that on remote mac.
For some people plugging in a keyboard and mouse to the Server allowed to turn on JavaScript Apple Events in Safari and set the password.
However, for me that wasn't an option, so the next best thing is use an accessbility scripting feature and have the machine think a user is doing the clicks, allowing you to set the password:
-- The delays can be shorter, coordinates may vary
-- Best way to get the coordinates is with Apple screen capture (command-shift-3) from upper right to lower left (the coordinates will be shown)
-- if one spends the time, the click events can be converted to Accessibility AppleScript objects by capturing them as variables, or checking the events and using the events instead of the click coordinates
tell application "System Events"
tell application "Safari"
activate
end tell
delay 1
-- click develop menu (make sure its on first)
click at {430, 12}
delay 1
-- click Allow Javascript menu from Apple Events
click at {615, 615}
delay 1
-- Click the Allow Button
click at {1010, 386}
end tell

Accessing an Applescript from 2 different menus produces different results. Why?

I've got an application that has an embedded Script menu for running Applescripts. However, if you try to run scripts with certain functions (mostly UI related) they won't work unless you run them from the System script menu (in menu bar).
For example, if in theApplication you say :
tell application "System Events" to tell application process "theApp" to get all windows
it will return an empty list if run from the program's script menu, but 2 if run from the system script menu. I've also tried:
tell application "System Events"
tell application process "theApp"
set allElements to UI elements
display dialog (count of allElements)
end tell
end tell
-- returns 2 when run from System script menu but 0 when run from within theApp.
Also if you run from the Script Editor it will work fine. GUI scripting is enabled for the application in System Preferences, so I'm curious as to why this is happening, and any workarounds for it (other than run the script from the System Script menu)? The Dictionary shows Standard Suite so it should have access to windows...
Any ideas?
I believe you haven't provisioned the app in question to use assistive devices.
You should really open System Preferences, then click the button for "Security", then unlock, and click the button for Assitive Devices, (the blue icon with a white man), then drag your app onto it (reveal your app from its Dock menu), and permit it to control your machine, remember to lock the pane afterwards.
I can not guaranttee this to work, but it is certainly worth a try.

Positioning windows with applescript on dual monitors

I have 2 air applications that I wrote. They auto fullscreen after 10 seconds. Before then, they need to be sent to their proper displays. "app_1" needs to run on display 1, "app_2" needs to run on display 2.
Essentially, I have this code:
do shell script "cd /Applications/app_1.app/Contents/MacOS/ ; open app_1;"
which works for me flawlessly. Both apps are launched that way, and there is some code for ensuring that the apps weren't already open, and closing them if they were.
I tried to add in a script to position the app after it is launched:
do shell script "cd /Applications/app_1.app/Contents/MacOS/ ; open app_1;"
tell first window of application "app_1" to set bounds to {0,0,1920,1080}
This gives me an error:
app_1 got an error: Can't set bounds of window 1 to {0,0,1920,1080}
I tried adding a delay of a couple seconds before the set bounds, in case the application hadn't yet launched when the set bounds fired off, however this didn't change anything.
I also tried setting the bounds to something like {100,100,200,200} just to see if I had the screen coordinates wrong or something, but still the exact same error, only with the {100,100,200,200} instead of the original 1920x1080 coordinates.
Anyone have any insight on this? I've been trying to find the solution on google for a couple of hours now.
It sounds like your app isn't exposing the standard "window" class. I don't know if AIR apps are supposed to automatically take care of this and it's not working—if so, you'll want to debug that.
But another alternative is to use UI Scripting to control its windows externally. Instead of this:
tell first window of application "app_1" to set bounds to {0,0,1920,1080}
Do this:
tell application "System Events"
set position of first window of application process "app_1" to {0, 0}
set size of first window of application process "app_1" to {1920,1080}
end tell
However, this will only work if you've gone to the Universal Access pane of System Preferences and checked "Enable access for assistive devices" (or done the same via API, "sudo touch /var/db/.AccessibilityAPIEnabled", etc.).

How to tell if a menu item is 'checked'?

I'm building an Applescript that will scan my network every X minutes, checking for my house's Xbox360 or PS3 and enabling my Transmission BitTorrent client Speed-Limit Mode when either console is online.
Currently I can only Pause all transfers or resume all transfers using applescript, as there are separate key-commands for start/stop transfer. I want it to go into speed-limit mode though, not stop completely.
My issue is that the Speed-Limit (Turtle) mode is the same key to turn it on/off. If anyone touches the speed-limit manually, it will be out of sync and will actually turn speed-limit off when the consoles come online. Also if one console comes online, the speed-limit will come on, but then if the other console comes on, the limit will be turned off.
The menu item becomes 'checked' when the speed-limit is active, but I do not know how to test for this. There was nothing in the applescript dictionary for the transmission app.
How can I determine whether a menu item is 'checked'(It even shows an actual check-mark) in Applescript?
[Edit:] I'm currently trying to figure out how to turn the Speed-Limit on via RPC, rather than trying to script it using the GUI or keycommands, since the developers don't provide any applescript access.
http://trac.transmissionbt.com/browser/trunk/doc/rpc-spec.txt
I had the exact same issue, and finally figured out how to check if Transmission's Speed Limit menu item is checked (and you could easily modify this to check for menu items in other applications). This has been dead for almost a year now, but hopefully this helps.
tell application "Transmission" to activate
tell application "System Events"
tell process "Transmission"
set speedLimitCurrentlyOn to (value of attribute "AXMenuItemMarkChar" of menu item "Speed Limit" of menu "Transfers" of menu bar 1 as string) ≠ ""
display dialog "Speed Limit On: " & speedLimitCurrentlyOn
end tell
end tell
PS:
I adapted this from the AppleScript here: http://mac.softpedia.com/progDownload/Transmission-Auto-Speed-Limit-Download-60275.html
What information you are able to divine from any given application via AppleScript is entirely up to said application's developer. If Transmission doesn't define any way for you to determine this state, then you're not going to be able to do so with any degree of reliability.
It would make far more sense to invest $40-$50 in a router with quality of service controls that would allow you to prioritize your network traffic by port or by device.

Resources