Idea: Generic Code to Select a Popup Menu Item - Let's Talk

Pinging @cdthomer and @ccstone, but anyone can jump in here.

I just had a thought of something I might be able to write, but I wanted to toss the idea around first before I jumped into it. (BTW, I'm talking specifically here about popup menus, not menu-bar menus.)

I've got lots of JXA code that manipulates menus - even context menus (i.e. right-click menus). I know how to read all the items in the menu, tell if it's "checked", select the one I want, etc. All of that code is hard-coded to specific menus, of course.

I also have code that converts an AppleScript path to a JXA path, i.e.

pop up button 2 of group 1 of window "Whatever"`

to

windows("Whatever").groups[0].popUpButtons[1] // or whatever

So my thought is that I could write some JXA code for accessing menus, that could take as one parameter the path to the menu or control that pops up the menu. And of course it would take other parameters so it knows what to do with the menu, etc.

The issue, of course, is how a "typical" KM user would get the path to the menu/control.

Any thoughts on this idea?

FWIW an old menuItemClicked from my library which takes a path (list of strings) as a parameter:

Expand disclosure triangle to view JS Source
// menuItemClicked :: String -> [String] -> IO Bool
const menuItemClicked = strAppName =>
    // Click an OS X app sub-menu item
    // 2nd argument is an array of arbitrary length 
    // (exact menu item labels, giving full path)
    lstMenuPath => {
        const intMenuPath = lstMenuPath.length;

        return intMenuPath > 1 ? (() => {
            const
                appProcs = Application("System Events")
                .processes.where({
                    name: strAppName
                });

            return appProcs.length > 0 ? (
                Application(strAppName)
                .activate(),
                lstMenuPath.slice(1, -1)
                .reduce(
                    (a, x) => a.menuItems[x].menus[x],
                    appProcs[0].menuBars[0].menus.byName(
                        lstMenuPath[0]
                    )
                )
                .menuItems[lstMenuPath[intMenuPath - 1]]
                .click(),
                true
            ) : false;
        })() : false;
    };

For example:

Expand disclosure triangle to view JS Example
(() => {
    "use strict";

    const main = () =>
        menuItemClicked("Safari")([
            "Bookmarks", "Add to Reading List"
        ]);

    // --------------------- GENERIC ---------------------

    // menuItemClicked :: String -> [String] -> IO Bool
    const menuItemClicked = strAppName =>
        // Click an OS X app sub-menu item
        // 2nd argument is an array of arbitrary length
        // (exact menu item labels, giving full path)
        lstMenuPath => {
            const intMenuPath = lstMenuPath.length;

            return intMenuPath > 1 ? (() => {
                const
                    appProcs = Application("System Events")
                    .processes.where({
                        name: strAppName
                    });

                return appProcs.length > 0 ? (
                    Application(strAppName)
                    .activate(),
                    lstMenuPath.slice(1, -1)
                    .reduce(
                        (a, x) => a.menuItems[x].menus[x],
                        appProcs[0].menuBars[0].menus.byName(
                            lstMenuPath[0]
                        )
                    )
                    .menuItems[lstMenuPath[intMenuPath - 1]]
                    .click(),
                    true
                ) : false;
            })() : false;
        };

    return main();
})();

Generally a fold ('reduce' in JS and Python) lets us define a compound value/effect in terms of a list and a seed value.

Yeah, like that! :laughing:

Any thoughts on how someone could get the path? Is UI Browser the only option, or is there something that's available to everyone without buying an app?

Tell me more ?

A menu path is easily read from the GUI (though of course the KM Menu clicked action interface does a better job)

In terms of specifying a path – a JSON formatted KM variable ?

Sorry for not being more clear. I was thinking of a popup menu. I'll modify the original post to be more clear.

Hey Dan I appreciate you thinking of me for your question. Unfortunately I'm not sure how the average KM user would be able to get a path for things like that without resorting to an app like UI Browser which might be too involved for some.

Honestly my experience and knowledge on these topics is still very basic. :frowning:

Not impossible to write a basic version of UI Browser – do I remember that @ccstone wrote one at some point ?

I was wondering about that, and actually typed that out...but realizing how (relatively) complex that might be I didn't want to mention it since I wouldn’t have even the slightest idea as to how to do it. :sweat_smile:

You're right - I forgot about that. I actually have that macro. Chris has been feeling under the weather lately, so I'm not sure if he'll see this right away, but I'll email him if he doesn't reply.

I totally understand. The reason I brought this up is that people have asked about popup menus before so I was just thinking out loud.

By the way, with a little guidance, using UI Browser to get the path to a button or whatever is really easy. Basically you just switch to the screen reader, move your mouse over the button, then hold down the Command key as you move your mouse away, and click the "Find in browser" button. Then use a UI Browser menu option to generate the AppleScript to access the button (or whatever).

It's pretty trivial, actually.

Very true. I’m wondering though if some might be turned off to UI Browser because of the cost once the initial trial period ends.

I had no problem shelling out money for it cus I’ve been working a lot with learning AppleScript the last few months, but I’m not sure others would want to.

Either way, I think this is a good idea and if it could be easily implemented it would probably help quite a few users here. I’m glad to help out any way I can but since I really don’t have much experience with AppleScript and none with JSA, I’d probably be limited to testing :sweat_smile:

That's the thing! I've been on the fence on buying UIB mainly due to the lack of videos and guidance. Their site doesn't help sell the product either. I have a psychological issue asking for help as it is. :slight_smile: I bought Script Debugger, by a suggestion on the forum, and feel I wasted money because I have NO idea how to use it or it doesn't work the way I think it should. I may still buy UI Browser. I definitely need to find something I'm comfortable with, to invest the time in, because I feel horrible asking the 5 or so people here for AppleScript assistance. I feel I owe it to the team to learn it just so I can offer you all some relief. Meanwhile, I hack my way through AppleScript like I did/do Keyboard Maestro. :sunglasses:

I didn't purchase Script Debugger because for me the Lite version does everything I need it to. But I did purchase UIB and it has been incredibly helpful in learning AppleScript. I am certain I don't use it to it's full potential but it was still worth the investment.

1 Like

That's a good endorsement. And... Even though you claim Ohio, you are still a helpful guy so I'll put my trust in your comment. :wink:

1 Like

Aww man…. When you talk to Chris, please tell him we are sending good vibes for him to get better.

KC

3 Likes

Oh I’m not from Ohio originally (moved here two years ago) and believe me, I’m not crazy about the place. :rofl:

1 Like

I've been demoing UI Browser and today had an issue with popup menus in Logic Pro. I could click the button fine but the menu would just flash up for a split second and then disappear before its items became selectable. I was also quite unsure what the name of the menu would be as that's not viewable in UI Browser as far as I could see. Anything that made the process a little easier would get my vote!

That's a problem I have with UI Browser also. I don't remember how I solved it, but I think I solved it.

We know that menus go away as soon as the window loses focus, so the answer may be to make sure UI Browser doesn't take away the focus. So maybe a combination of UI Browser hotkeys, and preference settings.


I just managed to have it see a popup menu, and report it in the Screen Reader window. I couldn't figure out how to get the AppleScript for it, but I took a picture of the screen with my camera. From there, I would imagine you could type the applescript in by hand, then make a macro that pops up the menu, pauses for a 10th of a second or so, and then access the menu from applescript.

Let me know if that doesn't make sense.

@noisneil and @DanThomas I have this issue too. Whenever a window loses focus, some menus disappear, which means that UIB can no longer read them.

I solve this by holding the hotkey to freeze UIB's results window, and then screenshot it and just use it as a reference to build my AppleScript.

1 Like

Glad it's not just me! I did write some scripts by hand and clicking the popup button via Applescript still just flashed up the menu for a split second. If this isn't a problem you've encountered then perhaps it's peculiar to Logic Pro.