Console spamming bug when gamepad disconnect

Hello,

I am trying to controller connection listener but there is a primary problem when disconnect the connected gamepad.

In this case Logger spamming like this;

Jan 12, 2018 9:04:44 PM net.java.games.input.ControllerEnvironment log
INFO: Failed to poll device: Failed to poll device (8007000c)

Jan 12, 2018 9:04:44 PM net.java.games.input.ControllerEnvironment log
INFO: Failed to poll device: Failed to poll device (8007000c)

Jan 12, 2018 9:04:44 PM net.java.games.input.ControllerEnvironment log
INFO: Failed to poll device: Failed to poll device (8007000c)

I searched the spamming reason in source codes and i think i found it.

com.jme3.input.lwjgl.JInputJoyInput.update() method contains

if( !c.poll() )
continue;

if we must to look at poll method. Here;

net.java.games.input.AbstractController.poll()

public synchronized boolean poll() {
     Component[] components = getComponents();
	try {
		pollDevice();
		for (int i = 0; i < components.length; i++) {
			AbstractComponent component = (AbstractComponent)components[i];
			if (component.isRelative()) {
				component.setPollData(0);
			} else {
				// Let the component poll itself lazily
				component.resetHasPolled();
			}
		}
		while (getNextDeviceEvent(event)) {
			AbstractComponent component = (AbstractComponent)event.getComponent();
			float value = event.getValue();
			if (component.isRelative()) {
				if (value == 0)
					continue;
				component.setPollData(component.getPollData() + value);
			} else {
				if (value == component.getEventValue())
					continue;
				component.setEventValue(value);
			}
			if (!event_queue.isFull())
				event_queue.add(event);
		}
		return true;
	} catch (IOException e) {
		ControllerEnvironment.logln("Failed to poll device: " + e.getMessage());
		return false;
	}
} 

Why this notification being more than once? is not enough a notification that the connection is broken? Why does it have to spamming console trough the whole game? By the way if re-connect the gamepad, notifications are not stopping.

thanks for reading.

I don’t know… none of us wrote that code. It’s in the library we just use, right? net.java.games.input

Right source is net.java.games.input but our com.jme3.input.lwjgl.JInputJoyInput.update() method calls this source

I mean that;

if( !c.poll() )
continue;

code is reason of this spamming. Because it runs the

catch (IOException e) {
	ControllerEnvironment.logln("Failed to poll device: " + e.getMessage());
	return false;
}

code on every frame.

Yes, but if we don’t call poll() then none of the joysticks will ever work… which I guess does at least solve the reported problem.

Edit: or are you just suggesting that when poll() returns false that we should stop calling it?

Edit: or are you just suggesting that when poll() returns false that we should stop calling it?

I guess, yea… Why not ? If we cant resolve the disconnect problem by reconnect gamepad, why we get this notifications on every frame during remaining game time?

The quick solution would be to adjust the classes error level. Warn or something. Please don’t discourage logs :o

if we want a mid-game add or remove controller system, we dont need quick solutions because, when the gamepad removed -so the poll method returns false-, we need remove ids or other stuff related with removed controller from inputManager for next connections. Actually I guess, if we can do it there will not be spamming already.

I searched old topics for this system is i am talking about. There is an old topic and no result.

We must get over it controller detect system. All new games has that ability to if there is a gamepad connection the controls changed for gamepads and whe disconnection the controls returns keyboard+mouse state.

Well, one reason is because let’s say you have two gamepads connected… disconnecting one would cause both to stop working if we stop calling poll. Want to use the other controller to navigate the menus to exit/restart the game? Tough.

Edit: actually, nevermind me… since I see it’s controller specific now. The components thing in JInput always messed me up.

But there are other Situations where Polling might fail for only one frame.

The much better solution would be to see if there is an api to check whether the Controller is disconnected and then react to it (Maybe with an event)

when debug run i detect the problem exacly.

ControllerEnvironment ce = ControllerEnvironment.getDefaultEnvironment();
Controller c = ce.getController(); <— this c always return the opening same value when gamepad connected or disconnected. I mean if i cut connection of my gamepad the c never changing. This is not logical and LWJGL’s problem.

Possible solution is ;

