Alternative to Robot class?

I’m working on a full screen 3D first person game for my class that utilizes the Java Robot class to recenter the mouse for camera movement.

However, the Robot class is awful on Mac OS X. It works well on Linux and Windows… Are there any other ways around using the Robot class?

Also, removing the cursor on OS X doesn’t work either, although the means of doing it seems like a hack anyways (setting the cursor image to an image that doesn’t exist).

Any help would be greatly appreciated…

I’m working on a full screen 3D first person game for my
class that utilizes the Java Robot class to recenter the
mouse for camera movement.

Java3d huh? Well, bad luck.

Also, removing the cursor on OS X doesn’t work either,
although the means of doing it seems like a hack anyways
(setting the cursor image to an image that doesn’t exist).

You actually set the cursor to an image, which is completely transparent.

setCursor(Toolkit.getDefaultToolkit().createCustomCursor(new BufferedImage(1,1,BufferedImage.TYPE_INT_ARGB),new Point(0,0),""));

[quote]>I’m working on a full screen 3D first person game for my

class that utilizes the Java Robot class to recenter the
mouse for camera movement.

Java3d huh? Well, bad luck.

Also, removing the cursor on OS X doesn’t work either,
although the means of doing it seems like a hack anyways
(setting the cursor image to an image that doesn’t exist).

You actually set the cursor to an image, which is completely transparent.

setCursor(Toolkit.getDefaultToolkit().createCustomCursor(new BufferedImage(1,1,BufferedImage.TYPE_INT_ARGB),new Point(0,0),""));
[/quote]
Actually we’re using JOGL… it’s been pretty good to me.

Thanks for the cursor removal hint…the example I was working from was setting the cursor to an image that didn’t exist, which seemed like a really bad way to go about it…

Actually we’re using JOGL

Ah alright, I suggest to take a closer look at JInput… it should have some mouse stuff (I’m a lwjgl user myself… it comes with it’s own input/sound stuff).

Well, I tried the suggestion for ‘removing’ the cursor, and I’m getting the same results. I’m sure it’s just OS X’s Java implementation.

No big deal, really, I’m developing/running on Linux and it’s working quite well there. I just wanted it to work on all platforms so I could demo it from my Powerbook.

I looked at JInput, but that may be a bit too much for one piece of functionality on one platform for a game that is due next Friday.

Thanks for the suggestions, though! If you or anyone else have anymore, I’ll give them a shot.

I remembered there was some oddity with mac os… see here:
http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=2D;action=display;num=1095892264

Sweet! Two problems down in the last 15 minutes. I simply moved the cursor removal method call after the requestFocus() call…working nicely. (The other problem was rebuilding joal to fix the endian-ness issue with os x)

Now if I can get the robot.mouseMove() from being so choppy, I will be a happy camper. It recenters the mouse, but only intermittently. Since my camera movement is relative to the center of the screen, it looks/runs horrible…

Anyways, thanks for the help!

[quote][…]
Now if I can get the robot.mouseMove() from being so choppy, I will be a happy camper. It recenters the mouse, but only intermittently. Since my camera movement is relative to the center of the screen, it looks/runs horrible…
[…]
[/quote]
Ah… hehe :slight_smile:

Well, this isn’t a problem with robot itself. It’s the way you’ve used it. Since robot/the event stuff weren’t build with first person shooters in mind it’s a bit counter intuitive, but not impossible.

Ok. I’ll try to explain it.

You need a small object for storing the relative coords. Whenever you pickup those cords you have to set em both to 0. This is done once per frame

Your MouseMotionListener needs to overwrite mouseMoved and mouseDragged (mouseDragged just calls mouseMoved with that event object).

Ok. When the mouse is moved you:
if(!ignore)
-determin the relative offsets
-add em to the current relative offsets (that small object, I mentioned before)
-set the ignore flag to true
else
-move the mouse to the center
-set the ignore flag to false

You have to do it like that, because there can be more than one pair of new mouse coords per frame and because the robot’s movements also trigger mouse moved events.

HTH :wink:

Ah… I found it…

import java.awt.*;
import java.awt.event.*;

/** The input listener handles all input for the game. It allows direct checking
 * of key states and processes mouse movements.
 */
public class InputListener implements KeyListener, MouseListener, MouseMotionListener, KeyEventPostProcessor
{
  // used for calculating mouse movement
  private int mouselast_x;
  private int mouselast_y;

  // keeps track of which keys are down
  private boolean [] keysdown = new boolean[256];

  // keeps track of the mouse buttons being down
  private boolean lmousedown = false;
  private boolean rmousedown = false;

  // a java.awt.robot  is needed to keep the cursor in the center of the screen
  private Robot robot;

  // find the middle of the screen
  private Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
  public int midscreen_x = (int)screenSize.getWidth()/2;
  public int midscreen_y = (int)screenSize.getHeight()/2;

  // this is used to pass mX and mY to the cameraBehavior
  private volatile Point point;

  // these are the total movments of the mouse between frames
  private int mX = 0, mY = 0;

  private boolean ignore_next_mouse = false;
  private boolean ignore_all_mouse = true;

  /** this gets all key events. */
  public boolean postProcessKeyEvent(KeyEvent e)
  {
    if (e.getID() == e.KEY_PRESSED) this.keyPressed(e);
    if (e.getID() == e.KEY_RELEASED) this.keyReleased(e);
    return true;
  }

  // default constructor
  public InputListener()
  {
    try
    {
      robot = new Robot();
    }
    catch (AWTException e) { System.out.println("Robot Creation Failed");}
  }

