hammerspoon
hammerspoon copied to clipboard
How do I enable/disable sticky keys programmatically?
I want to disable sticky keys on certain apps. To do so, I need a way to programmatically toggle the sticky keys settings. Is there a way to do this?
Here is the setting in the macOS GUI, for reference:
Related:
-
https://apple.stackexchange.com/questions/468312/how-do-i-enable-disable-sticky-keys-programmatically
-
https://apple.stackexchange.com/questions/81523/disable-sticky-keys-only-while-certain-applications-have-focus
Pressing shift for five times quickly toggles this setting. I wonder if doing that via Hammerspoon would work. How can I press the shift key alone?
hs.eventtap
can emit keystrokes of your choice, so you could try that, but macOS may not consider it for the accessibility shortcut.
I tried doing this (with various delays between events), but the system didn't seem to pick it up:
for i=1,5 do
hs.eventtap.event.newKeyEvent(hs.keycodes.map.shift, true):post()
hs.timer.usleep(1000)
hs.eventtap.event.newKeyEvent(hs.keycodes.map.shift, false):post()
hs.timer.usleep(1000)
end
Edit: I also tried:
for i=1,5 do
local event = hs.eventtap.event.newEvent()
event:setType(hs.eventtap.event.types.flagsChanged)
event:setFlags{shift=true}:post()
event = hs.eventtap.event.newEvent()
event:setType(hs.eventtap.event.types.flagsChanged)
event:setFlags{}:post()
end
Another option which does seem to work is to use hs.axuielement
to click the checkbox for it in System Preferences. Here's an example of how to do that, adapted from some code from my config that toggles Mouse Keys:
local function shellArg(x)
return [[']] .. x:gsub([[']], [['\'']]) .. [[']]
end
local function stickyKeysAreOn()
return (hs.execute[[defaults read com.apple.universalaccess stickyKey]]):match('(%d+)') == '1'
end
local function setStickyKeys(enabled)
if stickyKeysAreOn() == enabled then return end
hs.execute('osascript -e '..shellArg[[
tell app id "com.apple.systempreferences"
reveal anchor "Keyboard" of pane id "com.apple.preference.universalaccess"
end
]])
hs.axuielement.applicationElement(hs.application.get 'com.apple.systempreferences'):elementSearch(function(msg, results)
local cb = results[1]
if (cb.AXValue == 1) ~= enabled then
cb:doAXPress()
end
end, hs.axuielement.searchCriteriaFunction{
attribute = "AXIdentifier",
value = "UA_StickyKeys_Checkbox"
}, {count = 1, depth = 4})
end
-- example:
setStickyKeys(true)
Original version for Mouse Keys
local function shellArg(x)
return [[']] .. x:gsub([[']], [['\'']]) .. [[']]
end
local function mouseKeysAreOn()
return (hs.execute[[defaults read com.apple.universalaccess mouseDriver]]):match('(%d+)') == '1'
end
local function setMouseKeys(enabled)
if mouseKeysAreOn() == enabled then return end
hs.execute('osascript -e '..shellArg[[
tell app id "com.apple.systempreferences"
reveal anchor "Alternate_Pointer_Actions" of pane id "com.apple.preference.universalaccess"
end
]])
hs.axuielement.applicationElement(hs.application.get 'com.apple.systempreferences'):elementSearch(function(msg, results)
local cb = results[1]
if (cb.AXValue == 1) ~= enabled then
cb:doAXPress()
end
end, hs.axuielement.searchCriteriaFunction{
attribute = "AXTitle",
value = "Enable Mouse Keys" -- depends on the selected language
}, {count = 1, depth = 4})
end
-- example:
setMouseKeys(true)
(I'm hs.execute
ing osascript
instead of just using hs.osascript.applescript
in order to avoid #1980.)