Insert event listeners into Runtime

I am trying to implement Android back button functionality in my app, but having trouble due to the order the event listeners fire on Runtime.  

If I add this to a scene:

local function onKeyEvent( event ) -- If the "back" key was pressed on Android, then prevent it from backing out of your app. if (event.keyName == "back") then -- go back or do something here return true end -- Return false to indicate that this app is \*not\* overriding the received key. -- This lets the operating system execute its default handling of this key. return false end Runtime:addEventListener( "key", onKeyEvent );

Then add an overlay (the menu for example), I would like to add similar code to the menu, so that the back button only hides the menu. However, when I do that, the *first* onKeyEvent function that was defined is hit first, which is in the scene, not in my overlay.

Is there a way to set the precedence of the event listeners? Ultimately, something like this:

Runtime:insertEventListener(“key”, onKeyEvent, 1) – add this event as the first one, shifting all others

or just an overload to add:

Runtime:addEventListener("key, onKeyEvent, 1)

That way, it would always hit the “latest” function that was defined for handling the back button, and I can stop it from going any further.

I could do what I want by inserting into the _functionListeners directly I guess, but I’m always hesitant to mess with undocumented stuff in case Corona changes a variable name down the road.

Thanks,
Dave

Hi Dave,

Perhaps I’m over-simplifying this, but why not just set a variable flag that says if your overlay is showing (or not)? Then, when the back button is pressed, check that variable value and if the overlay is open, close it; otherwise do something else.

Brent

The overlay is just one example. If you look at our app – Floorvana by Shaw Floors – and look at a details page for one of the products, you could potentially be looking at a full screen view of a product image.  At that point, it would need to do something like the following with every back button tap:

Close the full screen view

Go back to 2 columns of results

Go back to either: Color Picker, Photo, Favorite Colors, or My Products

You can get to the same stuff from multiple locations… Then we have a menu overlay, and it has two overlays (Find a Dealer and Settings – Settings is in not in the current published version on the App Store; it’s only in Google Play right now).

So, that would be a lot to keep track of, and the various overlays don’t know about each other and communicate via events. To keep the hairiness of it all down to a minimum, it’d be great if I could just insert an event listener as the first one. :slight_smile:

I’ve started building my own little simple class today to just store an array of functions, or a stack of functions really, and pop off the last one when we get the event for the back button. (It has remove methods too so I can remove them as necessary.) My initial tests seem okay, but there’s still a lot more work to do.

IMO Brent’s suggestion is probably the best way to go, but you could also try removing the ‘old’ event listener when you need to use a different one, and then add it back as you need it.
If you always use the same global function name, you can just change it to refer to the new function:

defaultKeyHandler = function( event ) if (event.keyName == "back") then doSomething() return true end return false end onKeyEvent = defaultKeyHandler Runtime:addEventListener( "key", onKeyEvent ); --then when you open menuOverlay: Runtime:removeEventListener( "key", onKeyEvent ); onKeyEvent = function( event ) if (event.keyName == "back") then doSomethingElse() return true end return false end Runtime:addEventListener( "key", onKeyEvent ); --and then when closing the menuoverlay: Runtime:removeEventListener( "key", onKeyEvent ); onKeyEvent = defaultKeyHandler Runtime:addEventListener( "key", onKeyEvent );

…and so on. That way each overlay etc is directly responsible for what the back key will do when the overlay is shown, and you have a default function to go back to when you’ve finished. Not the prettiest way to do it, but it would work.

Hi Dave,

Perhaps I’m over-simplifying this, but why not just set a variable flag that says if your overlay is showing (or not)? Then, when the back button is pressed, check that variable value and if the overlay is open, close it; otherwise do something else.

Brent

The overlay is just one example. If you look at our app – Floorvana by Shaw Floors – and look at a details page for one of the products, you could potentially be looking at a full screen view of a product image.  At that point, it would need to do something like the following with every back button tap:

Close the full screen view

Go back to 2 columns of results

Go back to either: Color Picker, Photo, Favorite Colors, or My Products

You can get to the same stuff from multiple locations… Then we have a menu overlay, and it has two overlays (Find a Dealer and Settings – Settings is in not in the current published version on the App Store; it’s only in Google Play right now).

So, that would be a lot to keep track of, and the various overlays don’t know about each other and communicate via events. To keep the hairiness of it all down to a minimum, it’d be great if I could just insert an event listener as the first one. :slight_smile:

I’ve started building my own little simple class today to just store an array of functions, or a stack of functions really, and pop off the last one when we get the event for the back button. (It has remove methods too so I can remove them as necessary.) My initial tests seem okay, but there’s still a lot more work to do.

IMO Brent’s suggestion is probably the best way to go, but you could also try removing the ‘old’ event listener when you need to use a different one, and then add it back as you need it.
If you always use the same global function name, you can just change it to refer to the new function:

defaultKeyHandler = function( event ) if (event.keyName == "back") then doSomething() return true end return false end onKeyEvent = defaultKeyHandler Runtime:addEventListener( "key", onKeyEvent ); --then when you open menuOverlay: Runtime:removeEventListener( "key", onKeyEvent ); onKeyEvent = function( event ) if (event.keyName == "back") then doSomethingElse() return true end return false end Runtime:addEventListener( "key", onKeyEvent ); --and then when closing the menuoverlay: Runtime:removeEventListener( "key", onKeyEvent ); onKeyEvent = defaultKeyHandler Runtime:addEventListener( "key", onKeyEvent );

…and so on. That way each overlay etc is directly responsible for what the back key will do when the overlay is shown, and you have a default function to go back to when you’ve finished. Not the prettiest way to do it, but it would work.