Mouse.setGrabbed problem

Started by petterm, April 30, 2006, 09:54:55

Previous topic - Next topic

petterm

Hi,

I'm having some problems with Mouse.setGrabbed(). I'm using LWJGL's Mouse class through JME's
MouseInput like this:

----
boolean[] res = new boolean[MouseInput.get().getButtonCount()];
boolean grab = false;
      
for (int i = 0; i < res.length; i++) {
 res = MouseInput.get().isButtonDown(i);
   if (res) {
      log.debug("res[" + i + "] is true!");
      grab = true;
   }
}

log.debug("getMouseState - grab is: " + grab);
      
Mouse.setGrabbed(grab);
----

What happens when I start my app is that before I press any button, the debug printout says that grab is
always false, as expected. When I press the left button, the following text repeats a number of times, again as expected:

res[0] is true!
getMouseState - grab is: true
res[0] is true!
getMouseState - grab is: true

When I release the button, I start getting into trouble, though:

getMouseState - grab is: false
res[0] is true!
getMouseState - grab is: true
getMouseState - grab is: false
res[0] is true!
getMouseState - grab is: true
getMouseState - grab is: false
res[0] is true!
getMouseState - grab is: true

and so on every few milliseconds, "forever". I had a look at the Windows native code (using Windows XP), to try to
figure out what could be going on. I've got no clue at all about Windows programming, but I have a theory that sort
of seems to fit the facts. The below method gets called when the mouse is polled:

----
static void UpdateMouseFields(JNIEnv *env, jobject coord_buffer_obj, jobject button_buffer_obj) {
   HRESULT                         hRes;
   DIMOUSESTATE diMouseState;                  // State of Mouse
   int i, j;

   int *coords = (int *)(*env)->GetDirectBufferAddress(env, coord_buffer_obj);
   int coords_length = (int)(*env)->GetDirectBufferCapacity(env, coord_buffer_obj);
   unsigned char *buttons_buffer = (unsigned char *)(*env)->GetDirectBufferAddress(env, button_buffer_obj);
   int num_buttons;
   int buttons_length = (int)(*env)->GetDirectBufferCapacity(env, button_buffer_obj);
   if (coords_length < 3) {
      printfDebugJava(env, "ERROR: Not enough space in coords array: %d < 3", coords_length);
      return;
   }

   handleMessages();

   if (mouse_grabbed) {
      hRes = IDirectInputDevice_GetDeviceState(mDIDevice, sizeof(DIMOUSESTATE), &diMouseState);
      if (hRes != DI_OK) {
         // Don't allow the mouse to drift when failed
         diMouseState.lX = 0;
         diMouseState.lY = 0;
         diMouseState.lZ = 0;
         // did the read fail because we lost input for some reason?
         // if so, then attempt to reacquire.
         if(hRes == DIERR_INPUTLOST || hRes == DIERR_NOTACQUIRED) {
            hRes = IDirectInputDevice_Acquire(mDIDevice);
            if (hRes != DI_OK)
               return;
         } else {
            printfDebugJava(env, "Error getting mouse state: %d", hRes);
            return;
         }
      }

      coords[0] = diMouseState.lX;
      coords[1] = -diMouseState.lY;
      coords[2] = diMouseState.lZ;
      num_buttons = mButtoncount;
      if (num_buttons > buttons_length)
         num_buttons = buttons_length;
      for (j = 0; j < num_buttons; j++)
         buttons_buffer[j] = diMouseState.rgbButtons[j] != 0 ? JNI_TRUE : JNI_FALSE;
   } else {
      coords[0] = last_x;
      coords[1] = last_y;
      coords[2] = accum_dwheel;
      accum_dx = accum_dy = accum_dwheel = 0;
      num_buttons = mButtoncount;
      if (num_buttons > BUTTON_STATES_SIZE)
         num_buttons = BUTTON_STATES_SIZE;
      for (j = 0; j < num_buttons; j++)
         buttons_buffer[j] = win32_message_button_states[j];
   }
}
----

My hunch is that when using direct input, the window won't get any Windows events due to changes in the mouse state. If
it doesn't get any messages, the win32_message_button_states array doesn't get reset, so the following could
happen:

1. before I have clicked the mouse, the state is not grabbed, so regular windows events are sent
2. I click the button, and handleMouseButton() is called, setting win32_message_button_states[0] to JNI_TRUE.
3. my Java code sets the mouse_grabbed flag, and events are disabled
4. state is grabbed, the buttons_buffer values are set based on diMouseState.rgbButtons
5. I release the button, and immediately, my Java code sets the 'mouse_grabbed' to false
6. the method above checks the state of the buttons using the win32_message_button_states array, which hasn't been
  update, since no new Windows events have been sent.
7. my Java code sets the state back to grabbed
8. the method above checks the direct input, correctly sees that no mouse button is pressed.
9. my Java code sets the state to 'not grabbed'
10. go to 6.

Could this theory be correct? Is there a workaround? If the theory is correct, I guess that it would be possible to
set the state in win32_message_button_states when reading direct input also and thereby solve the problem?

Thanks in advance,

Petter

elias

You're right about the problem switching from grabbed to non-grabbed. I've applied your suggested fix (tracking the directinput state in the win32 state array manually) and it should be included in the upcoming 1.0 beta. In the meantime, please test:

http://odense.kollegienet.dk/~naur/lwjgl-win32-30062006.zip

which includes an updated win32 binary and a corresponding lwjgl.jar.

- elias

petterm

Thanks for the update - unfortunately, I cannot verify whether it works or not, since jME doesn't seem to be compatible with the new .jar file:

    [java] java.lang.NoSuchMethodError: org.lwjgl.opengl.GL11.glVertexPointer(IIII)V
    [java]     at com.jme.renderer.lwjgl.LWJGLRenderer.predrawGeometry(Unknown Source)
    [java]     at com.jme.renderer.lwjgl.LWJGLRenderer.draw(Unknown Source)
    [java]     at com.jme.renderer.lwjgl.LWJGLRenderer.createDisplayList(Unknown Source)
    [java]     at com.jme.scene.Geometry.lockMeshes(Unknown Source)
    [java]     at com.jme.scene.Node.lockMeshes(Unknown Source)
    [java]     at com.jme.scene.Spatial.lockMeshes(Unknown Source)
    [java]     at com.jme.scene.Spatial.lock(Unknown Source)
    [java]     at se.jadestone.haven.democlient.visualiser.JMEGui.loadStatic(JMEGui.java:2146)
    [java]     at se.jadestone.haven.democlient.visualiser.JMEGui.createTerrain(JMEGui.java:2231)
    [java]     at se.jadestone.haven.democlient.visualiser.JMEGui.create3DStuff(JMEGui.java:1792)
    [java]     at se.jadestone.haven.democlient.visualiser.JMEGui.simpleInitGame(JMEGui.java:307)
    [java]     at com.jme.app.BaseSimpleGame.initGame(Unknown Source)
    [java]     at com.jme.app.SimplePassGame.initGame(Unknown Source)
    [java]     at com.jme.app.BaseGame.start(Unknown Source)

It's not an urgent problem for the moment for me, but I will most likely get back to it later and try to verify it.

SamR

I have the same problem on about 60% of the jmetest programs.  Please let me know when this is fixed.

Matzon

this is a JME issue, not LWJGL.

renanse

looks like just an issue of pairing a version of jme with the wrong lwjgl version