  /** Sets the mouse position */
  private void setMousePos(int x, int y)
  {
    ignoreNextMouseMove();
    robot.mouseMove(x, y);
  }

  /** Tracks the state of keys. */
  public void keyReleased(KeyEvent e)
  {
    keysdown[e.getKeyCode()] = false;
  }

  /** Tracks the state of keys. */
  public void keyPressed(KeyEvent e)
  {
    if (keysdown[e.getKeyCode()] == false)
    {
      if (e.getKeyCode() == e.VK_ESCAPE) GameFrame.exit();
      if (e.getKeyCode() == e.VK_E) GameFrame.player.selectNextSpell();
      if (e.getKeyCode() == e.VK_Q) GameFrame.player.selectPreviousSpell();
    }

    keysdown[e.getKeyCode()] = true;
  }

  /** This adds each mouse movement to the current delta */
  public void mouseMoved(MouseEvent e)
  {
    if (ignore_all_mouse) return;

    if(!ignore_next_mouse)
    {
      Point newpoint = e.getPoint();
      mX -= midscreen_x - newpoint.getX(); //update x
      mY -= midscreen_y - newpoint.getY(); //update y

      setMousePos(midscreen_x,midscreen_y);
    }
    else
    {
      ignore_next_mouse=false; //next one is not to be ignored
    }
  }

  /** This causes the listner to ignore the next mouse movement. */
  public void ignoreNextMouseMove()
  {
    ignore_next_mouse = true;
  }

  /** This starts the mouse recognition. */
  public void startMouseRead()
  {
    ignore_all_mouse = false;
  }


  /** Tracks mouse events. */
  public void mouseDragged(MouseEvent e)
  {
    // MouseDrags need to be treated just like MouseMoves
    mouseMoved(e);
  }

  /** This returns the total change in the mouse position since it was last checked.  */
  public Point lastMouseMove()
  {
    if (point == null) point = new Point();
    point.setLocation(mX, mY);

    mX = 0;//<-reset x
    mY = 0;//<-reset y

    return point;
  }

  /** This returns true if the key is down.
   * (uses KeyEvent.VK_* key codes)
   */
  public boolean keyDown(int key)
  {
    return keysdown[key];
  }

  /** This returns true if the left mouse button is down. */
  public boolean LbuttonDown()
  {
    return this.lmousedown;
  }

  /** This returns true if the right mouse button is down. */
  public boolean RbuttonDown()
  {
    return this.rmousedown;
  }

  /** Tracks mouse events. */
  public void mouseReleased(MouseEvent e)
  {
    if (e.getButton() == e.BUTTON1) this.lmousedown = false;
    if (e.getButton() == e.BUTTON2) this.rmousedown = false;
  }

  /** Tracks mouse events. */
  public void mousePressed(MouseEvent e)
  {
    if (e.getButton() == e.BUTTON1) this.lmousedown = true;
    if (e.getButton() == e.BUTTON2) this.rmousedown = true;
  }

  // these are required by the interface, but unused.
  public void keyTyped(KeyEvent e) {  }
  public void mouseExited(MouseEvent e) { }
  public void mouseEntered(MouseEvent e) {  }
  public void mouseClicked(MouseEvent e) {  }

}

That’s a class I fixed for someone a year ago.

Well, I have something similar…


public void mouseMoved(MouseEvent e)
{

  if (isRecentering && centerLocation.x == e.getX() && centerLocation.y == e.getY())
  {
    isRecentering = false;
  }
  else// legitimate mouse event
  {
    //get size of frame
    Dimension size = e.getComponent().getSize();
    centerLocation.x = size.width/2;
    centerLocation.y = size.height/2;


    //Calculate relative movement
    mouseX = e.getX() - centerLocation.x;
    mouseY = e.getY() - centerLocation.y;


    //Recenter mouse and 'disable' next mouse move
    isRecentering = true;
    robot.mouseMove(centerLocation.x, centerLocation.y);
                        
    }
}

Same idea I think. The robot generates and event, which is ignored until it is finished recentering. Like I said it works beautifully in Linux and Windows, but not OS X…

If you see a fatal mistake in mine, let me know…

Thanks!

Yea… this bit…

[...]
//Calculate relative movement
mouseX = e.getX() - centerLocation.x;
mouseY = e.getY() - centerLocation.y;
[...]

If the framerate and the mouse polling rate are pretty much in sync it should work rather well. By accident, that is.

Make that:

[...]
//Calculate relative movement
mouseX += e.getX() - centerLocation.x;
mouseY += e.getY() - centerLocation.y;
[...]

And when you pick those values up (once per frame), you’ve to set both vars (mouseX and mouseY) to 0.

So if there are two events for one frame… +5/-2 and +3/-1 it ends up with +8/-3 (instead of +3/-1 [your version]). And if there are two frames for one event it could end up with something like +5/-2 and 0/0 (instead of +5/2 and +5/2 [your version]).

Using some filtering method would smooth that case out, where you have more frames than mouse events, but it’s usually not important since usb runs usually @125hz and ps2 runs usually @60-100hz (which is high enough for smooth input).

I think I’m going to give up on getting it to work properly on OS X. I understand your code, and I’m actually doing something quite similar, but the accumulation is occuring in the Camera class, then every frame the Camera class is used to update the current view matrix. I left out some important code on my post…

The problem is that on OS X, it really just is not recentering. I noticed it before you helped me fix the cursor. You could move the cursor to the side of the frame and it would stay there until you moved the mouse again.

Anyways, I appreciate your help very much. I will investigate it more when I can, but for now, I need to focus on ‘finishing’ the game before Friday!!!