RFC: joypad input with LWJGL3

A bit of background: gamepad support is currently plagued by a few issues, expecially with LWJGL3, which are unlikely to get solved in the short term.

So I’ve made a few experiments with GLFW: Input guide and bypassed InputManager and InputMapper. Early results looks promising. Now I’d like to have InputMapper to handle the events to the application, like:

 //I've detected a gamepad input and must forward it to the listener
 inputMapper.listeners.notifyStateChanged(...)

Problem is, listeners is private so I can’t just do that. Possible solutions:

  • fork Lemur and provide a getter for listeners (bad)
  • buid another layer on top of InputMapper and GLFW that wraps everything (not good either: yet another hardware abstraction layer)
  • somehow register and drive the input to the InputMapper (how?)
  • ???

Any suggestion is welcome, thanks!

Maybe another option would be to replace InputManager with your own that works? As you long as you do it before GuiGlobals.initialize() then Lemur’s InputMapper will grab yours.

Are your fixes something that could be included in InputManager?

The GLFW part works basically like this:

    if (state.buttons[GLFW_GAMEPAD_BUTTON_A])
    {
       inputMapper.listeners.notifyStateChanged("jump"...);
    }

Which might sound a step backward from the elegant InputMapper, because I’m mapping an ‘almost physical’ input to a direct gameplay action (without the Input abstraction provided by JME & Lemur)…

But the point is, the mapping is updated on an almost daily basis (and is updatable by the end user) so we can safely assume that the mapping “just works” if you use an Xbox-like controller, which is precisely my target.

Unfortunately, this approach bypasses completely InputMapper so I can’t think of a simple way to make both cohexist in a elegant way.

What does this mean?

The way you’ve described it, you are bypassing elegance and want to continue doing so by calling the listeners directly. I’m not sure I understand why you can’t just keep a reference to your own listeners in that case and also add them to InputMapper.

…if you are trying to make a general “every game can use it approach” then fixing the real problems that caused this approach to be necessary seems like the right way. Else, add listener place1 and add listener place2 seems pretty elegant.

Edit: do note that by bypassing the “abstractions” that InputMapper provides (whichever way it’s done) then you also lose combos because the “abstraction” is a bit more than just an abstraction in this case and InputMapper actually keeps track of input-combos. “UP” versus “UP + L1”, for example.

The compatibility layer is this one GitHub - gabomdq/SDL_GameControllerDB: A community sourced database of game controller mappings to be used with SDL2 Game Controller functionality , ; by looking at the commit log it looks updated very frequently.

Looks a nice idea but I probably need about 70% more words to fully understand how to do it, otherwise I’ll try to figure out by myself :slight_smile:

Sure, I do agree that JME solutions are elegant (and in fact, this thread exists because I want to leverage it). The problem, is that it doesn’t work 100%, expecially with LWJGL3. Even the TestJoystick (i.e. the bare minimum) don’t even get all the input buttons or don’t get them reliably. I guess that it worked well with LWJGL2 (which indeed, did) and then InputManager was shoehorned into GLFW. I basically resorted to “pseudo low level” GLFW out of desperation.

The best I can think of is:

MyGame implements StateFunctionListener {
...
  MyGLFWLibrary.register(this, functionID);
}

MyGLFWLibrary {

public void register(Statefunctionlistener l){
 listeners.add(l);
}

public void update(float tpf){
if (GLFW.PRESSED_A) {
listeners.valuechanged(functionID);
}
}


}

By the way, on my build I’ve commented out this line

…because otherwise I get just flooded with this warning. Again, fairly sure this didn’t happen with LWJGL2.

It looks like I’m stuck. The input works, and I’ve worked around the limitations for buttons, but if I want to use 4-way navigation with Dpad then I must use F_X_AXIS and F_X_AXIS FunctionIDs.

I see only 2 possible options:

  1. Manage GLFW input from InputMapper: then the RawInputListener should be modified, which means breaking compatibility and basically making GLFW mandatory. NOPE
  2. Add the ability to Lemur to set programmatically the status of a FunctionId (i.e. emulate the pressing of an input)
  3. Extend InputMapper to do the above, then plug it in at runtime (leaving Lemur untouched)

Please @pspeed let me know!

Given that I’m still using lwjgl2 for a variety of reasons, I have limited ability to help with this… so option 3 may be your best bet for now. When we know what that looks like then we can see what changes might be needed to Lemur to make that easier or even unnecessary.

So… like this?

GuiGlobals.getInstance().setInputMapper(new GLFWInputMapper());

I made up the code above as I don’t see a hook to plug in my InputMapper… please tell me! :slight_smile:

It looks like I did not make this easy.

The idea would be to extend GuiGlobals with your custom initialization and then call setInstance() instead of initialize(). But InputMapper appears to be one of those things where I though “Why would anyone ever change this?!?”

The class needs a design touch-up.

At this point, your only reasonable option may be to fork Lemur until I can fix this design issue.

2 Likes

Fixed that for you :stuck_out_tongue: