Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ImGui-SFML keyboard and gamepad input support #51

Closed
eliasdaler opened this issue Apr 8, 2018 · 13 comments
Closed

ImGui-SFML keyboard and gamepad input support #51

eliasdaler opened this issue Apr 8, 2018 · 13 comments

Comments

@eliasdaler
Copy link
Contributor

eliasdaler commented Apr 8, 2018

UPD: It's here, check it out!

Hey everyone! So, ImGui 1.60 got released and keyboard/gamepad navigation looks really sweet. There are some things that I want to discuss before implementing them.

So, there's this enum:

{
    // Gamepad Mapping
    ImGuiNavInput_Activate,      // activate / open / toggle / tweak value       // e.g. Circle (PS4), A (Xbox), B (Switch), Space (Keyboard)
    ImGuiNavInput_Cancel,        // cancel / close / exit                        // e.g. Cross  (PS4), B (Xbox), A (Switch), Escape (Keyboard)
    ImGuiNavInput_Input,         // text input / on-screen keyboard              // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard)
    ImGuiNavInput_Menu,          // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard)
    ImGuiNavInput_DpadLeft,      // move / tweak / resize window (w/ PadMenu)    // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard)
    ImGuiNavInput_DpadRight,     // 
    ImGuiNavInput_DpadUp,        // 
    ImGuiNavInput_DpadDown,      // 
    ImGuiNavInput_LStickLeft,    // scroll / move window (w/ PadMenu)            // e.g. Left Analog Stick Left/Right/Up/Down
    ImGuiNavInput_LStickRight,   // 
    ImGuiNavInput_LStickUp,      // 
    ImGuiNavInput_LStickDown,    // 
    ImGuiNavInput_FocusPrev,     // next window (w/ PadMenu)                     // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)
    ImGuiNavInput_FocusNext,     // prev window (w/ PadMenu)                     // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch) 
    ImGuiNavInput_TweakSlow,     // slower tweaks                                // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)
    ImGuiNavInput_TweakFast,     // faster tweaks                                // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch)

So, most of the time Dpad is PovX/PovY, but sometimes the Y axis on dpad is inverted (on Linux).
Left stick is X/Y, I don't know if any gamepad has it differently. And other keys (A, B, X, Y, etc.) are totally different for all the gamepads.

Here's what I want to do - by default it'll map to XInput/Xbox 360 gamepad input, as it's the most popular controller for the PC. Is it a good idea? Or maybe not? Maybe users should do all the mapping themselves?

As for button bindings, I think I'll provide an interface like this:

ImGui::SFML::SetGamepadBinding(ImGuiNavInput_Activate, 0); 
// maps "0" ("A" on Xbox 360 gamepad) to activation button
  • Handling axes is a bit harder, probably users will need to set thresholds for D-pad and stick, so that only if axis is more than that value, we'll say that "Down/Left/Right/Up" is pressed for a stick or a D-pad.

  • And of course, users will need to tell ImGui-SFML which controller to use. Something like

ImGui::SFML::SetActiveGamepad(2); // gamepad with id 2

ImGui-SFML should probably then check for this joystick's disconnection event so that if it gets disconnected, it won't poll its state incorrectly. I think that if id won't be set, the gamepad support will be disabled.

There'll also be a function for a keyboard input enabling/disabling. Something like:

ImGui::SFML::SetKeyboardNavigationEnabled(true);

Okay, any other concerns? I think we'll probably will need a lot of them during the testing, but if you have something to say now - please do, it'll make the implementation easier.

@Alia5
Copy link
Contributor

Alia5 commented Apr 8, 2018

by default it'll map to XInput/Xbox 360 gamepad input, as it's the most popular controller for the PC.

I think it'll be fine. In addition to that, Steam hooks XInput on Windows in case of a SteamController / DS4

probably users will need to set thresholds for D-pad and stick

Can you provide 'sane' defaults? So users will only need to change the threshold if really needed

@eliasdaler
Copy link
Contributor Author

I think it'll be fine. In addition to that, Steam hooks XInput on Windows in case of a SteamController / DS4

Awesome.

Can you provide 'sane' defaults? So users will only need to change the threshold if really needed

Sure. I'll test on two gamepads and try to find the ones that are good enough at least for these two: I have Xbox 360 gamepad and Logitech F310.

@dabbertorres
Copy link
Contributor

I have a wireless Xbox One controller I could test with.

@eliasdaler
Copy link
Contributor Author

Neat. I'll notify you when the testing will be needed. :)

@Ironbell
Copy link

Ironbell commented Apr 9, 2018

Sounds fine to me in general.
For axis threshold defaults: I found a value of 50 (0.5) for an axis felt good for joysticks as well as for using triggers as buttons (I used an XBox 360 controller).

My concern about having the user bind the buttons is the following: As you noticed, axes are different on different controllers. When the user of your library binds for example the button 12 to ImGuiNavInput_Menu, because he's using a playstation controller, the enduser can only use a playstation controller.

Or would you expect the user to detect the controller type and then do the mapping dependent on it? That's how I did it to support both XBox and Playstation controllers. (https://github.com/tizian/Cendric2/blob/feature/controller_support/src/Controller/GamepadController.cpp)

You could also have different defaults for your ImGuiNavInput depending on different controller types and only have the user map them if they really need it.

About setting the active gamepad: You could also default to the first connected one and poll events JoystickConnected and JoystickDisconnected to update it. Unless you want to have support for multiple controllers at once.

@eliasdaler
Copy link
Contributor Author

ImGui-SFML won't try to detect the type of the gamepad. It'll just set Xbox 360 mapping by default and then the users will be able to change it if it's needed later (e.g. if they check for gamepad type and see that it's a PS4 one).

