If You Can't Read Your Keyboard, Read This Topic

I’m new at JInput and just got it figured out for keyboard input. The doesn’t seem to be alot of documentation about this. There’s tidbits here and there, but there doesn’t seem to be one tutorial that spells everything out.

For this reason, I’m posting this topic about some of the pitfalls. I haven’t figure out mouse and gamepad input yet, but some of these pitfalls should apply to them too.

When you download jinput_combined_dist_latest.zip from https://jinput.dev.java.net/ , you must extract all the files into your classpath somehow. You always need jinput.jar, and you’ll also need one or more binary files depending upon your OS. It’s .dll for Windows, .so for Linux, and .jnilib for Mac OS X. This part isn’t too hard to figure out. If you can get the test programs to work, you should be able to get your own code to work too.

The first thing your program must do is read all the controllers. That only requires the following two lines of code:

ControllerEnvironment controllerEnvironment =
	ControllerEnvironment.getDefaultEnvironment();
Controller[] aController = controllerEnvironment.getControllers();

That isn’t hard, but now you need to do something with those controllers. I propose that you split them up by type. You need to store all the controllers of each type so that you can poll them all, not just the first one. Some people store just one controller, and it might be the wrong one. This is probably most often the case when people have all kinds of weird pointer devices that they don’t actually use.

Here’s my code for separating the controllers:

public class ControllerManager {
/**Constructor.
 */
public ControllerManager() {
	//find all the controllers
	ControllerEnvironment controllerEnvironment =
		ControllerEnvironment.getDefaultEnvironment();
	Controller[] aController = controllerEnvironment.getControllers();
	
	//separate the controllers into groups
	int numControllers = aController.length;
	for(int iController = 0; iController < numControllers; iController++) {
		Controller controller = aController[iController];
		
		//figure out which group to put the controller into
		Controller.Type controllerType = controller.getType();
		if(controllerType == Controller.Type.KEYBOARD)
			aKeyboard.add((Keyboard)controller);
		else if(controllerType == Controller.Type.MOUSE)
			aMouse.add((Mouse)controller);
		else if(controllerType == Controller.Type.TRACKBALL ||
			controllerType == Controller.Type.TRACKPAD)
		{
			if(controller instanceof Mouse)
				aMouse.add((Mouse)controller);
		} //end if the controller is a trackball or trackpad
		else if(controllerType == Controller.Type.GAMEPAD)
			aGamepad.add(controller);
	} //end for each controller
	
	//list the types of controllers found
	int numKeyboards = aKeyboard.size();
	int numMice = aMouse.size();
	int numGamepads = aGamepad.size();
	System.err.println("Controllers Found" +
		"\nGamepads: " + numGamepads +
		"\nKeyboards:" + numKeyboards +
		"\nMice/trackballs/trackpads: " + numMice +
		"\nUnknown: " + (numControllers - (numGamepads + numKeyboards + numMice)));
} //end constructor

//PRIVATE VARIABLES//////////////////////////////////////////////////////////////////////
//controllers
private final MutableArray<Controller> aGamepad = new MutableArray<Controller>();
private final MutableArray<Keyboard> aKeyboard = new MutableArray<Keyboard>();
private final MutableArray<Mouse> aMouse = new MutableArray<Mouse>();
} //end class ControllerManager

MutableArray is just my version of ArrayList. The only other weirdness is that I just dumped trackballs and trackpads in with mice. I’m not sure how this works out, but I imagine that’s what should be done with them.

Now, you need some way to read the controllers. Since I’ve only dealt with keyboards so far, that’s all we’re going to look at. The straightforward way to check all your keyboards is the following:

/*WARNING: THIS CODE WILL NOT WORK*/
Component.Identifier.Key key = /*whatever key you want to poll*/;
int numKeyboards = aKeyboard.size();
for(int iKeyboard = 0; iKeyboard < numKeyboards; iKeyboard++) {
	Keyboard keyboard = aKeyboard.get(iKeyboard);
	if(keyboard.isKeyDown(key)) {
		isPressedNow = true;
		break;
	}
} //end for each keyboard

This will not work. It will never detect key presses. This is because you have to call the poll method to make the keyboard check which keys are pressed. The correct code is listed below:

Component.Identifier.Key key = /*whatever key you want to poll*/;
int numKeyboards = aKeyboard.size();
for(int iKeyboard = 0; iKeyboard < numKeyboards; iKeyboard++) {
	Keyboard keyboard = aKeyboard.get(iKeyboard);
	keyboard.poll();
	if(keyboard.isKeyDown(key)) {
		isPressedNow = true;
		break;
	}
} //end for each keyboard

There is still one minor issue. Since the controllers are only detected during the constructor, any devices plugged in after the constructor is called won’t be detected. The inverse is not a problem; if a controller is unplugged after the constructor is called, it won’t hurt anything. (I tested this by unplugging a USB keyboard from my laptop while my program was running.) You could just detect all the controllers every time you poll for input, but detecting controllers takes close to 2 seconds on my computer. Clearly, that’s too long.

I’m not going to say anything about what you do with key presses when they happen. That’s covered pretty well in Developing Games in Java, even though that book doesn’t use JInput. I just posted this topic so that anyone who had a problem with JInput would be able to easily find some kind of solution.

If anyone else wants to post any solutions to beginner problems with reading keyboard input using JInput, this would probably be a good thread to post it in.

Hi

The more information user have of jinput the better. Everything you mentioned so far is in the getting started thread, so it must not be clear there. Do you have any suggestions on what needs to be rewritten in a clearer way?.

Using isKeyDown for every key someone is using (especially if they are detecting typing for usernames/text) might get a bit tedious. As of version 2 of JInput you can get events from the device instead of checking each key in turn. Hopefully this post explains it :slight_smile:

HTH

Endolf

My problem was that I skimmed the two intro/introduction threads and then stopped reading before the getting started thread. The information I needed was there, but I read the information around it instead of what I needed. I would almost say it would better to have less threads stickied, but the real issue is that I didn’t read enough of them.

None of them jumped out at me as being what I needed, despite the fact that the relevant thread was called “Getting started with JInput”. I parsed that title as being another introduction thread and assumed it was about setting up the .dlls and so forth, which I had no problem with.

So I don’t think anything needs to be changed unless there’s some way the getting started thread can be made to seem more important. Maybe the Getting Started link on https://jinput.dev.java.net/ should link directly to that thread instead of just to this forum. It looks like it’s supposed to, but there seems to be some kind of error.