I have a colleague who needs to toggle the settings for Control and Command keys, basically switching them each time the script is run. I have written a proof-of-concept script below which uses the System Preferences UI, and it seems to work OK, at least in macOS 10.11.6. I’m not sure if it will work with Sierra.
But I hate using UI scripting, unless there is no alternative.
So,
What is Best Method to Set System Preferences Modifier Keys?
Is there an ASObjC or Shell Script method that will set the modifier keys directly, without using the UI? I have done extensive searching of the Internet, and have not found any.
Screenshot of SP Keyboard Panel
This is what I’m trying to change.
If not, then I have some questions about UI scripting, but I’ll wait to hear from you guys first. Hopefully there is another solution.
AppleScript UI Scripting of System Preferences
(*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Example to Show How to ReMap Control Key to Command Key
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
• Works in El Capitan
* Untested in Sierra
*)
use AppleScript version "2.5" -- macOS 10.11.6+
use framework "Foundation"
use scripting additions
set frontApp to path to frontmost application as text
tell application "System Preferences" to activate
set elapTime to my pauseUntilWin("System Preferences", "System Preferences", 1)
tell application "System Events"
tell process "System Preferences"
click button "Keyboard" of scroll area 1 of window "System Preferences"
set elapTime to my pauseUntilWin("Keyboard", "System Preferences", 1)
log elapTime
tell window "Keyboard"
repeat until (button "Modifier Keys…" of tab group 1) exists
delay 0.1
end repeat
click button "Modifier Keys…" of tab group 1
repeat until (sheet 1) exists
delay 0.1
end repeat
tell sheet 1 -- (modifier key list)
--- TOGGLE CONTROL KEY Between CONTROL & COMMAND KEY CODE ---
tell pop up button "Control (⌃) Key:"
set ctrlVal to value
set numDown to 3 -- for Command
if (ctrlVal contains "Command") then set numDown to 1 -- for Control
set newKeyMap to item numDown of {"Control", "", "Command"}
perform action "AXShowMenu"
delay 0.5 -- the "delay until exists" method doesn't work for this
### It should work with these menu items, but I get errors ###
(*
--tell menu 1
-- --set menuList to title of every menu item
--
--
-- tell menu item 4 -- "⌘ Command"
-- --perform action "AXPress"
-- set menuTitle to title
-- end tell
--end tell
*)
### So I was forced to use Key Codes to Move with Arrows ###
--- Move Selection to TOP Menu Item ---
key code 126 using {option down} -- UP Arrow
--- TOGGLE Control Key ---
repeat with iK from 1 to numDown
key code 125 -- DOWN Arrow
delay 0.1
end repeat
key code 36 -- return
end tell -- pop up button "Control (⌃) Key:"
click button "OK" -- on sheet 1 (modifier key list)
end tell -- sheet 1 -- (modifier key list)
end tell -- window "Keyboard"
end tell -- "System Preferences"
end tell -- "System Events"
tell application "System Preferences" to quit
tell application frontApp
set msgStr to "CONTROL Key has been mapped to: " & newKeyMap
set msgTitleStr to "Remap of Modifier Keys"
display dialog msgStr with title msgTitleStr
end tell
on pauseUntilWin(pWinTitle, pProcessName, pMaxTimeSec)
local startTime, elapTime, errMsg
set startTime to current application's NSDate's |date|()
tell application "System Events"
repeat until window pWinTitle of process pProcessName exists
if ((startTime's timeIntervalSinceNow()) > pMaxTimeSec) then
set errMsg to "Max Time of " & pMaxTimeSec & " exceeded waiting for:" & LF & ¬
"Window: " & pWinTitle & LF & "Process: " & pProcessName
log errMsg
error errMsg
end if
delay 0.1
end repeat
--- Make Sure Window is Fully Defined ---
set uiElem to UI elements of window pWinTitle of process pProcessName
end tell
set elapTime to (-(round ((startTime's timeIntervalSinceNow()) * 100)) / 100.0)
return elapTime
end pauseUntilWin