NullPointerException thrown from Poll() method

I’ve got a project using jInput for gamepad input. I rolled my own class to provide polling-update functionality (a thread that polls the controllers constantly for a change in button state) so that my classes can be notified when the state of one of the buttons changes on the gamepad. The problem is, that a few of my users are having troubles where a NullPointerException is being thrown (apparently) from the poll() method.

Here is the stacktrace:

java.lang.NullPointerException
at net.java.games.input.DIControllers.getNextDeviceEvent(DIControllers.java:62)
at net.java.games.input.DIAbstractController.getNextDeviceEvent(DIAbstractController.java:62)
at net.java.games.input.AbstractController.poll(AbstractController.java:219)
at com.astruyk.freetar.input.Gamepad.updateButtonStates(Gamepad.java:123)
at com.astruyk.freetar.input.GamepadPoller.startPolling(GamepadPoller.java:91)
at com.astruyk.freetar.editor.MusicEditor.initButtonConfig(MusicEditor.java:561)
at com.astruyk.freetar.editor.MusicEditor.<init>(MusicEditor.java:111)
at com.astruyk.freetar.editor.MusicEditor.main(MusicEditor.java:2093)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javaws.Launcher.executeApplication(Unknown Source)
at com.sun.javaws.Launcher.executeMainClass(Unknown Source)
at com.sun.javaws.Launcher.continueLaunch(Unknown Source)
at com.sun.javaws.Launcher.handleApplicationDesc(Unknown Source)
at com.sun.javaws.Launcher.handleLaunchFile(Unknown Source)
at com.sun.javaws.Launcher.run(Unknown Source)
at java.lang.Thread.run(Unknown Source) 

the com.astruyk.freetar.* classes are my own. The initbuttonconfig() method in the Music Editor calls the GamepadPoller’s startPolling() method, which activates javax.swing.Timer with the following intialization code:

pollTimer = new Timer(POLL_TIME, new ActionListener(){
            public void actionPerformed(ActionEvent e){
                pollController();
            }
        });

The pollController() method calls the controllers poll() method (via a wrapper class - Gamepad) , and the exception is being thrown - at least, thats what I think is happening from the stackTrace.

I’m not familiar with the jInput code, and I was wondering if anyone might have any idea what is causing this issue, or what I might do to fix it for my users? For now I guess I’ll just wrap the poll() in a try{}catch block for NullPointerException - but I thought I should report the issue anyways.

Hi

I’ve looked at the jinput source where this is happening, and it looks like it can’t map the object information in the event into a component. This is just a hash table lookup. It’s possible that the poll is being called before the initialisation has finished, but I can’t tell from the code you have provided.

Is your source available online somewhere?

I’m particularly interested in the following 2 lines and surrounding calls

at com.astruyk.freetar.input.Gamepad.updateButtonStates(Gamepad.java:123)
at com.astruyk.freetar.input.GamepadPoller.startPolling(GamepadPoller.java:91)

Cheers

Endolf

The full source isn’t available at the moment anywhere, but here’s the code you are interested in:

    public synchronized void startPolling() {
        // Get the last state of all the components of the controller
        gamepad.poll();
        pressedLastUpdate.clear();
        for(Button currentButton : gamepad.getButtons()){
            pressedLastUpdate.put(currentButton, currentButton.isPressed());
        }
        pollTimer.start();
    }

Last night I refactored the gamepad.updateButtonStates() to gamepad.poll() to more closely match its intended functionality - so here’s the source for the gamepad.poll()

   public void poll(){
        controller.poll();
    }

Gamepad contains its own Controller Class - and also an array of Button objects associated with the gamepad.
Button is basically a wrapper for Component, with a couple subclasses so that I can handle analog and HAT-switch input as button presses rather than true-analog inputs. I had to create these classes so I could handle analog stick movements as button presses simply by calling .isPressed() rather than doing a bunch of checks each time for the type of Component I’m working with…

