Capturing 'back' key input

I’ve been working on a pretty sweet game in jmonkey for a while now, and I recently decided to port it to android. One thing I hated though was how when you press the phone’s back button, it would just show a message about if you want to quit. Lame. Since I plan to capture that input and use it to call my own methods, I spent several hours researching how to do it and eventually used the approach given on this post here. It seems to work, but I had some questions…

  1. Is this really the best way to do it?
    and

  2. As I’m kind of a java newbie, how can I call one of my other classes’ methods from the android main activity class? I would pass the Main() class or whatever but I have no idea how jme3’s hierarchy of abstract classes and interfaces works. Also I have a feeling that would be bad coding practice.

Thanks in advance!

  1. cant answer not using android

If you call any jme application related code, remember, always enqueue if unsure, will save you a lot of multithreading trouble (as I’m pretty sure the main activitys gui might run in a different thread).

1 Like

Ok thanks for the info. I’m already using this.runOnUiThread, is enqueue better? Anyways, it’s less of a threading problem and more just how do I access the running instance of the game, or in this case the Main class? There is a method there that needs to be called whenever the button is pressed. it’s really not that complex in theory but it’s turning out to be quite complicated… Sorry if this is a stupid question.

Sorry to double post but I was trying some things today and noticed this… When extending AndroidHarness and overriding the onTouch method, the back button triggers it. However, when overriding onTouch with a TouchListener in my main class, it wouldn’t. So I did some digging into the source code and found this in the AndroidInput class: [java] @Override
public boolean onKeyDown (int keyCode, KeyEvent event)
{
TouchEvent evt;
evt = getNextFreeTouchEvent();
evt.set(TouchEvent.Type.KEY_DOWN);
evt.setKeyCode(keyCode);
evt.setCharacters(event.getCharacters());
evt.setTime(event.getEventTime());

    // Send the event
    processEvent(evt);
    
    // Handle all keys ourself, except the back button (4)
    if (keyCode == 4)
        return false;
    else
        return true;
}[/java]  

Ok seriously what the heck?! It’s hard coded to prevent getting input from the back key? Is there any way to override this, or am I going about this the totally wrong way?
This is really really important to me to get this working so any help would be appreciated greatly!

as far as I remember there is a onBackPressed()

1 Like
@skyhawkrr said: Sorry to double post but I was trying some things today and noticed this... When extending AndroidHarness and overriding the onTouch method, the back button triggers it. However, when overriding onTouch with a TouchListener in my main class, it wouldn't. So I did some digging into the source code and found this in the AndroidInput class: [java] @Override public boolean onKeyDown (int keyCode, KeyEvent event) { TouchEvent evt; evt = getNextFreeTouchEvent(); evt.set(TouchEvent.Type.KEY_DOWN); evt.setKeyCode(keyCode); evt.setCharacters(event.getCharacters()); evt.setTime(event.getEventTime());
    // Send the event
    processEvent(evt);
    
    // Handle all keys ourself, except the back button (4)
    if (keyCode == 4)
        return false;
    else
        return true;
}[/java]  

Ok seriously what the heck?! It’s hard coded to prevent getting input from the back key? Is there any way to override this, or am I going about this the totally wrong way?
This is really really important to me to get this working so any help would be appreciated greatly!

That’s probably to prevent the default of it closing down your app (I guess). A more descriptive comment about ‘why’ would have been nicer. The error message appears from the AndroidHarness in the onTouch() method, so the easiest way is to override the onTouch() method in MainActivity.java

1 Like
@wezrule said: That's probably to prevent the default of it closing down your app (I guess). A more descriptive comment about 'why' would have been nicer. The error message appears from the AndroidHarness in the onTouch() method, so the easiest way is to override the onTouch() method in MainActivity.java

Alright, that makes sense. So I overrode the onTouch method and can successfully detect back key presses (yay!) but now I need to somehow notify the jme thread from the main activity. I used the tutorial on the advanced android page which said this:

