Is there a way for a norns script to know that the user has tapped K1 and has either left to or returned from the norns menu?

Just wondering if there is a way for my script to know if the user has tapped K1 and left the script screen and is in the main norns menu structure.

PSA: not a good idea. these non-public APIs can change at any moment and will result in nil values inside of otherwise-working scripts

dragons

there is! it’s all inside the _menu table

_menu.mode is set to true if the user is in the main norns structure and false if the user is inside of the script

there are a few other helpful functions in there – eg. _menu.set_mode(bool) will toggle between the menu layers.

edit: @distropolis, if it helps, executing tab.print(_menu) in maiden’s REPL as you make changes can also illustrate the changes to the state data without code diving.

Cool! I’ll give this a shot.

1 Like

Now I just need to figure out how to listen for this with an event(?) or something. Tucking it in my redraw loop only activates it when it is false (because the redraw loop shuts off when the user is in the menu I suppose.

yeah i actually don’t think there’s a good way for the script to handle this right now.

you would have to hack it into the redefinition of _norns.key in menu.lua (but don’t do this! if it seems useful/needed we can easily add a formal “mode change” callback to the script API.)

the hacky workaround that comes to mind would be to have a timeout metro in parallel with the one used in menu:

  • start a metro on each key(1, 1),
  • cancel it on key(1, 0),
  • on the metro’s event, check the menu mode and do what you need
  • make it just a bit longer than the menu’s timer to be sure of catching the state correctly
2 Likes

i was wondering whether you were trying to solve a problem with this :slight_smile:

how often are you redrawing your screen? it’s kinda become “house style” to use a screen_dirty flag and keep a steady 30fps clock on a function which checks the flag state and executes redraw() whenever flag is true. at the end of redraw(), reset the flag to false. anything that changes visual state would just have to flip the flag to true, instead of constantly refreshing, which removes unnecessary redraws.

2 Likes

yeah i almost asked, how would you use this exactly? (there may be another solution)

In my script (pixels), I have an undocumented “drawing” mode that works by not calling screen.clear() in the redraw loop, essentially allowing the user to draw their own landscape like an etch-a-sketch. Instead of redrawing the whole screen every frame (running at 12fps), the user is just painting new areas pixel by pixel.

The biggest problem is that because switching to the menu clears the screen, it essentially erases the screen when the user exits the script. Their work is still saved (as a 2d table) but the screen is wiped.

I might solve this by running another 12fps loop that just looks at the _menu.mode and does a quick redraw when the user pops back into the script.

EDIT:
I just tested this method and it works.

3 Likes

@distropolis, thank you for sharing more about the usecase – i’ve edited my original reply to actually direct away from this sort of non-public API usage, as it can cause longterm compatibility issues if these internal systems ever need to change for better system experiences. apologies for the overzealous “yeah, sure, why not?!” energy :slight_smile:

this has sparked good discussion about the menu code, though. look for improvements in this arena.

1 Like

that makes sense.

i think several people have expressed an interest in implementing one or more offscreen drawing states, to allow double buffering and things like this.

2 Likes

I did get this working with the original suggestions above, but after reading your edited comments, I’m hesitant to release an update based on your initial suggestions.

Are there any immediate plans to modify those menu flags?

from my understanding, not immediate, but it was unwise for me to suggest using the non-public API as a canonical solution. it creates upstream design considerations in areas where there were none previously, which boxes in future decisions for the core devs.

@ngwese has managed workarounds for this situation in his own scripts without relying on these ops. perhaps he can share some of his solutions which will be better than the not-legacy-supported one i suggested. apologies for the worry!

1 Like

it’s a reasonable API feature request (script focus/defocus), i’ve created an git issue

4 Likes

Until such time as an API is available the technique I’ve been using is to test whether or not the global redraw function is set to a function I’ve defined in my script. Something like this:

local function script_redraw() end

local function script_has_focus()
   return redraw == script_redraw
end

-- assign my dummy function to the redraw callback
redraw = script_redraw

…then in other parts of the code (outside the redraw function) I bracket calls to screen functions like so:

if script_has_focus() then
   screen.blah(...)
end
4 Likes