Back key not closing RSG Dialogs

I’m finishing a new RSG channel and it was based on the Hero Grid Channel sample (https://github.com/rokudev/hero-grid-channel).

After all my implementation and changes I noticed that the Dialog used to show warnings and the KeyboardDialog I added to a screen, are not closing when the “back” remote key is pressed.

There is still only one “onKeyEvent” for the whole channel, located at the Scene brs script. I noticed that the “back” “press” event is never triggered at this function, indicating it was handled somewhere else before the scene, but the dialog is not closed. I also noticed that setting the “close” property to true, as described at the documentation, also is not closing the dialog.

I can’t figure out what I did that could have caused this, but I thing it is wrong behaviour, because the documentation says clearly that the “back” key always close dialogs.

Anyone have a good clue for me ?

i haven’t read that sample - are the “Dialog used to show warnings and the KeyboardDialog” part of it (then pls mention which file/component) or something you added? who has the input focus at that time, when they are up?

“RokuNB” wrote:
i haven’t read that sample - are the “Dialog used to show warnings and the KeyboardDialog” part of it (then pls mention which file/component) or something you added? who has the input focus at that time, when they are up?
The warning Dialog is part of it not the KeyboardDialog. But neither is behaving properly.

Some of my code related to the KeyboardDialog.

The XML has:

        <KeyboardDialog
            id="KeyboardDialog"
            text=" "
            visible="false" />

The script Init:

m.keyboardDlg = m.top.findNode("KeyboardDialog")
m.keyboardDlg.observeField("buttonSelected", "OnButtonSelected")
m.keyboardDlg.observeField("text", "OnTextChanged")

To show the dialog I’m using:

m.keyboardDlg.title = "User Login"
m.keyboardDlg.buttons = ["OK", "Cancel"]
m.keyboardDlg.visible = true
m.keyboardDlg.focusButton = 0
m.keyboardDlg.setFocus(true)

Everything works as expected, except the back key that does not close the dialog.

And actually in the documentation there is no declared way to prevent pressing “back” from closing the dialog.

“marcelo.cabral” wrote:
Everything works as expected, except the back key that does not close the dialog.

And actually in the documentation there is no declared way to prevent pressing “back” from closing the dialog.
Your sentences - read together - are confusing. One complains Back does not close the dialog, the next says there is no way to prevent dialog from being closed…

Now, i know how to display a modal dialog in a scene and that is by setting scene’s dialog property, i.e.

myScene.dialog = myDialog
myScene.optionsDialog = true ' if you want `*` to also close it '

That’s all - from there on the scene will take care of displaying it modal and hold it on for dear life - that is, until Back button is pressed or say you set myScene.close = true …

So i think the magic ingredient is to let the scene handle it. If not, i assume dialogs behave as generic windows…

“EnTerr” wrote:

“marcelo.cabral” wrote:
Everything works as expected, except the back key that does not close the dialog.

And actually in the documentation there is no declared way to prevent pressing “back” from closing the dialog.
Your sentences - read together - are confusing. One complains Back does not close the dialog, the next says there is no way to prevent dialog from being closed…
Sorry for the confusion, what I meant with the second sentence was that even if I wanted to prevent the back button to close the Dialog, based on the documentation, there is not way to do it.
This was to emphasize that in my view it’s either a bug, or a missing information in the documentation.

“EnTerr” wrote:

Now, i know how to display a modal dialog in a scene and that is by setting scene’s dialog property, i.e.

myScene.dialog = myDialog
myScene.optionsDialog = true ' if you want `*` to also close it '

That’s all - from there on the scene will take care of displaying it modal and hold it on for dear life - that is, until Back button is pressed or say you set myScene.close = true …

So i think the magic ingredient is to let the scene handle it. If not, i assume dialogs behave as generic windows…
Hmmm, the documentation again does not make it clear that the dialog would only respond to a back if is assigned to the scene dialog property. And if it is supposed to act as a regular screen, in my scenario, then the “press” event for the “back” button should be generated at the only “onKeyEvent” of the channel, don’t you agree?

I found one place at the documentation that mentions that we should use the scene dialog property: " For example, to create the dialog object and assign it to the dialog field of a Scene node defined in a component XML file (which is the required usage of the Dialog node class)" from
https://sdkdocs.roku.com/display/sdkdoc/Scene+Graph+Data+Scoping#SceneGraphDataScoping-m.topComponentScopeReference

The problem is the example provided by Roku (that I based my implementation on) does not follow this “requirement”, by defining the Dialog named “WarningDialog” in the Screen xml. So I believe the documentation needs to be improved on Dialog node usage, and the fact it “swalows” the back key in some situations is a bug for me.

What you’re both saying aligns with my experience: A dialog isn’t a dialog unless you assign it to the Scene’s dialog field.

Once that’s been done, the Back button will be handled automatically by the dialog and close the dialog. You won’t get a keypress event for Back (in this case), which is consistent with what the documentation says.

The Roku example appears flawed. Surprise, surprise! At least it’s on GitHub, so you can submit an issue and/or pull request.

I managed to make it work, thank you guys.

Another question: I want to show the dialog from a script that is in a screen brs not the scene brs, there is any way I can access the “parent” scene from there ?
The way I implemented was to pass the reference for the scene down to the screen using a field:

    else if key = "options"
      if m.DetailsScreen.visible = false
          m.OptionsScreen.scene = m.top
          m.OptionsScreen.visible = true
          m.OptionsList.setFocus(true)
      end if

Why do you need the parent’s m.top? Can’t you set the child’s m.top.dialog to the Dialog?

“belltown” wrote:
Why do you need the parent’s m.top? Can’t you set the child’s m.top.dialog to the Dialog?
When I set to m.top.dialog at the child screen the dialog never showed, but this way setting in the child screen script it works:

m.top.scene.dialog = keyboardDlg

PS. Considering that I passed down the Scene node as the code in my previous post

I don’t see why setting m.top.dialog in the child component wouldn’t work. Are you setting this in one of the event-handlers in the child’s brs code? And is keyboardDlg set up correctly when assigning it to m.top.dialog in the child component?

“belltown” wrote:
I don’t see why setting m.top.dialog in the child component wouldn’t work. Are you setting this in one of the event-handlers in the child’s brs code? And is keyboardDlg set up correctly when assigning it to m.top.dialog in the child component?
Here is the full code, if I choose line tagged as Option 1 it works, if I switch to the option 2, nothing happens:

sub OnItemSelected()
    m.index = m.top.itemSelected
    if m.index = 0 
        print "about selected"
    else if m.index < 3 
        print "open keyboard"
        m.keyboardDlg = createObject("RoSGNode", "KeyboardDialog")
        m.keyboardDlg.title = "Login"
        m.keyboardDlg.text  = " "
        m.keyboardDlg.observeField("buttonSelected", "OnButtonSelected")
        m.keyboardDlg.observeField("text", "OnTextChanged")
        if m.index = 1
            m.keyboardDlg.message = "Entre o e-mail do usuário:"
            if m.global.user <> ""
                m.keyboardDlg.text  = m.global.user
            else
                m.keyboardDlg.text = "@email.com"
            end if
            m.keyboardDlg.keyboard.textEditBox.secureMode = false
        else if m.index = 2
            m.keyboardDlg.message = "Entre a senha do usuário:"
            m.keyboardDlg.text  = ""
            m.keyboardDlg.keyboard.textEditBox.secureMode = true
        end if
        [OPTION 1] m.top.scene.dialog = m.keyboardDlg <========= Dialog is Shown
        [OPTION 2] m.top.dialog = m.keyboardDlg <============= Nothing happens
    else
        m.infoLabel.text = ""
        item = m.optionsList.content.getChild(2).getChild(m.index - 3)
        if item.id <> m.global.maxRes
            m.global.maxRes = item.id
            LoadMenuItems()
            m.optionsList.jumpToItem = m.index
        end if
    end if
end sub

I’m not really sure what’s going on. All I could come up with is that when OnItemSelected is called, if the component does not have focus, and therefore is not the “current Scene node” then setting that component’s dialog will have no effect because, “Setting the dialog field of the current Scene node to a Dialog node causes the dialog to be displayed”.

“belltown” wrote:
Why do you need the parent’s m.top? Can’t you set the child’s m.top.dialog to the Dialog?
Because not every component has a .dialog property.
Only Scene nodes have that property.
And since saw elsewhere we should use only one and only scene, that means there is only one such node per RSG.

His question is how can i find the scene from one of the children, nested levels down?
I suppose can just walk the tree up:

nxt = m.top
while nxt <> invalid:
  scene = nxt
  nxt = scene.getParent()
end while
' at this point `scene` is the top-most node `

“EnTerr” wrote:

“belltown” wrote:
Why do you need the parent’s m.top? Can’t you set the child’s m.top.dialog to the Dialog?
Because not every component has a .dialog property.
Only Scene nodes have that property.
And since saw elsewhere we should use only one and only scene, that means there is only one such node per RSG.

His question is how can i find the scene from one of the children, nested levels down?
I suppose can just walk the tree up:

nxt = m.top
while nxt <> invalid:
  scene = nxt
  nxt = scene.getParent()
end while
' at this point `scene` is the top-most node `

Thanks again EnTerr!
The ideal would be to have it available as the global, once all child screens should be able to open dialogs, but anyway I will keep my implementation.

“EnTerr” wrote:
Because not every component has a .dialog property.
Only Scene nodes have that property.
And since saw elsewhere we should use only one and only scene, that means there is only one such node per RSG.
I get it now. I was confusing components with Scenes. Yes, there’s only one Scene generally, so that’s where you need to set the dialog.

I hadn’t come across this issue myself because most of my dialogs are “custom” components, not real Dialog components, but they behave as modal dialogs. I show/hide them instead of setting scene.dialog. The only time I use actual Dialog components are in my main Scene, so m.top.dialog works.

So yes, EnTerr’s solution should get the Scene m.top, or just pass it in as a component interface field – or, since there’s only one Scene, set m.global.scene = m.top

or you can do

            scene = invalid
            for each nod in m.top.getRoots():
                if nod.isSubType("scene") then scene = nod: exit for
            next

This should work, if there is one and only one scene (which seems like a sane assumption)

“RokuNB” wrote:
or you can do


m.top.getRoots()

According to the docs, the note above getRoots() states: The following methods can be called on any subject node and return the same global results. They can be used in a development channel for debugging purposes, but should not be used in a production channel. and then it goes on to say: Any calls to getAll(), getRoots(), getRootsMeta() and getAllMeta() should be removed from your production channels.

“belltown” wrote:
According to the docs, the note above getRoots() states: The following methods can be called on any subject node and return the same global results. They can be used in a development channel for debugging purposes, but should not be used in a production channel. and then it goes on to say: Any calls to getAll(), getRoots(), getRootsMeta() and getAllMeta() should be removed from your production channels.
The wisdom behind of that statement is not immediately apparent to me. It is possible that some of these functions are grossly inefficient (but ok for debug). It might be prudent then to use the previous idea of getParent() to the root.

“RokuNB” wrote:

“belltown” wrote:
According to the docs, the note above getRoots() states: The following methods can be called on any subject node and return the same global results. They can be used in a development channel for debugging purposes, but should not be used in a production channel. and then it goes on to say: Any calls to getAll(), getRoots(), getRootsMeta() and getAllMeta() should be removed from your production channels.
The wisdom behind of that statement is not immediately apparent to me. It is possible that some of these functions are grossly inefficient (but ok for debug). It might be prudent then to use the previous idea of getParent() to the root.
I’d be curious to know the wisdom as well. It did refer to these features as diagnostic tools in the Developer Blog post that announced their availability: https://blog.roku.com/developer/2016/06/21/roku-os-7-2-dev-highlights/. You wouldn’t normally use diagnostic (debugging?) tools in production code, but it doesn’t explain why these particular tools shouldn’t be used in production.