[java] 1. Create an interface named something along the lines of JmeToHarness.java 2. Open your Android Main Activity and implement this interface. 3. In Main.java of your Application, add the following:

JmeToHarness harness;
public JmeToHarness getHarness() {
return this.harness;
}
public void setHarnessListener(JmeToHarness harness) {
this.harness = harness;
}

  1. Add the following snippet to the onCreate method of your Android Main Activity:

if (app != null)
((Main)app).setHarnessListener(this);
[/java]

After dealing with a ton of netbeans’ bugs (Package not found, symbol not found, blablabla) I managed to get it to compile with that code! Almost there! The thing is it doesn’t explain how to use the listener… So I’m not quite sure what to do now. (I just learned what an interface is yesterday so this is kind of hard for me, sorry)

Thanks for all the helpful replies!

Never mind I finally got it to work!!! I didn’t use the interface/listener thing, I just used Empire Phoenix’s suggestion:

@Empire Phoenix said: If you call any jme application related code, remember, always enqueue if unsure, will save you a lot of multithreading trouble (as I'm pretty sure the main activitys gui might run in a different thread).

So if anyone for future reference is wondering here’s the code from my main activity class.

[java]@Override
public void onTouch(String name, TouchEvent evt, float tpf)
{

        {
            if (name.equals(ESCAPE_EVENT))
            {
                switch(evt.getType())
                {
                case KEY_UP:
                   
                    app.enqueue(new Callable(){
                        
                        public Object call() throws Exception {
                            ((gb3d.Main)app).GoBack();//your command here
                        return null;
                        }
                         
                    });
                    
                break;

                default:
                break;
                }
            }
        }         
    }[/java]  

Thanks for the help guys!

ok but what the hell is/does gb3d.main?

I think you might have overcomplicated what is actually quite simple (though really not much documentation on it i guess)

to handle the “back” key yourself you first go to MainActivity, and in the constructor set this variable handleExitHook = false; (handleExitHook is inherited from AndroidHarness). that makes it so it wont show the “are you sure you want to quit” dialog when back is pressed.

Now you can handle the back button yourself within jmonkey with the RawInputListener or through a TouchListener

[java]public class MyListener implements RawInputListener {
@Override
public void onTouchEvent(TouchEvent evt) {
if (evt.getType() == Type.KEY_UP) {
if (evt.getKeyCode() == TouchInput.KEYCODE_BACK) {
// back was pushed
evt.setConsumed();
}
}
}
}[/java]

you can also do this with a Touch Listener.

[java]
public class MyListener implements TouchListener{

            @Override
            public void onTouch(String name, TouchEvent event, float tpf) {
                    if(event.getType() == Type.KEY_UP){
                            if(event.getType() == Type.KEY_UP){
                                    if(event.getKeyCode() == TouchInput.KEYCODE_BACK){
                                            // back was pressed
                                    }
                            }
                    }
            }
            
    }

[/java]

@hello123 said: ok but what the hell is/does gb3d.main?

Gb3d.main is just the main class in my jme program that I wanted to access. Just replace that whole line with whatever your main class is.

@icamefromspace said: I think you might have overcomplicated what is actually quite simple (though really not much documentation on it i guess)

to handle the “back” key yourself you first go to MainActivity, and in the constructor set this variable handleExitHook = false; (handleExitHook is inherited from AndroidHarness). that makes it so it wont show the “are you sure you want to quit” dialog when back is pressed.

Now you can handle the back button yourself within jmonkey with the RawInputListener or through a TouchListener

That was actually the very first thing I tried, but for some reason I just could not get it to work. I’ll give it another shot when I can.
Thanks everyone!

For anyone who is still struggling with this, like I was (I spent 2 hours solving this :rolling_eyes:)
You have to delete the INPUT_MAPPING_EXIT mapping in order for this to work. Otherwise your app will just exit.
Put inputManager.deleteMapping(SimpleApplication.INPUT_MAPPING_EXIT); into simpleInitApp() and then handle stuff with touch listeners.