I’m not sure if you need it, but here’s the code that the Timer calls when it is activated. It is in the GamepadPoller class (the class in charge of repeatedly polling the controller and generating events after button updates). This code is called by the Timer each time it runs.

    public synchronized void pollController() {
        // Recheck the states of the components of the watched controller
        gamepad.poll();
        for (Button currentButton : pressedLastUpdate.keySet()) {
            if (pressedLastUpdate.get(currentButton) != currentButton.isPressed()) {
                ButtonEvent.EventType eventType = null;
                if (currentButton.isPressed()){
                    eventType = ButtonEvent.EventType.BUTTON_PRESSED;
                }else{
                    eventType = ButtonEvent.EventType.BUTTON_RELEASED;
                }
                ButtonEvent evt = new ButtonEvent(
                        gamepad,
                        currentButton,
                        eventType);
                for(GamepadButtonListener observer : observers){
                    observer.buttonActionTriggered(evt);
                }
                pressedLastUpdate.put(currentButton, currentButton.isPressed());
            }
        }
    }

As you can see, the ControllerPoller contains a Map<Button, Boolean> (pressedLastUpdate) that stores the state of the button at the last call to pollController() - so that it can tell when the button state has changed.

If this isn’t enough code for you to figure out whats going on, I can send you a copy of the relevant code from my input package…

Is there a way I can block until I’m sure the initialization is finished? If not, how can I avoid calling the poll() method before the controller is finished initializing?

Peering into the debugger - I can’t see anything overtly wrong with the DIAbstractController’s event_queue state, the head and tail both are 0, and the queue seems to be full of [component=null, value=0, nanos=0] values, and there doesn’t appear to be null keys or values in the id_to_components hashmap.

After doing some debugger-sleuthing, it appears that the error originates at the

public final DIComponent mapObject(DIDeviceObject object) {
		return (DIComponent)object_to_component.get(object);
	}

method in the IDirectInputDevice.java file - object_to_component does not contain the correct DIDeviceObject. This causes the call from to the line highlighted below (from DIControllers.java) to return null:

	public final static synchronized boolean getNextDeviceEvent(Event event, IDirectInputDevice device) throws IOException {
		if (!device.getNextEvent(di_event))
			return false;
		DIDeviceObject object = device.mapEvent(di_event);
		int event_value;
		if (object.isRelative()) {
			event_value = object.getRelativeEventValue(di_event.getData());
		} else {
			event_value = di_event.getData();
		}
		DIComponent component = device.mapObject(object); // <-----------------------------------------------------
		event.set(component, component.getDeviceObject().convertValue(event_value), di_event.getNanos());
		return true;
	}

And the the event.set() line causes the the nullPointerException.

This ‘unknown’ object is present in the IDirectInputDevice’s variable (‘object’ in the above context) ArrayList ‘objects’, but not in the ‘object_to_component’ HashMap. This ‘unknown’ object - has a name String that identifies it as “Axis 6” - and oddly enough an ‘id’ field with a ‘null’ value in it.

I’ll do some more sleuthing to see if I can dig up why the rogue “Axis 6” component is being created in the first place - or why its not present in the object_to_component hashmap. I’m guessing that there’s some obscure error going on with the actual gamepad hardware - something that’s causing the actual jInput Component to fail to be created (so it can’t be added to the object_to_component HashMap), but that allows it to get far enough to make it into the ‘objects’ list of the Controller. … I’ll try looking for the place where the object_to_component var is populated, might provide some insight…

Perhaps you can think of a case where an ‘object’ could be created, but not successfully mapped to a Component?

Hi

Right, the object will not get registered if the component identifier can’t be looked up. I suspect that the switch statement in IDirectInputDevice.getIdentifier is hitting the default part and returning null.

Can I suggest you stick a debug statment in there and dump out the value of guid_type, type and instance.

HTH

Endolf

Here ya go. you were right that its returning null from that method - here’s the info you asked for:

guid_type = 11
type = 2
instance = 6

Hi

This guid_type is ‘unknown’ type, so I’ve made it so that on that fiven guid_type it returns Component.Identifier.Axis.UNKOWN which is also new. I’ve only got linux to compile on atm (I’m at work), so I can’t test it, but I have commited the change to CVS. If you could checkout the source and compile it, and test it, that would be very helpful.

Cheers

Endolf

I’ll give it a shot as soon as I can. Sorry for the delay - got busy there for a while :slight_smile: