Applet MouseInput issue with page refresh

Hey there. I've been using an older version of jME and have diagnosed a serious problem in my application that causes mouse input to fail if an applet is refreshed. Notably, when the applet is navigated away from (that is, the destroy() method is called and all of the destroyIfInitialized() methods are called), and then refreshed, the MouseInput fails to update anymore.



I don't know if this is an issue with the latest 1.0 release, but I wouldn't be surprised if it was not fixed.

It is my intent to test this with 1.0 later, but if anyone has experienced a similar issue, please respond to this post and I will elaborate my findings.

I do not see this problem in my own applets that use jme 1.0 and the latest lwjgl.  A lot of applet fixes and input changes have been done in the last few lwjgl releases, so you could be looking at an outdated issue.

Hi Renanse, thank you for your breathtakingly swift reply!



Hopefully now that you've replied once, I may elaborate further…

I updated to the latest version of jME, which was surprisingly painless, and the problem persists. Fortunately, the process has not changed too much, so I can step through the phenomenon that I have.



I think I'll add here that the problem also is related to the fact that I'm using a Mouse (an AbsoluteMouse, specifically) and registering it with my input handler.



Here's what happens in code:


  1. I call AWTMouseInput.setup(), and then I create a new InputHandlerfor my application.


  2. I create an AbsoluteMouse and call mouse.registerWithInputHandler(input).


  3. Here, things begin to go awry. The input handler has two Actions added to it, for the x and y movement.


  4. addAction(…) in InputHandler grabs a MouseInputHandlerDevice and adds a trigger to it for each action. NOTE that MouseInputHandlerDevice is a Device and has a global singleton instance.


  5. createTriggers(…) in MouseInputHandlerDevice creates a MouseAxisTrigger and adds that trigger to the MouseInputListener for the device. But wait! The MouseInputListener does not exist yet, so it is created in the getMouseListener() method.


  6. This is where things get especially sneaky: the mouse listener for the mouse device is a TriggersMouseInputListener. When its activate() method is called, it adds itself as a listener to the MouseInput.


  7. Initially, the applet runs fine, but when I clean up, I need to call MouseInput.destroyIfInitialized().



    This is actually really tricky: The device is a global instance, the device's mouse listener (that listens for mouse motion events so that it can call its trigger actions) is ALSO a global instance, but the MouseInput that it is attached to is destroyed when the applet is cleaned up. Thus, when a new applet is created (ie, the browser is refreshed, or perhaps if I load another applet on the same page with the same VM), the original TriggersMouseInputListener is still listening to the MouseInput that was destroyed.



    I'll add two notes: one, getting rid of the call to MouseInput.destroyIfInitialized() does not seem to work. The refreshed applet simply seems to receive no input at all. I'll have to test it more thoroughly, though. The second issue is that the issue only seems to arise through creating an AbsoluteMouse object that is registered to the input handler.


Hmm, that is tricky.  I've only used AWTMouseInput.setup(…) on Swing apps (like RenControlEditor).



Unfortunately I'm pretty sick at the moment and not able to think straight enough to analyze your code flow… :(  As an alternative, may I suggest the possibility of setting up input similar to SimpleJMEApplet?  If you are not doing it that way for a specific reason, explain why and maybe we can figure out another approach.

Hi again Renanse, thank you again for your response!



My workaround at the moment is to make some small changes to MouseInputHandlerDevice.java and TriggersMouseInputListener.java.



specifically, if anyone is interested:



in TriggersMouseInputHandler.java I added the method:

    public boolean isActivated() {
        return MouseInput.get().containsListener(this);
    }



and in MouseInputHandlerDevice.java, I changed the getMouseListener() method to:

    public synchronized TriggersMouseInputListener getMouseListener() {
        if ( mouseListener == null ) {
            mouseListener = new TriggersMouseInputListener();
            mouseListener.activate();
        }
        if ( !mouseListener.isActivated() )
            mouseListener.activate();
        return mouseListener;
    }



It's not the absolute cleanest approach for now, but it gets the job done.
I think this may be something worthy of a bug report, but I do not know the process for that.

Hope you feel better soon!

Looks reasonable.  In cvs now, with a minor tweak.

Fabulous, thank you!!