public void update() {
        ControllerEnvironment ce =
            ControllerEnvironment.getDefaultEnvironment();

        Controller[] cs = ce.getControllers();
        Event e = new Event();
        for (int i = 0; i < cs.length; i++){
            Controller c = cs[i];
            
            JInputJoystick stick = joystickIndex.get(c);
            if( stick == null )
                continue;
                
            if( !c.poll() ){
                joystickIndex.remove(c); //<- here is the wizard.
                continue;
            }

//bla bla

This error also happens if you switch between XInput and DirectInput8 on my gamepad.
I still can’t get my head around how to deal with more than one gamepad and how it “knows” which key is to map on which controller. I use the Lemurs input handling com.simsilica.lemur.input.InputMapper and I have kinda recipe that works but it is a total mystery to me how it actually works and how it can provide mappings for more than one controller.
As well I would like to detect what mode (i.e. XInput or DirectInput8) I’m in but have not a clue… Wonder if there is some docu or examples or something I could look at.

Meaning you don’t fully understand how to use Lemur’s support for multiple controllers or you don’t understand how Lemur implemented its support?

Both tbh, but mainly how to use Lemur’s support for multiple controllers.

As well I tried to figure out how to get the controller name so I could implement a customized key names as on my nacon controller it is a “1” where it is “B” on the nintendo controller and an “X” on the PS4 controller.

At the moment I just map Keys and jostick buttons to “something” I don’t see the joystick… But I might be just blind and it is drectly in front of me.

here is an example (my current game does read it from a file and is a bit less straight forward so I took an older game, but same principle). I can not see in this code where it knows which gamepad, it looks to me that this is only for one and if there are two it just picks one of the two…

package ch.artificials.bg.view.states.player;

import com.jme3.input.KeyInput;
import com.simsilica.lemur.input.Axis;
import com.simsilica.lemur.input.Button;
import com.simsilica.lemur.input.FunctionId;
import com.simsilica.lemur.input.InputMapper;
import com.simsilica.lemur.input.InputState;

public class PlayerMovementFunctions {

    public static final String G_MOVEMENT = "Movement";
    public static final String G_ACTION = "Action";

    public static final FunctionId F_X_ROTATE_MOUSE = new FunctionId(G_MOVEMENT, "RotateMouse");
    public static final FunctionId F_X_ROTATE_KEYBOARD = new FunctionId(G_MOVEMENT, "RotateKeyboard");
    public static final FunctionId F_X_ROTATE_CONTROLER = new FunctionId(G_MOVEMENT, "RotateControler");

    public static final FunctionId F_THRUST = new FunctionId(G_MOVEMENT, "Thrust");
    public static final FunctionId F_STRAFE = new FunctionId(G_MOVEMENT, "Strafe");
    public static final FunctionId F_BOOST = new FunctionId(G_MOVEMENT, "Boost");

    public static final FunctionId F_SHOOT = new FunctionId(G_ACTION, "Shoot");
    public static final FunctionId F_LAUNCH = new FunctionId(G_ACTION, "Launch");
    public static final FunctionId F_TAKE_SCREENSHOT = new FunctionId(G_ACTION, "Take Screenshot");

    public static void initializeDefaultMappings(InputMapper inputMapper) {

        if (!inputMapper.hasMappings(F_THRUST)) {
            inputMapper.map(F_THRUST, InputState.Negative, Axis.JOYSTICK_LEFT_Y);
            inputMapper.map(F_THRUST, KeyInput.KEY_W);
            inputMapper.map(F_THRUST, InputState.Negative, KeyInput.KEY_S);
        }

        if (!inputMapper.hasMappings(F_STRAFE)) {
            // Strafing is setup similar to move.
            inputMapper.map(F_STRAFE, Axis.JOYSTICK_LEFT_X);
            inputMapper.map(F_STRAFE, KeyInput.KEY_D);
            inputMapper.map(F_STRAFE, InputState.Negative, KeyInput.KEY_A);
        }

        if (!inputMapper.hasMappings(F_X_ROTATE_MOUSE)) {
            inputMapper.map(F_X_ROTATE_MOUSE, Axis.MOUSE_X);
        }

        if (!inputMapper.hasMappings(F_X_ROTATE_KEYBOARD)) {
            inputMapper.map(F_X_ROTATE_KEYBOARD, KeyInput.KEY_RIGHT);
            inputMapper.map(F_X_ROTATE_KEYBOARD, InputState.Negative, KeyInput.KEY_LEFT);
        }
        
        if (!inputMapper.hasMappings(F_X_ROTATE_CONTROLER)) {
            inputMapper.map(F_X_ROTATE_CONTROLER, Axis.JOYSTICK_RIGHT_X);
        }

        if (!inputMapper.hasMappings(F_SHOOT)) {
            inputMapper.map(F_SHOOT, Button.JOYSTICK_RIGHT2);
            inputMapper.map(F_SHOOT, KeyInput.KEY_SPACE);
            inputMapper.map(F_SHOOT, Button.MOUSE_BUTTON1);
        }

        if (!inputMapper.hasMappings(F_LAUNCH)) {
            inputMapper.map(F_LAUNCH, Button.JOYSTICK_LEFT2);
            inputMapper.map(F_LAUNCH, KeyInput.KEY_UP);
            inputMapper.map(F_LAUNCH, Button.MOUSE_BUTTON2);
        }

        if (!inputMapper.hasMappings(F_TAKE_SCREENSHOT)) {
            inputMapper.map(F_TAKE_SCREENSHOT, KeyInput.KEY_P);
        }

    }

}

And I ask because the testers for my demo stuck mainly because of issues with the gamepad. For example if I run my gamepad with XInput instead DirectInput8 the R1,2,3 and L1,2,3 are not functional (they probably are axis there). And the player has not a clue what a jostick_button1 is :slight_smile: he wants to read X or B or 1 depending on the controller.

1 Like

So by “more than one controller” you mean “different controllers”. Versus “two player cooop, two controllers at once” type of thing.

Lemur is somewhat slave to JME’s mappings… which is sort of slave to jinput’s mapping on some levels.

The “multiple controllers at once” answer was going to be easier. The other probably deserves a separate thread.

1 Like

Ok. Yes I found the Lemur mapping which maps all the buttons to more straight forward names on a gamepad. And I saw Lemur does this for all possible joystick. But let’s say I have plugged in two controller, which one will Lemur / Jme take? I cant see that. Both together? One of them?
And is there a better way to handle different kind of gamepads and is it even possible to know which type of controller is connected with Lemur?
EDIT: Shall I start a new thread for this?

Yeah, it’s probably best. Both because it’s off topic for this thread and because it might help others if it’s labeled properly and they have the same issue.