With the Keyboard, Scroll to the Bottom of a Macro?

I often want to scroll to the very bottom of a macro. Since I like to do as much as possible with the keyboard, unless I'm missing something, this isn't as easy as one might think.

If the last action in the macro is short (vertically), then the simple selection of the last action does get one very close to the macro bottom. However, if the last action is long (vertically), e.g., with a Group that contains many actions, then the selection of the last action is not near the bottom of the macro since the automatic scrolling that occurs (when the action is selected) is to the top of the last action (in this case, the Group action).

This issue could be easily addressed if there was a keystroke that automatically scrolled to the bottom of the selected action. Is there one I'm missing?

If so, I could create a simple macro that:

  • Selects the last action
  • Invokes the keystroke that automatically scrolls to the bottom of the selected action

I've been experimenting. The following sequence does accomplish the task, but it's admittedly a kludge.

  • Selects the last action
  • Adds a Debugger Finish action. (I selected that action for two reasons:
    1. It's simple and innocuous, and
    2. when it's added, the entire action is automatically selected. When some actions are added, e.g., a Comment, an element within the action is automatically selected, not the entire action.)
  • Invokes keystroke Up Arrow. This selects the second-to-last action and even if it's long (vertically) the bottom of the action remains visible in the editor.
  • Invokes keystroke ⌘Z. This deletes the Debugger Finish action. Also, since Undo is used, the modification date of the macro is not changed.

Group.kmactions (2.8 KB)

Keyboard Maestro Export

In addition to being a kludge, there's another shortcoming with the above steps: for large macros, the Undo step can be slow.


Is there a simpler approach I'm missing?

Don't laugh too hard, but this works for me: (assign this to a hotkey)

image

1 Like

Not exactly a specific keystroke for that, but this functionality could be achieved by simulating the End key followed by some number of simulating the Page Down key. A macro with extra instances of simulating Page Down isn't apt to affect anything since Macs and Keyboard Maestro tend to be fast enough that, say, always simulating it seven times when typically only three are necessary probably won't be noticeable.

1 Like

Bingo! I was hoping for something simple. Thanks, @NaOH.

With some quick-and-dirty testing it appears that only one End and one Page Down are required. If further testing is successful, then I'll modify Scroll to Top or Bottom of Macro by using this:

Group.kmactions (2.1 KB)

Keyboard Maestro Export


2024-09-26 23:0402 EDT TESTING UPDATE: On my fast M1 MacBookPro, the above approach (select last action, End, Page Down) works great.

However, with very large macros on my two older and slower macs, the above approach does not seem to work reliably. I have the following:

• Keyboard Maestro 11.0.3
• Sequoia 15.0 (24A335)/MacBookPro18,2
• Mojave 10.14.16/Macmini6,2
• High Sierra 10.13.6/iMac11,1445

@peternlewis, might you have any suggestions for an approach that would be more robust?


@Airy, thanks for your post. 100% for creativity. (I've learned a lot from your posts where you apply the OCR action.)

  • Ideally the scroll to the bottom would be fast. For a large macros, the Simulate Scroll Wheel action is slow. I messed around with it too, but I didn't "look" for the New Action text as you did in your creative approach.

  • When scrolling the macro, the Simulate Scroll Wheel also scrolls code within Execute a JavaScript For Automation actions, etc., as the actions are scrolling up.

  • If the Keyboard Maestro editor window bottom is below the bottom edge of the display, the OCR could be fail because the New Action is outside the perimeter of the display.

The approach I'm using in Version 2.0 of Scroll to Top or Bottom of Macro also suffers from third bullet limitation because it's possible that the bottom of the scroll bar is not visible.

Keyboard Maestro Export

That's one of the nicest things anyone's ever said to me on these forums, so thanks.

1 Like

I've done some additional testing and updated my post above.

Option click the scroll bar.

image

1 Like

In case anyone reading this thread doesn't already know, clicking in the scroll area of a Mac window moves the content up or down a page. Option-clicking in the scroll area moves the content to where the user option-clicked.

This is one of those capabilities that's been around a while, sites have written about it, maybe Apple has it documented somewhere, but it's not clear if it's well-known and it's probably not so obvious a user might try it while poking around the Mac UI.

2 Likes

This only works if the scroll bar is visible, though. And with Macs set to hide it by default (grrrrr), you'd have to simulate a scroll first to make it visible, wouldn't you? I hid my scrollbars and tried option-clicking in the area that should be a scroll bar, and nothing happens. If I've recently scrolled and the bars are still visible, it works.

This is but one of the reasons I typically have my scroll bars set to always visible :).

-rob.

3 Likes

I forgot about that setting. It's great you noted that critical detail.

1 Like

Yes, I mentioned this requirement for the current version (2.0) of Scroll to Top or Bottom of Macro. As written, the macro also checks that the bottom of the scroll bar is inside the perimeter of the display.

Version 2.0 includes a much better method to scroll to the top that does not rely on the scroll bars (thanks to information from @NaOH).

As I consider Version 3.0, I’ve yet to find a method for scroll to the bottom that is as fast and robust AND works on my slower macs. As it stands now, Version 3.0 might include three different scroll to the bottom methods with a setting to specify the default method and another optional setting that enables the method to be dependent on the %MacName%. (I don’t want to resort to a method based on the least common denominator.)

Thanks to all that have contributed to this thread!

@peternlewis, thanks for this tip. For others that might stumble upon this thread later, this technique only works if:

  1. That click region (-7, -45) of the Keyboard Maestro window (the bottom of the scroll bar) is within the perimeter of the screen.

  2. The two System Settings (or System Preferences) are set as follows:


For user that that have Jump to the spot that's clicked set, the Move or Click Mouse action would not have the ⌥ with modifiers set.

1 Like

I've had a skim, but haven't seen this mentioned yet. Quickly hacked together but seems to work, regardless of whether the scroll bar is set to show or not:

tell application "System Events"
	tell process "Keyboard Maestro"
		tell window 1
			tell group 6
				tell splitter group 1
					tell scroll area 3
						tell scroll bar 1
							set value to 0 -- moves thumb to top
							-- set value to 1 --moves thumb to bottom
						end tell
					end tell
				end tell
			end tell
		end tell
	end tell
end tell

Whack it in an "Execute an AppleScript" action, comment in/out the set value... statements as appropriate, set a hot key -- and Bob's your mother's brother.

2 Likes

That's so strange. I have JXA code that does this exact same thing, and I swear it didn't work, and all of a sudden it works now. I must have been doing something wrong. It's also possible I have a version that doesn't work, and I got confused as to which version was which.

By the way, if anyone thinks it's "iffy" to assume this will always work, then I agree. However, I wrote this code something like 7-8 years ago, and it still works (previous comment notwithstanding).

Anyway, here's th JXA code:

(() => {

	Application("Keyboard Maestro").activate();
	const proc = Application("System Events").processes["Keyboard Maestro"];

	// get
	const scrollPos = proc.windows[0].groups[5].splitterGroups[0].scrollAreas[2].scrollBars[0].value();

	// set (floating point number from 0 to 1 - 0.5 is halfway, 0 top, 1 bottom)
	proc.windows[0].groups[5].splitterGroups[0].scrollAreas[2].scrollBars[0].value = 0.5

})()
1 Like

Can you have another go, @DanThomas, and test with the Action pane open and then not present?

I rarely use that way of adding actions, so wouldn't have picked that up.

1 Like

Are you saying that the "path" to the scroll bar changes when you do that?

Because if so, that happens in FCPX, and I have specific code (for FCPX) to look at the various paths that it might be, and then cache that path and try to use it next time.

It's not a lot of fun, and certainly not worth my effort here!

...or did I misunderstand what you were trying to say?

1 Like

I think -- and you should test yourself -- that when the Action pane is active it becomes window 1 and the Editor becomes window 2. That's why the path changes.

In which case:

tell application "System Events"
	tell process "Keyboard Maestro"
		if name of window 1 is "New Action" then
			set winIndex to 2
		else
			set winIndex to 1
		end if
		tell window winIndex
			tell group 6
				tell splitter group 1
					tell scroll area 3
						tell scroll bar 1
							set value to 0 -- moves thumb to top
							-- set value to 1 --moves thumb to bottom
						end tell
					end tell
				end tell
			end tell
		end tell
	end tell
end tell
1 Like

Yeah, that sounds about right.

In FCPX (for this particular UI control), I've got 3 different sets of indices that can change. Fortunately, only the indices change, not the path components.

var outline = _win.splitterGroups[0].groups[group1Index].splitterGroups[0].groups[group2Index].splitterGroups[0].groups[group3Index].splitterGroups[0].groups[1].splitterGroups[0].scrollAreas[0].outlines[0];

So when I check to see which one's valid, I have to do this:

for (var group1Index = 0; group1Index < 2; group1Index++) {
	for (var group2Index = 0; group2Index < 3; group2Index++) {
		for (var group3Index = 0; group3Index < 5; group3Index++) {
			var outline = _tryGetUIObject(group1Index, group2Index, group3Index);
			if (outline !== null) {
				_group1Index = group1Index;
				_group2Index = group2Index;
				_group3Index = group3Index;
				return outline;
			}
		}
	}
}

The good thing is that once I find the correct indices, I can save them and reuse them. If they quit being valid then I just have to look for the again.

That's a royal PITA. In the case that we're talking about here, if you're right, you only need to test for window 1 or 2 (or 0 and 1 in JXA).

This is why, when people who use FCPX ask me for my macros, I politely decline. Can you imagine how much trouble this could be if you had to support this in production code?

User: Hey, your macros quit working with this new version of FCPX, and I'm in the middle of working on a Hollywood movie. I need this fixed NOW!

Me: :exploding_head::scream::face_vomiting::fu::writing_hand::man_detective::clock230::yawning_face::pray:

1 Like

Me: Not a problem. That'll be $200 an hour, minimum 1 hour, and the first $200 up front. Or you wait on my convenience and get it later for free.

Amazing how, at least where I work, jobs suddenly become less important when there's a cost attached!

2 Likes

Very true. I think $200 is too cheap, though. :joy:

1 Like