【问题标题】:How to create an Applescript to set a Keyboard shortcut?如何创建 Applescript 来设置键盘快捷键?
【发布时间】:2020-05-26 08:31:49
【问题描述】:

如果有人可以帮助我,我正在尝试为某些服务自动创建键盘快捷键。
到目前为止我得到的是

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

但现在我被卡住了,我无法做的是:

  • 这个...of row 59...不好,我想用快捷方式的名字代替这个索引。我知道快捷方式的名称在 UI element "My Service Name" 中,但我不知道如何进行嵌套选择,例如 ...of row 59... 执行类似 of row (where UI element "My Service Name") 的操作
  • 此脚本仅在 服务 有以前的快捷方式时才有效,如果快捷方式没有,则根本不工作

有人提示我该如何解决这个问题?

如果有其他方法可以在没有applescript的情况下创建快捷方式,欢迎

提前谢谢大家。

【问题讨论】:

    标签: macos applescript shortcut


    【解决方案1】:

    我知道的唯一一种可以使用 UI 脚本系统偏好设置 > 键盘 > 快捷方式的方法strong> > Services(或Shortcuts下的任何其他类别)基本上模拟了手动执行时会发生的所有步骤。这就是为什么我只在没有其他方法来完成手头的任务时才使用 UI 脚本

    由于在您的 代码 中,您使用的是 select row 6 ... 并希望定位 row 59,我假设您使用的是 ma​​cOS Mojavema​​cOS Catalina,并以服务 类别为目标,因为这是唯一类别,实际上会有那么多行 或更多,分配一个键盘快捷键

    示例 AppleScript 代码(如下所示)在ma​​cOS 下的Script Editor 中进行了测试Mojavema​​cOS Catalina,以及 ma​​cOS High Sierra 进行了一次小修改,按原样在我的系统上使用美国英语,因为它在系统偏好设置中的语言和地区设置。

    这也是专门针对服务 类别而编写的,因为其他类别需要不同的编码

    你需要设置三个变量serviceNameregularKeymodifierKeys,后者是基于listscript 的开头 cmets 中。

    它最初是使用键盘快捷键 ⇧⌘9导入图像设置的,您应该测试脚本原样,在修改之前。

    注意:任何键盘快捷键集必须对于在按下键盘快捷键时具有焦点的任何应用都是唯一的。

    示例 AppleScript 代码

    --  # Call the SetChangeServicesKeyboardShortcut(serviceName, regularKey, modifierKeys)
    --  # handler using the parameters as defined below:
    
    --  # serviceName defines the name of the target service under:
    --  # System Preferences > Keyboard > Shortcuts > Services
    
    --  # regularKey defines the regular key to press.
    
    --  # modifierKeys define the modifier keys to be pressed. 
    --  # Use the value based on the list below:
    --  # 
    --  #   1 = {command down}
    --  #   2 = {shift down, command down}
    --  #   3 = {control down, command down}
    --  #   4 = {option down, command down}
    --  #   5 = {control down, option down, command down}
    --  #   6 = {shift down, control down, command down}
    --  #   7 = {shift down, option down, command down}
    --  #   8 = {shift down, control down, option down, command down}
    --  #   
    --  # |  shift = ⇧ | control = ⌃ | option = ⌥ | command = ⌘ |
    --  #   
    
    
    my SetChangeServicesKeyboardShortcut("Import Image", "9", "2")
    
    
    
    --  ##################################
    --  ## Do not modify code below unless necessary, as ##
    --  ## it's tokenized for the variables defined above.   ##
    --  ##################################
    
    
    --  ## Handlers ##
    
    on SetChangeServicesKeyboardShortcut(serviceName, regularKey, modifierKeys)
        --  # Need to start with System Preferences closed.
        if running of application "System Preferences" then
            try
                tell application "System Preferences" to quit
            on error
                do shell script "killall 'System Preferences'"
            end try
        end if
        repeat while running of application "System Preferences" is true
            delay 0.1
        end repeat
        --  # Open System Preferences to the target pane.
        tell application "System Preferences"
            activate
            reveal pane id "com.apple.preference.keyboard"
        end tell
        --  # Navigate to Shortcuts > Services and select the
        --  # target service, then change/set its keyboard shortcut.
        tell application "System Events"
            tell application process "System Preferences"
                tell its window 1
                    --  # Wait until the Shortcuts tab can be clicked.          
                    repeat until exists (radio buttons of tab group 1)
                        delay 0.1
                    end repeat
                    --  # Click the Shortcuts tab.          
                    click radio button "Shortcuts" of tab group 1
                    --  # Wait until Services can be selected.                      
                    repeat until exists ¬
                        (rows of table 1 of scroll areas of splitter group 1 of tab group 1 ¬
                            whose name of static text 1 is equal to "Services")
                        delay 0.1
                    end repeat
                    --  # Select Services.          
                    try
                        select (rows of table 1 of scroll area 1 of splitter group 1 of tab group 1 ¬
                            whose name of static text 1 is equal to "Services")
                    end try
                    tell outline 1 of scroll area 2 of splitter group 1 of tab group 1
                        --  # Wait until the services under Services are available.                 
                        repeat until exists (row 1)
                            delay 0.01
                        end repeat
                        --  # Set focus to the first item of Services.              
                        repeat 2 times
                            key code 48 -- # tab key
                            delay 0.25
                        end repeat
                        --  # Get the name of every service under Services.             
                        set serviceNames to (get name of UI element 2 of rows)
                        --  # Get the row number of the target service under Services.              
                        set countRows to (count serviceNames)
                        repeat with i from 1 to countRows
                            if contents of item i of serviceNames is equal to serviceName then
                                set rowNumber to i
                                exit repeat
                            end if
                        end repeat
                        --  # Select the row of the target target service under Services.               
                        select (row rowNumber)
                        --  # Change/Set the keyboard shortcut of the target service under Services.                
                        if exists (button "Add Shortcut" of UI element 2 of row rowNumber) then
                            click button "Add Shortcut" of UI element 2 of row rowNumber
                            my shortcutKeystrokes(regularKey, modifierKeys)
                        else
                            key code 36 -- # return key
                            my shortcutKeystrokes(regularKey, modifierKeys)
                        end if
                        select (row 1)
                    end tell
                end tell
            end tell
        end tell
        quit application "System Preferences"
    end SetChangeServicesKeyboardShortcut
    
    on shortcutKeystrokes(regularKey, modifierKeys)
        tell application "System Events"
            if modifierKeys is equal to "1" then
                keystroke regularKey using {command down}
            else if modifierKeys is equal to "2" then
                keystroke regularKey using {shift down, command down}
            else if modifierKeys is equal to "3" then
                keystroke regularKey using {control down, command down}
            else if modifierKeys is equal to "4" then
                keystroke regularKey using {option down, command down}
            else if modifierKeys is equal to "5" then
                keystroke regularKey using {control down, option down, command down}
            else if modifierKeys is equal to "6" then
                keystroke regularKey using {shift down, control down, command down}
            else if modifierKeys is equal to "7" then
                keystroke regularKey using {shift down, option down, command down}
            else if modifierKeys is equal to "8" then
                keystroke regularKey using {shift down, control down, option down, command down}
            end if
        end tell
    end shortcutKeystrokes
    

    注意:对于 ma​​cOS High Sierra 以及可能更早的版本,请将 comment 下的 repeat 2 times -- # Set focus to the first item of Services. 设置为:repeat 3 times


    注意:示例 AppleScript 代码就是这样,并且没有现有的错误处理,不包含任何适当的额外错误处理。用户有责任根据需要或需要添加任何错误处理。查看AppleScript Language Guide 中的try statementerror statement。另请参阅Working with Errors。此外,在适当的情况下,可能需要在事件之间使用delay 命令,例如delay 0.5延迟设置得当。

    【讨论】:

    • 这个答案适用于我在 macOS 11.6 (Big Sur) 上,而接受的答案却没有。这个答案还具有在设置键盘快捷键后关闭系统偏好设置的好处。
    【解决方案2】:

    我对您的脚本进行了一些重组,因为我更喜欢分层的“tell block”结构(我发现它更易于阅读和遵循),并且我已将其全部放入处理程序中以对其进行概括。但除此之外,诀窍是使用where 搜索来查看 UI 结构并找到可识别的功能(注意,where 是更传统的whose 的同义词)。请参阅脚本中的 cmets。请注意,我正在更改键盘快捷键首选项的“Spotlight”部分中的“显示 Finder 搜索窗口”行,但通过更改处理程序调用的值,您可以更改任何首选项。

    要完成这项工作,您需要知道您的服务属于哪个部分,以及列表中显示的服务名称。如果您为new_val 输入一个文本字符串,它会将其视为您输入了第一个字母;如果你输入一个整数,它将把它当作一个键码,允许你使用非打印字符和功能键作为快捷键。请参阅:list of key codes

    已更正此脚本以修复几个错误,并适应“服务”部分的层次结构以及通过单击“添加快捷方式”按钮添加新快捷方式的能力。请注意,如果您是第一次添加快捷方式,UI 仍会显示“添加快捷方式”按钮,直到您选择不同的行。即使手动添加快捷方式也是如此,因此这是 GUI 的限制,而不是脚本。

    -- 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
    

    【讨论】:

    • @user3439894:试试这个版本。
    • 好吧,我知道我忘记了功能键,所以我必须调整我的代码,谢谢。另外,我可能必须使用你的一些代码,我想我喜欢能够定义传递给句柄的修饰键,然后是我使用的方法,感谢你!也就是说,我不想说在我的系统上,您的 code 运行时间比我的要长 3 倍以上,如果它已经设置,它不会更改键盘快捷键,而我的会同时执行这两种操作。我现在没有时间调试为什么它需要和我的系统一样长,但我很感兴趣。也许几天后我有时间。
    • @user3439894: 更改已在我的机器上设置的键盘快捷键没有问题;等一下,让我看看我是否输入了什么内容
    • @user3439894:不,它对我 (Catalina) 的设置和更改快捷方式都很有效。我用苹果服务和第三方服务都试过了。你能告诉我它没有在哪个服务上运行,你得到了什么错误(如果有的话)?有可能你在不同的部分有两个同名的服务,它设置了错误的;我没有检查。
    • @user3439894:请随意使用我的代码;无论如何,这都是公共领域。不用担心...