Long Text Display, Modification and Reading limitations

I have a cool new macro, but it's hindered because I can't figure out how to do something (or perhaps it cannot be done.) Let me explain what I actually can do before I explain my problem.

I know how to change the default duration (e.g., change to 7 seconds) of the Large Text Display using this action...

image

...or by using this command...

defaults write com.stairways.keyboardmaestro.engine DisplayLargeTextDisplayPeriod -float 7.0

And I know how to read the global value using this command...

defaults read com.stairways.keyboardmaestro.engine DisplayLargeTextDisplayPeriod

And I can change a macro's private value of this duration using... (although there seems to be no command line equivalent)

image

...but I cannot read the value of the long text display for the current macro. More importantly, I cannot read the value for the current instance. And for that matter, I can't change the value for the current instance.

So there are really three separate problems here:

  1. I can't determine the value of this setting for the current macro.
  2. I can't change the value of this setting for the current instance.
  3. I can't determine the value of this setting for the current instance.

As a result my macro can't quite live up to its full potential. Even so, I'll probably release my macro with a trimmed down functionality.

Does it not only apply to the current instance? It looks like every time I run this:

Short or Long Delay.kmmacros (3.4 KB)

...there's a 50/50 chance of either a 1 second or the Engine default pause.

If that's the case for you too, then all that's left is determining the value within the current instance -- which should be the default until you set it to something else (and you'll have to track "something else" yourself...).

A "instance" is different from a "local" value. Your test is only testing the action and its value in a single macro, which means you aren't testing if changing the value impacts other macros in the same instance. If you move the Display Text Large action into a separate macro, it won't inherit the value of the Large Text Display Delay from the parent.

Try your test again and move the Display Text Large action into a separate macro which you call from the first macro.

You seemed to be saying that this set the value "for this macro" (as, indeed, it says in the action's options). I'm saying it is set for this execution of this macro, ie the current instance.

If you're saying that setting the value for this instance of this macro also sets it for all "child" macros of this instance of this macro (phew!), that's something else. Does setting it within the child reflect back to the parent?

An "instance" includes any sub-macros that are called by the parent macro. You seem to be thinking that an "instance" does not include child macros. It certainly does, at least with variables.

If you create a variable named "Instance1" in a macro, its value will be visible to any sub-macros that it calls. That's what I'm trying to do here. I'm trying to find the value of the "Display Large Text Duration" KM variable when it is set by the calling macro but my macro, which is being called, wants to find its value. I can't find its value, and that's because (a) there is no way to set the Duration variable for the entire instance, and (b) there's no way to fetch the value for the current instance.

As the KM Documentation says:

https://wiki.keyboardmaestro.com/manual/Variables

The key words from that page are:

Instance Variables...Available to ...Sub-Macros of that Macro
Local Variables... Not available to any of its Sub-Macros

So I'm using the same terminology. When I say "instance," I'm referring to any sub-macros created by a macro. But when you say instance, you are referring only to the top macro only.

For instance variables, yes! KM supports "local" Large Text Display Durations, and "Global" durations, so why not instance durations? I don't get the inconsistency.

Oddly, KM's support for "local durations" is only 50%, since it lets you change the value but not fetch the value.

I'm (clumsily) trying to draw a distinction between

  • the macro, and values hard-coded in its actions (your first screen shots)
  • the executing instance of that macro
  • the executing instance(s) of that macro's sub-macros
  • instance variables

Too many instances spoil the broth, or something :wink:

Try it. Instance variables changed in a child have that new value when control returns to the parent, but the "display duration" value doesn't do that.

It's more like an environment variable -- the child inherits "display duration", but any changes made are not applied to the parent's environment.

Hopefully this Group will demonstrate what I mean:

Instance test 2 Macros.kmmacros (5.6 KB)

If it behaved like an instance variable then all 3 "Display large" would last 1 second, as set in sub 2 -- instead, they have the duration they set before calling their child.

All of which means you can change the value in a child (and a child of a child, etc...). You know the value for each child because either a) you've explicitly set it, or b) it's inherited from the parent. And after a child finishes executing you know the value -- it's whatever it was before the child started executing.

As long as you don't store the value in an instance variable, of course!

I would recommend that you stop using the word "instance" in a way that's inconsistent with KM's philosophy of using the word "instance" to include an entire calling stack of macros.

In my original post I wrote "I can't change the value of this setting for the current instance." So that proves I already know what you are asking me to try means that I already understand what you are trying to explain to me here.

Yes. This is what I explained in my original post. It doesn't support either an "instance context" and doesn't fully support a "local context" since it doesn't let you fetch the local value. It is precisely what you are talking about that I am complaining about.

I know precisely how it works. Nothing in my original post needs to be corrected. And nothing in your examples changes my understanding of how it works. What I'm complaining abut is that KM doesn't have an "instance context" for this setting, and it doesn't even fully support a "local context" since it doesn't let the user fetch this value.

No! I'm trying to write a macro that can be called by other people! I'm primarily a utility macro writer. So I do not set the value in the parent macro because I do not write the parent macro.

But I don't think it is -- it's the calling stack from the point of definition down. Which is why sub-macros are their own instances inside their parent instance. But that's besides the point...

The value is set in the parent macro -- either explicitly by the user or implicitly from the default. Whatever you do within your sub(s) has no effect on the parent. Why do you need to know what it is?

In other words, what function of your sub(s) depends on the user's defined value? Are you doing something like "make this last twice as long as the user usually wants"?

I know from experience that whatever it is you're trying to do is going to be cool, and I don't want whatever-the-problem to stand in the way!

That's very kind of you, and you are helping to lower the temperature here.

I'm trying to create a super-enhanced version of Display Text Large, but one of the problems I'm facing is that there is no way for me to tell what duration the calling macro has set if the user has used the action "Set Duration for Large Text Display to X." Basically, I would be ignoring the user's desired duration. I want to use the user's specified duration, but I cannot, because there is no way to find out what the user has specified. It will limit my ability to support the user's wishes. Yes, I could tell the user to either pass the desired value as a parameter or tell the user to set a global (or instance) variable whenever he calls my macro, but that's putting redundant work on the user's shoulders.

Let me be clear in case this isn't clear. If the user says "Set Duration for Large Text Display to 10 for this macro" and then calls my macro, my macro has no way of determining or inheriting his chosen value. His chosen value is "local" to his macro and I cannot access it.

One possible solution is for KM to add a "for this instance" option to the "Set Duration for Large Text Display" action. Another possible solution is for KM to add a token called %GetLargeTextDisplayDurationInstance%. I can't use macOS's "defaults" to get these values because the "for this macro" value is not stored in macOS and there's no way for any KM action to fetch this value. I would like to point out that KM has at least three tokens that contain the word "Instance" so having a token that returns a value for a specific instance is not unprecedented.

I admit that those words are compelling as a definition, BUT they disagree with the exact words stated by Peter: (see link below for full context)

both the initial macro and the executed sub-macro are within the same “instance”.

He specifically calls them the same instance (while you call them different instances) and also says both the parent and child macro "share the same variables." But I must admit I find your way of explaining it potentially valid too.

I've been pondering a way to disprove either Peter's assertion or yours, which differ on this matter, but I'm unable to think of a way to show whether your definition or Peter's is correct. It may not matter.

1 Like

I feel like a complete twunt.

I swear that when I first tried this out:

  1. Instance variables defined in sub-macros were out of scope for the parent
  2. Delay durations set in the parent were inherited by the sub-macro

...and now I can't replicate either.

Since I'm sure nothing has changed in KM -- I (obviously) screwed up. So everything I've written above is complete and utter b*llocks.

Sorry, @Airy -- and thanks for being gentle with me.

Every day your technical acumen impresses me, and today your humility impresses me. Is there nothing you do poorly?

We may never know if a parent has access to the child's instance variables, as there seems to be no way to check, since (so far as I can tell) execution must return to the parent after the child's completion before we can check if the parent can read the child's instance variables. So you might be right when you say a child gets a copy of the parent's instance (you said, "sub-macros are their own instances inside their parent instance".)

My belief (and see above for how much that's worth!) is now that instance variables are in scope across the whole instance, for the main and all sub (and sub-sub, etc) macros no matter where those instance variables are defined.

So while they might get "copied down", instance variables defined in sub-macros are also "copied up":

Instance test 3 Macros.kmmacros (8.8 KB)

...where Instance_sub2 is available in "Main".

And look at the ExecutingInstance values -- the first UUID is the same for "Main", "sub 1", and "sub 2", only the second part differs. I'm thinking that the first UUID is the "instance ID" -- perhaps variables have similar ID structures, leading to "any variable that has the same instanceID as me is available to me" (local variables would require a match on both UUID parts).

It may not be totally, factually, correct -- but it seems to be practically correct! Write a macro that sets an instance and a local variable, displays its ExecutingInstance ID, then pauses:

AS and UUID test.kmmacros (3.5 KB)

Image

You can then test from Script Editor or similar with:

-- spare secondPart:
-- "00000000-0000-0000-0000-000000000000"


set firstPart to "F3CA7386-347D-43E1-A341-725535840CBC"
set secondPart to "00000000-0000-0000-0000-000000000000"

set theInst to firstPart & ":" & secondPart

tell application "Keyboard Maestro Engine"
	
	return "Instance: " & (getvariable "Instance_var" instance theInst) & linefeed ¬
		& "Local: " & (getvariable "Local_var" instance theInst)
	
end tell

...pasting the first part of the UUID from the "Display text" dialog as the firstPart text. With the spoofed secondPart you'll only see the instance variable. Paste the second part of the UUID as secondPart and you see both instance and local variables. Change a random character in firstPart and you won't see either.

Ah yes, that token would constitute proof to me that they share the same actual instance, internally in the KM Engine.

Your AppleScript seems to be even more definitive. You've sold me on the idea that you were wrong and I was right. :wink:

1 Like