Post

Replies

Boosts

Views

Activity

Reply to MenuItem scripting
The general idea would be to get the menus of the menu bar, then repeat through the menu items of each of those menus. Since a menu item can also have a menu, a recursive handler can be used to descend the menu structure. Once you have a regular menu item (no submenu), you can then get the values of its attributes to build the shortcut. Attributes of interest would be AXMenuItemCmdModifiers which is a mask of the modifier keys used (shift, option, etc), AXMenuItemCmdChar which is the character, and AXMenuItemCmdGlyph which is a code for a glyph for keys such as tab or backspace that don’t have a character. From there it is just a matter of formatting the results into something readable.
Jul ’23
Reply to MenuItem scripting
It is one thing to learn about AppleScript (pay attention to object specifiers and references), but the scripting terminology of any given application is like the wild west - just about the time you think you have everything figured out, some mysterious animal you haven't seen before comes over the hill and eats all your hair. In System Events, an attribute is a class that is a named data value associated with a UI element. An attribute will have properties such as a name and value, but the attributes themselves vary depending on the UI object. The various class properties are documented in the scripting dictionary, but you will need to go exploring to find out what attributes are available and what they are. A lot of these attributes can be also figured out from the Cocoa API documentation. There are some examples out there, although most seem to be based on a few StackExchange topics from over a decade ago. I blew the dust off my version, it uses System Events to get an application's menu item shortcuts and writes them to a file. Note that the script scans every menu item, so depending on how many there are it may take a while. Rich Text and symbols for the various keys and their modifiers are used for readability. property glyphSymbols : {{2, "tab", "⇥"}, {4, "enter", "⌤"}, {9, "space", "␣"}, {10, "delete right", "⌦"}, {11, "return", "↩"}, {23, "delete left", "⌫"}, {27, "escape", "⎋"}, {28, "clear", "⌧"}, {98, "page up", "⇞"}, {100, "left arrow", "←"}, {101, "right arrow", "→"}, {104, "up arrow", "↑"}, {106, "down arrow", "↓"}, {107, "page down", "⇟"}, {111, "F1", "F1"}, {112, "F2", "F2"}, {113, "F3", "F3"}, {114, "F4", "F4"}, {115, "F5", "F5"}, {116, "F6", "F6"}, {117, "F7", "F7"}, {118, "F8", "F8"}, {119, "F9", "F9"}, {120, "F10", "F10"}, {121, "F11", "F11"}, {122, "F12", "F12"}, {135, "F13", "F13"}, {136, "F14", "F14"}, {137, "F15", "F15"}, {140, "eject", "⏏"}, {143, "F16", "F16"}} -- https://www.hammerspoon.org/docs/hs.application.html#menuGlyphs property modifierSymbols : {{"command", "⌘"}, {"shift-command", "⇧⌘"}, {"option-command", "⌥⌘"}, {"option-shift-command", "⌥⇧⌘"}, {"control-command", "⌃⌘"}, {"control-shift-command", "⌃⇧⌘"}, {"control-option-command", "⌃⌥⌘"}, {"control-option-shift-command", "⌃⌥⇧⌘"}, {"none", ""}, {"shift", "⇧"}, {"option", "⌥"}, {"option-shift", "⌥⇧"}, {"control", "⌃"}, {"control-shift", "⌃⇧"}, {"control-option", "⌃⌥"}, {"control-option-shift", "⌃⌥⇧"}} -- modifier mask bits (⌘ is assumed): 1 = ⇧, 2 = ⌥, 4 = ⌃, 8 = no ⌘, 16 = fn global ItemsScanned, totalFound -- sums for number of menu items scanned, number of shortcuts found on run -- example to get a list of menu item key equivalents (shortcuts) for an application set output to linefeed set {ItemsScanned, totalFound} to {0, 0} set appName to name of application ((choose file of type "com.apple.application") as text) tell application appName to activate tell application "System Events" to tell process appName -- note that process names can be different repeat with aMenu in (menus of menu bar items 2 thru -1 of menu bar 1) -- skip Apple menu set someResults to my (getshortcuts for aMenu) if someResults is not in {"", missing value} then set output to output & name of aMenu & ":" & linefeed & someResults end if end repeat end tell set outputPath to ((path to desktop) as text) & id of application appName & " menu item shortcuts.rtf" do shell script "echo " & quoted form of output & " | /usr/bin/textutil -stdin -convert rtf -output " & quoted form of POSIX path of outputPath -- rich text (for formatting and better symbols) return "" & ItemsScanned & " menu items scanned for " & totalFound & " shortcuts" -- global sums end run # Recursive handler to get modifiers and any key equivalent (shortcut) for menu items of a menu. to getshortcuts for someMenu given indent:indent : 1 set {shortcuts, prefix} to {"", ""} repeat indent times set prefix to prefix & tab end repeat tell application "System Events" to repeat with menuItem in (menu items of someMenu) tell menuItem to try set itemName to name of it if itemName is not in {"", missing value} then -- skip separator items and views set ItemsScanned to ItemsScanned + 1 -- global sum set symbol to my (getCommandSymbols for it) if symbol is not missing value then -- found one set totalFound to totalFound + 1 -- global sum set spacer to tab if (count symbol) < 3 or symbol begins with "fn" then set spacer to spacer & tab -- alignment set shortcuts to shortcuts & prefix & symbol & space & spacer & itemName & linefeed else -- try submenu repeat with submenu in menus of it -- keep reference indexes to work with duplicate names set theItems to my (getshortcuts for submenu given indent:(indent + 1)) if theItems is not in {"", missing value} then set shortcuts to shortcuts & prefix & itemName & ":" & linefeed & theItems end repeat end if end if on error errmess log "*** Error getting shortcut for " & (get name of it) & ": " & errmess end try end repeat return shortcuts end getshortcuts # Get character symbols as needed for a menu item command. to getCommandSymbols for menuItem tell application "System Events" to tell menuItem to try set cmdModifiers to value of attribute "AXMenuItemCmdModifiers" of it if cmdModifiers is 8 then -- none return missing value else if cmdModifiers is 24 then -- function key set modifier to "fn" else set modifier to last item of item (cmdModifiers + 1) of modifierSymbols -- mask starts at 0 end if set cmdChar to value of attribute "AXMenuItemCmdChar" of it if cmdChar is not in {"", missing value} then return modifier & cmdChar set cmdGlyph to value of attribute "AXMenuItemCmdGlyph" of it if cmdGlyph is not in {"", missing value} then repeat with glyph in glyphSymbols if contents of first item of glyph is cmdGlyph then return modifier & last item of glyph end repeat on error errmess log "*** Error getting command symbols for " & quoted form of (get name of it) & ": " & errmess end try return missing value end getCommandSymbols
Jul ’23
Reply to AppleScript. Split the string into parts by the separator character.
Text item delimiters are what you are looking for, for example: set myString to "MyData1|MyData2" set {myVar1, myVar2} to splitString(myString) to splitString(someString) try set tempTID to AppleScript's text item delimiters -- save current delimiters set AppleScript's text item delimiters to "|" set pieces to text items of someString -- split the string set AppleScript's text item delimiters to tempTID -- restore old delimiters set firstPart to item 1 of pieces set secondPart to item 2 of pieces on error errmess -- delimiter not found log errmess return {firstPart, ""} -- empty string for missing item end try return {firstPart, secondPart} end splitString
Aug ’23
Reply to Speeding Up Code
You can speed it up a bit more by not bothering with the check for a window, as just getting the windows will always return a list and avoid the duplication in getting windows. Better yet, you can usually reduce overhead by having an application do as much as possible with any given call, for example: tell application "System Events" set foregroundApps to (processes whose background only is false) repeat with anApp in foregroundApps set minimizedWindows to (windows of anApp where value of attribute "AXMinimized" is true) repeat with aWindow in minimizedWindows tell aWindow to set value of attribute "AXMinimized" to false end repeat end repeat end tell In this example you can go even further by doing something like getting the (windows of (processes whose background only is false) where value of attribute "AXMinimized" is true), but there are diminishing returns for increased noise and the performance of complex expressions depends a bit on the particular application.
Sep ’23
Reply to translation project only uses first and last items in a Numbers cell range
It is only translating the first and last items because in the getCellRangeValues handler, that is all that the words of cellRange list contains. You would need to get the individual cell elements of the range and use those in the repeat statement to get the in between cell references, for example: repeat with cellRef in cells of range cellRange of tbl set end of cellValues to value of cellRef end repeat
Mar ’24
Reply to AppleScript, Do Shell. How do I write the "test" command to the "script editor"?
This is one of those situations where learning some basics instead of having others do everything helps. The posted script just has some quoting issues - either escape the double quotes for use in the string, or use single quotes since the shell also understands those. The corrected script would be: set myFile to choose file -- choose a package or or try `choose folder` to select a folder set theCommand to "(test -d " & quoted form of POSIX path of myFile & " && echo 'is a dir') || (set status 0; echo 'not a dir') ; 2>&1" return do shell script theCommand
Jun ’24
Reply to Applescript: window API handler crashing in split view
OK, I am getting a few different errors, but the problem seems to be that for whatever reason (looks like a bug), when you initially click in the window or use the divider or history, the window accessibility properties are not getting set up. Clicking the window again gets things set up, but until then the "front" window doesn't have any properties for the script to use, such as selected tab, so trying to use that throws an error. Unfortunately, this also prevents targeting the window by name, id, tty, etc, so I haven't found a workaround other than to click the window a couple of times before running the script. A command line tool to do the clicking could probably be used, but you would need to get information about the "front" window to get the bounds to click into, which would most likely be way more involved than what you are doing now.
Aug ’24