As for the gamepadId... I'm now considering possible behaviours for gamepads:

  1. Get events from all the gamepads, so that if two gamepads are connected, the user will be able to manipulate ImGui using both of them. But this has one problem: I won't be able to poll state. I'll have to track it using events and store the state of the gamepad somewhere. And conflicts are unavoidable. If left stick is pressed "Up" one one gamepad and "Down" on the second one, we'll say that the value of left stick's Y is 0.
  2. Detect first joystickId and use it. JoystickConnected and JoystickDisconnected won't have influence on it, unless the disconnected gamepad has joystickId equal to currently used. In the case of disconnection, we can just iterate joystickIds again and set the first connected one as active.

Example:
Gamepad A and B are connected to PC. Gamepad A has id = 0, B has id = 1. On startup A is set as active one. If it gets disconnected, B is automatically set as active.

If user wants to use gamepad "B" instead of "A", they'll be able to set active gamepad id via a function call, e.g.

ImGui::SFML::SetActiveGamepad(1);

@Ironbell
Copy link

Ironbell commented Apr 9, 2018

I'd strongly advise to go for 2., 1. will most likely cause confusion.
Your example sounds good & like an intuitive behavior.

@eliasdaler
Copy link
Contributor Author

Okay. It'll much easier to implement it as well, which is very good. :)

@eliasdaler
Copy link
Contributor Author

Here's the branch
Keyboard and gamepad implemented. Please test it and tell me what you think, before I do the merge into master. :)

@eliasdaler
Copy link
Contributor Author

eliasdaler commented Apr 20, 2018

See this for controls and more info on gamepads.
To test the gamepad navigation, add these lines to simple example after ImGui::SFML::Init call:

ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;

and for keyboard navigation it'll be:

ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;

@dabbertorres
Copy link
Contributor

Working great over here!
(tested keyboard and gamepad navigation - gamepad is a wireless (non-bluetooth) Xbox One controller)

@Ironbell
Copy link

Looking good! Also tested keyboard and gamepad navigation with a non-wireless Xbox One and 360 controller.

@eliasdaler
Copy link
Contributor Author

Merged into "master". Feels free to open new issues if any problems arise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants