Joystick in Java with JInput

Posted: September 2, 2012 in Uncategorized

I got Logitech Double Action gamepad from a friend and I wondered how can I use it in Java and I come acrose JInput. Then I made a test program, something like what you can find in Windows. You can download this program and its source code at the bottom of this post.

JInput Joystick Test

How to use JInput?

Here is newer and better version of this post and program.

To use joystick in your java games or apps you can use JInput. First download latest release of it (current is jinput_nightly_20120831.zip). You can also download JInput javadoc to link it with NetBeans or you can look it online here.

First you need to move JInput files to certain places and link jar file to your project. I will describe how I did it in NetBeans, probably is almost the same with Eclipse.

  1. First unzip jinput zip package that you downloaded and move “jinput.jar” somewhere for later use, I usually copy jar libraries files into my java installation dir (C:\Program Files \Java\) and then link them to project from there.
  2. Then you need to move other files into root director of your project. JInputJoystickTest root folder
  3. Now go to NetBeans and click on folder named “Libraries” in your project with right mouse button and select “Add JAR/Folder…” then locate “jinput.jar” file. Now should jar file be visible in “Libraries” folder.

Adding jar file to a project in NetBeans

Now that you put all JInput files/libraries where they need to be, you can start using JInput. Note that files (jinput-dx8.dll, jinput-raw.dll, …) that you put into your root folder of a project are used when you run project inside the NetBeans. When you will build your project you will need to copy this files (jinput-dx8.dll, jinput-raw.dll, …) into folder where your game/app jar file will be (into “dist” folder, inside your project folder when you build a project). File “jinput.jar” will be copied automatically.

Using JInput in code

For easier and cleaner use I wrote one additional class called JInputJoystick. I will explain how to use this class, so click on the link, download it and copy it to your project source folder among your other classes/files. If you don’t want to use this class, you can look at it to see how to use JInput directly. You can also download JInputJoystick javadoc.


// First you need to create controller.
JInputJoystick joystick = new JInputJoystick(Controller.Type.STICK, Controller.Type.GAMEPAD);

When I created a controller, I put two types of a controller to the method (you can also put just one type), one is a stick type and other is a gamepad. I also put stick type in, because my Logitech Dual Action gamepad is recognized as a stick type. I also used Xbox MadCatz gamepad to test and it was recognized as a gamepad type. And there it is a little difference between those two types. Xbox controller have 6 axis, Logitech Dual Action controller have 4 axis. And thous axis, right and left joystick that you use with your thumbs, don’t have the same name.
So (I’m just guessing that) controllers with 4 axis are, in JInput, recognized as a stick type and controllers with 6 axis as a gamepad type. So it’s probably good to make your game/app for both, stick and gamepad type.

Names of axis:

  • Xbox MadCatz
    • left joystick: X Axis and Y Axis
    • right joystick: X Rotation and Y Rotation
    • third “joystick” that you use with your pointer fingers: Z Axis
  • Logitech Dual Action
    • left joystick: X Axis and Y Axis
    • right joystick: Z Axis and Z Rotation

After you create controller, is good to check if any controller was found.


// Check if the controller was found.
if( !joystick.isControllerConnected() ){
   System.out.println("No controller found!");
   // Do some stuff.
}

Now that you have created joystick you need to pull that joystick for current data. You need to do this always before using joystick components data. Put this on start of your loop.


// Get current state of joystick! And check, if joystick is disconnected.
if( !joystick.pollController() ) {
   System.out.println("Controller disconnected!");
   // Do some stuff.
}

Using joysticks:


// Left controller joystick
int xValuePercentageLeftJoystick = joystick.getXAxisPercentage();
int yValuePercentageLeftJoystick = joystick.getYAxisPercentage();

// Right controller joystick
int xValuePercentageRightJoystick, yValuePercentageRightJoystick;

// stick type controller
if(joystick.getControllerType() == Controller.Type.STICK)
{
   // Right controller joystick
   xValuePercentageRightJoystick = joystick.getZAxisPercentage();
   yValuePercentageRightJoystick = joystick.getZRotationPercentage();
}
// gamepad type controller
else
{
   // Right controller joystick
   xValuePercentageRightJoystick = joystick.getXRotationPercentage();
   yValuePercentageRightJoystick = joystick.getYRotationPercentage();

   // If Z Axis exists.
   if(joystick.componentExists(Component.Identifier.Axis.Z)){
      int zAxisValuePercentage = joystick.getZAxisPercentage();
   }
}

As mentioned before axis names of the left controller joystick are the same for stick and gamepad type, but names of axis for the right controller joystick are different, so we need to put an if else statement and get right joystick data with diferent methods.
There’s another, better/easier/cleaner way to do this. There are some methods that you can use to get data for right joystick regardless of controller type. Here’s the code with the same data as before but with different methods:


// Left controller joystick
int xValuePercentageLeftJoystick = joystick.getX_LeftJoystick_Percentage();
int yValuePercentageLeftJoystick = joystick.getY_LeftJoystick_Percentage();

// Right controller joystick
int xValuePercentageRightJoystick = joystick.getX_RightJoystick_Percentage();
int yValuePercentageRightJoystick = joystick.getY_RightJoystick_Percentage();

// If controller is a gamepad type.
if(joystick.getControllerType() == Controller.Type.GAMEPAD)
{ // Must check if controller is a gamepad, because stick type controller also have Z axis but it's for right controller joystick.
   // If Z Axis exists.
   if(joystick.componentExists(Component.Identifier.Axis.Z)){
      int zAxisValuePercentage = joystick.getZAxisPercentage();
   }
}

I this examples I used methods that returns joystick values in percentages, int numbers from 0 to 100. You can also use methods that returns float numbers from -1.0 to 1.0.
I should also tell that when I tested Xbox MadCatz gamepad controller, I got -1.52… value for Z axis in idle mode (when I didn’t move “joystick” that you use with your pointer fingers).

Using Hat switch:


float hatSwitchPosition = joystick.getHatSwitchPosition();

if(Float.compare(hatSwitchDirection, Component.POV.OFF) == 0){
  // Hat switch is not pressed. The same as Component.POV.CENTER
}else if(Float.compare(hatSwitchPosition, Component.POV.UP) == 0){
   // Do stuff when UP is pressed.
}else if(Float.compare(hatSwitchPosition, Component.POV.DOWN) == 0){
   // Do stuff when DOWN is pressed.
}else if(Float.compare(hatSwitchPosition, Component.POV.LEFT) == 0){
   // Do stuff when LEFT is pressed.
}else if(Float.compare(hatSwitchPosition, Component.POV.RIGHT) == 0){
   // Do stuff when RIGHT is pressed.
}else if(Float.compare(hatSwitchPosition, Component.POV.UP_LEFT) == 0){
   // Do stuff when UP and LEFT is pressed.
}else if(Float.compare(hatSwitchPosition, Component.POV.UP_RIGHT) == 0){
   // Do stuff when UP and RIGHT is pressed.
}else if(Float.compare(hatSwitchPosition, Component.POV.DOWN_LEFT) == 0){
   // Do stuff when DOWN and LEFT is pressed.
}else if(Float.compare(hatSwitchPosition, Component.POV.DOWN_RIGHT) == 0){
   // Do stuff when DOWN and RIGHT is pressed.
}

Using joystick buttons:


// Number of buttons.
int numberOfButtons = joystick.getNumberOfButtons();

// Button one on the controller.
boolean joystickButton_1 = joystick.getButtonValue(0);

If variable “joystickButton_1″ is true then button one is pressed.

Closure

There are also some other methods that you can use, so look at javadoc of this JInputJoystick class and also look at JInput javadoc so that you will know what else can you use.

In JInputJoystickTest_source_code.zip package you can find class called JInputJoystickTest.java that you can use to see all controllers connected to your computer and its components. This class content was written by java-gaming.org forum user Endolf, you can find his posts about JInput on http://www.java-gaming.org/index.php/topic,16866.0, his post were my basis to work with JInput, so thanks you Endolf.

Downloads

To download, click on a link and then click File >> Download.

JInputJoystick.java – Additional class for easier and cleaner use of JInput.
JInputJoystick_Javadoc.html – Java doc for JInputJoystick.java class.

JInputJoystickTest.zip – Program for testing joystick.
JInputJoystickTest_source_code.zip – Program source code.

Folder containing all the above files.

About these ads
Comments
  1. carlos says:

    I have a mat pad , but doesnt work :( do you know how work _?

  2. TheUzo007 says:

    Try to use JInputJoystickTest.java class to see all controllers and its components, try to implement components one by one.

  3. carlos says:

    How can I create an event with joystick? here’s the code where I want to create the event. Any chance you could help me? http://pastebin.com/embed.php?i=8QpkLfV5

  4. TheUzo007 says:

    I think that you can’t set any listeners for events except for the controllerRemoved and controllerAdded.
    You need to check for states of components (buttons, joysticks) that you are interested into in a while loop.
    Look at JoystickTest.java into method stickOrGamepadTypeJoystick_Test_Better, in this method is while loop. In while loop first poll controller for current state/data and then use/check controller components states and make actions according to the state of buttons, joysticks.

  5. carlos says:

    thank´s !!!

  6. rsdnt says:

    excellent library! really help me out to control a rc car over wifi with my xbox360 controller! thank you so much

  7. Elecmike2k says:

    Great blog offering clear concept and instructions. Thanks!!

    Your JInputJoystick.java DOES run with Saitek P990 gamepad. However the following function occasionally causes IndexOutOfBoundException:

    /**
    * Gets value of required button.
    *
    * @param index Index of a button in array list.
    * @return True if button is pressed, false otherwise.
    */

    //Here is your original code:
    public boolean getButtonValue(int index)
    {
    return buttonsValues.get(index);
    }

    // Here is my WORKAROUND to avoid hang the application who calls it.

    public boolean getButtonValue(int index)
    {
    boolean buttonPressed = false;

    if(index >>>> index out of bounds ERROR! index: ” + index + ” buttonsValues.size: ” + buttonsValues.size() );
    }
    return buttonPressed;
    }

    //Here is the console output that index sometimes is greater or eaqual to buttonsValues.size():

    >>>>> index out of bounds ERROR! index: 5 buttonsValues.size: 14
    >>>>> index out of bounds ERROR! index: 5 buttonsValues.size: 14
    >>>>> index out of bounds ERROR! index: 5 buttonsValues.size: 1
    >>>>> index out of bounds ERROR! index: 4 buttonsValues.size: 4
    >>>>> index out of bounds ERROR! index: 4 buttonsValues.size: 1

    I have TWO questions:
    Q1. buttonsValues.size() should be a fixed number for a specific gamepad (i.e., Saitek P990), how its value keep changing (14, 1, 4) ?

    Q2. The first two lines of the console output, apparently index are 5 and buttonsValues.size() are 14, the code flow is supposed to go to if(index < buttonsValues.size()), but it actually go through else part.

    Could you help me understand?

    Thanks a lot,
    Mike

  8. TheUzo007 says:

    Every time that pullController() method in JInputJoystick.java is called, method gets controller components (Component[] components = controller.getComponents();) and then it goes through all components and fills the buttonsValues arraylist again. It looks like it doesn’t gets all the components. Is it possible that controller variable is overwritten or something?
    Did you test joystick with program JInputJoystickTest.jar did buttons work?
    Did you try JInputJoystickTest.java, does that class return the same and correct number of buttons every time?

    public boolean getButtonValue(int index)
    {
    try {
    return buttonsValues.get(index);
    } catch (Exception e) {
    System.err.println(“Error: JInputJoystick.java -> getButtonValue(int index): “);
    System.err.println(e.getMessage());
    }

    return false;
    }

  9. Dani says:

    First of all thank you very much for this tutorial.

    I got this error message:
    Exception in thread “main” java.lang.NullPointerException
    at joystick.JInputJoystick.getXRotationValue(JInputJoystick.java:363)
    at joystick.JInputJoystick.getXRotationPercentage(JInputJoystick.java:376)
    at joystick.JInputJoystick.getX_RightJoystick_Percentage(JInputJoystick.java:543)
    at joystick.JoystickTest.stickOrGamepadTypeJoystick_Test_Better(JoystickTest.java:99)
    at joystick.JoystickTest.main(JoystickTest.java:45)

    Do you have any idea why is not working?
    Thanks

  10. TheUzo007 says:

    Probably your joystick don’t have Component.Identifier.Axis.RX component, or it is named differently. Use program that list all components so that you can see which components you have.

    • Dani says:

      Thank you very much for your response.

      These are the controllers that I got:
      JInput version: 2.0.6-b1568

      HID Keyboard Device
      Standard PS/2 Keyboard
      HID-compliant mouse
      Synaptics PS/2 Port TouchPad
      Thrustmaster T-Mini Wireless 3-in-1
      USB Receiver
      USB Receiver
      USB Receiver
      USB Receiver

      These are the components of my joystick:
      Thrustmaster T-Mini Wireless 3-in-1
      Type: Gamepad
      Component count: 18
      Component 0: Button 1
      Identifier: 0
      ComponentType: Absolute Digital
      Component 1: Button 2
      Identifier: 1
      ComponentType: Absolute Digital
      Component 2: Button 3
      Identifier: 2
      ComponentType: Absolute Digital
      Component 3: Button 4
      Identifier: 3
      ComponentType: Absolute Digital
      Component 4: Button 5
      Identifier: 4
      ComponentType: Absolute Digital
      Component 5: Button 6
      Identifier: 5
      ComponentType: Absolute Digital
      Component 6: Button 7
      Identifier: 6
      ComponentType: Absolute Digital
      Component 7: Button 8
      Identifier: 7
      ComponentType: Absolute Digital
      Component 8: Button 9
      Identifier: 8
      ComponentType: Absolute Digital
      Component 9: Button 10
      Identifier: 9
      ComponentType: Absolute Digital
      Component 10: Ministick Left
      Identifier: 10
      ComponentType: Absolute Digital
      Component 11: Ministick Right
      Identifier: 11
      ComponentType: Absolute Digital
      Component 12: Button 12
      Identifier: 12
      ComponentType: Absolute Digital
      Component 13: Hat Switch
      Identifier: pov
      ComponentType: Absolute Digital
      Component 14: Z Rotation
      Identifier: rz
      ComponentType: Absolute Analog
      Component 15: Z Axis
      Identifier: z
      ComponentType: Absolute Analog
      Component 16: Y Axis
      Identifier: y
      ComponentType: Absolute Analog
      Component 17: X Axis
      Identifier: x
      ComponentType: Absolute Analog

      Still do you think the problem are the components? Could you please give an example about changing one of the components in the code (like before and after).
      Which the brand version of the joystick that you used?
      THANKS A LOT FOR YOUR SUPPORT!!!

      • TheUzo007 says:

        I used Xbox MadCatz (gamepade type) and Logitech Dual Action (stick type) joysticks.

        I listed all components of my Logitech Dual Action and the components are the same except mine doesn’t have Ministick Right and Left, It appers like your joystick is of a stick type, but it says that it is a gamepade.
        Try this: in JoystickTest.java use stickOrGamepadTypeJoystick_Test method and in this method change line if(joystick.getControllerType() == Controller.Type.STICK) into if(true), this way it will call methods for stick type. If this will work then, your joystick should probably be of a stick type.

      • Dani says:

        Same error massage.
        I would like to give you some more information.
        If I compare my GUI with the example GUI these are the differences and similarities:
        - The controller name label is working well (it display the name of my controller).
        - In the Axes part I have everything like in the example but two things. The point in the middle of the square is not moving and the progress bars are completely empty all the time
        - In the buttons part I just have the rectangle in which all the buttons are contained but none of the buttons are there.
        - In the Hat Switch part there isn’t any circle.

        Thanks again in advantaged for your help

      • TheUzo007 says:

        It can’t be the same error message because other methods are called if you did as I said.

      • Dani says:

        Sorry but I got the same error. (you can send me an e-mail to have yours) this is my e-mail I send you a pic with the modification and the same error.
        Thanks,
        Dani

  11. Arthur says:

    regarding multiple controllers: if I have a list of JinputJoystick objects and I try to poll any of them, it only polls the first one found, and the other controllers get the same outputs as the first one only… any ideas?

  12. TheUzo007 says:

    When I had been writing this JinputJoystick.java I did not take into account that you can have multiple connected joysticks, did not thought of this. So I wrote initController method the way that save first controller that it’s found. You will have to rewrite this method.

    For only two joystick you can use this, add this into JinputJoystick.java:
    New additional constructor:
    /**
    * Creates a controller, of one of the types that has been given and ignore (does not save) given controller.
    * Controller type which is first found will be created unless it is the same as given firstController.
    *
    * @param controllerType_1 Desired controller type.
    * @param controllerType_2 Desired controller type.
    * @param firstController Controller to ignore.
    */
    public JInputJoystick(Controller.Type controllerType_1, Controller.Type controllerType_2, Controller firstController)
    {
    initialize();
    initSecondController(controllerType_1, controllerType_2, firstController);
    }

    And this two new methods:
    /**
    * Save first founded controller of given type and ignore (does not save) given controller.
    *
    * @param controllerType_1 Desired controller type.
    * @param controllerType_2 Desired controller type.
    * @param firstController Controller to ignore.
    */
    private void initSecondController(Controller.Type controllerType_1, Controller.Type controllerType_2, Controller firstController)
    {
    Controller[] controllers = ControllerEnvironment.getDefaultEnvironment().getControllers();

    for(int i=0; i < controllers.length && controller == null; i++) {
    if(
    controllers[i].getType() == controllerType_1 ||
    controllers[i].getType() == controllerType_2 &&
    controllers[i] != firstController
    )
    {
    controller = controllers[i];
    break;
    }
    }
    }

    /**
    * Joystick controller.
    *
    * @return This object/joystick controller.
    */
    public Controller getController(){
    return this.controller;
    }

    So when you will creat second joystick use this new constructor and use getController() method to get controller of a first joystick.

  13. bjorn says:

    when i pluged in my joystick to your testprogram I wanted to see the percetage value’s on the screen so i extended the window class with some panels and labels to get the values on my screen. that’s when I noticed that the values that my joystick gave when in neutral were 49 instead of 50.
    i found the problem and it was in the calculation. when it rounds to integer it can give a slight miscalculation. so i replaced it by the following:
    PercentageValue=100-(int)(((RawValue-1)/-2)*100).
    maybe this is any use for you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s