Search code examples
macosapplescriptshortcut

How to create an Applescript to set a Keyboard shortcut?


If someone could give me a hand, I'm trying to automatize the creation of keyboards shortcuts for some Services.
What I got so far is

tell application "System Preferences"
    activate
    set current pane to pane id "com.apple.preference.keyboard"
    delay 1
    tell application "System Events"
        click radio button "Shortcuts" of tab group 1 of window "Keyboard" of application process "System Preferences"
        delay 1
        select row 6 of table 1 of scroll area 1 of splitter group 1 of tab group 1 of window 1 of application process "System Preferences"
        set value of text field 1 of UI element "My Service Name" of row 59 of outline 1 of scroll area 2 of splitter group of tab group 1 of window 1 of application process "System Preferences" to "⌥⌘1"
    end tell
end tell

But now I'm stuck, what I'm not being able to do is:

  • This ...of row 59... is not good, I would like to use the name of shortcut instead this index. I know the name of shortcut is in UI element "My Service Name" but I don't know how to do a nested selection, for example instead ...of row 59... do something like of row (where UI element "My Service Name")
  • This script only works only if the Service has an previous shortcut, if the shortcut is none not works at all

Does someone have a hint how can I solve this?

If is there some other way to create shortcut without the applescript will be welcome

Thank you all in advance.


Solution

  • I've restructured your script a bit, because I prefer the hierarchical 'tell block' structure (which I find it easier to read and follow), and I've put it all into a handler to generalize it. But that aside, the trick is to use where searches to look down the UI structure and find identifiable features (N.B, where is a synonym for the more conventional whose). See the comments in-script. Note that I am changing the "Show Finder search window" row in the "Spotlight" section of the keyboard shortcuts preferences, but by changing the values of the handler call you can change any preference.

    To make this work, you need to know which section your service falls under, and the name of the service as it appears in the list. If you put in a text string for new_val it will treat it as though you had typed the first letter; if you put in an integer it will treat it as a key code, allowing you to use non-printing characters and function keys for shortcuts. See: list of key codes.

    This script has been corrected to fix a couple of errors, and to accommodate both the hierarchical structure of the 'Services' section and and the ability to add a new shortcut by clicking the 'Add Shortcut' button. Note that if you're adding short-cut for the first time, the UI will still show the 'Add Shortcut' button until you select a different row. This is true even when adding shortcuts manually, so it's a limitation of the GUI, not the script.

    -- sets the 'Send Message' shortcut to cmd-opt-A
    my change_shortcut("Services", "Text", "Send Message", "a", {"command", "option"})
    -- sets the 'Call' service shortcut to cmd-F6
    my change_shortcut("Services", "Text", "Call", 97, {"command"})
    
    on change_shortcut(shortcut_region, section_name, shortcut_title, new_val, special_key_list)
        tell application "System Preferences"
            activate
            set current pane to pane id "com.apple.preference.keyboard"
            delay 1
            tell application "System Events"
                tell process "System Preferences"'s window "Keyboard"'s first tab group
                    click radio button "Shortcuts"
                    tell first splitter group
                        set sidebar_obj to first table of first scroll area
                        tell sidebar_obj
    
                            (* 
                                this looks to find the first row in the sidebar that contains a static text 
                                element with the value of `shortcut_region`
                            *)
    
                            set sidebar_entry to first row where (its first static text's value is shortcut_region)
                            select sidebar_entry
                        end tell
                        set outline_obj to first outline of second scroll area
                        tell outline_obj
    
                            (* 
                                if the shortcut outline view is arranged in groups, this section 
                                finds the correct group and make sure its disclosure triangle is 
                                opened, exposing the settings within
                            *)
    
                            if section_name is not "" and section_name is not missing value then
                                set wanted_section_row to first row where (its last UI element's name is section_name)
                                tell wanted_section_row's second UI element
                                    set disclosure_tri to first UI element whose role description is "disclosure triangle"
                                    if disclosure_tri's value is 0 then click disclosure_tri
                                end tell
                                delay 0.5
                            end if
    
                            (* 
                                this looks to find the first row in the outline that contains two 
                                UI elements (the row's cells) the second of which contains a static text 
                                element with the value of shortcut_title
                            *)
    
                            set wanted_entry to first row where (its last UI element's name is shortcut_title)
                            tell wanted_entry
                                select
                                set new_shortcut_flag to false
                                tell second UI element
                                    if exists button "Add Shortcut" then
                                        click button "Add Shortcut"
                                        set new_shortcut_flag to true
                                    end if
                                    UI elements
    
                                    -- set up a list of special keys
                                    set special_keys to {}
                                    if special_key_list contains "command" then set end of special_keys to command down
                                    if special_key_list contains "control" then set end of special_keys to control down
                                    if special_key_list contains "option" then set end of special_keys to option down
                                    if special_key_list contains "shift" then set end of special_keys to shift down
    
                                    -- opens the text field for editing, then write or keycode in the text
                                    tell first text field
                                        if not new_shortcut_flag then perform action "AXConfirm"
                                        if class of new_val is text then
                                            keystroke new_val using special_keys
                                        else
                                            key code new_val using special_keys
                                        end if
                                    end tell
                                    -- select the cell to submit the result
                                    select
                                end tell
                            end tell
                        end tell
                    end tell
                end tell
            end tell
        end tell
    end change_shortcut