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

Gamepad support? #217

Open
ferociouslettuce29 opened this issue Sep 4, 2023 · 5 comments
Open

Gamepad support? #217

ferociouslettuce29 opened this issue Sep 4, 2023 · 5 comments

Comments

@ferociouslettuce29
Copy link

Are there plans or possibility to add controller navigation support? For example, the game may be ported to consoles or the UI can be operated using a controller on PC.

@texus
Copy link
Owner

texus commented Sep 4, 2023

I'm not sure how I could do that in a practical way. You can position widgets at any position and in any order, it would be difficult for TGUI to automatically detect what to do when it receives a gamepad input.

All input in your program is received in your code via the window library (SFML, SDL or GLFW), so you can read the controller input from there and call TGUI functions to respond to them (e.g. calling setFocused on the next widget if an arrow key is pressed). Nothing stops you from using a controller already, TGUI just doesn't help you in any way. If you have suggestions on things that I can change to the API to make it easier for you to use a controller then I'm of course interested to hear them.

@ferociouslettuce29
Copy link
Author

ferociouslettuce29 commented Sep 4, 2023

Hi, thanks for replying this topic.

https://github.com/natinusala/borealis
This is another UI library mainly based on controllers and consoles for reference.

The reason why I chose to use tgui is because that library is too intrusive for game logic, so I hope tgui can have built -in Gamepad support. I can't give you any professional advice. Maybe there is a special UI container such as NavigatableContainer, so that Gamepad can automatically navigate between such containers, and you can press A to enter this container to navigate in it. Navigate between sub-controls. For example, pressing B can return to navigating between containers. However, these are just some simple ideas. For details, you may need to look at how borealis or other UIs are designed, maybe you can refer to it.

another helpful discussion about UI's Controller Support.
mikke89/RmlUi#142

@texus
Copy link
Owner

texus commented Sep 6, 2023

TGUI is too low level for this. Pressing B will never navigate somewhere else, TGUI just shows what you tell it to, so you need to hide one group of widgets and show another group if you want to change the menu.

Having a NavigatableContainer that handles screens and moves focus is something that can be entirely build upon TGUI, it doesn't need to be included in the lib itself. If someone were to write it and contributed it then I would happily merge it into TGUI so that others don't also need to write it, but it is not something I can do myself. Writing such container requires actual experience with such UI designs to understand what the needs are. As someone who almost always uses a mouse to change settings in PC games, I would not be the best person to implement this.

If you have a complex scene then you need to somehow create a mapping between widgets, e.g. create a map of which widget will get focus after the previous one when the user presses an arrow key. If you already have to construct such mappings in your own code, then adding a few lines to actually access the map and move the focus yourself is comparably easy. So the only moment automatically handling the controller input makes sense to me is when the UI is simple/restricted, i.e. when widgets aren't atbitrarily placed on the screen and the design follows a certain set of rules (e.g. everything below each other with tabs at the top). The NavigatableContainer would need to enforce these rules, so that is becomes clear what pressing a down arrow actually needs to do, and that is the part that requires knowledge about how navigatable UI's typically look and operate.

For handling the arrow keys, TGUI can already do so some of the work, but even here different people are going to have different needs. If you are at the bottom of the screen, should the arrow down key move to the top again? If you reach the end of a row that contains multiple columns, should the right arrow key move to the next row or at the start of the same row? Even for the B button it isn't clear what you might want: sometimes you want to close a menu, sometimes you want to go to a previous screen, other times you want a popup message to be displayed warning the user about unsaved changes. These things can't be automated in TGUI, you would have to specify them yourself anyway.

Imagine you have several rows (in a VerticalContainer) which each contain several widgets (in a HorizontalContainer). As long as the default focusing behavior matches your needs, passing the controller input to TGUI only takes a few lines per controller button. And if the default behavior isn't what you want, then you need to define it yourself anyway, whether I let TGUI handle controller input directly or not.

if (event == arrow_down_event)
    gui.focusNextWidget(false);     // move focus to the next row (goes to the top if at bottom)
if (event == arrow_up_event)
    gui.focusPreviousWidget(false); // move focus to the previous row (goes to the bottom if on top)
if (event == arrow_right_event)
    gui.focusNextWidget(true);      // move focus to the next column (goes to start of next row if at end)
if (event == arrow_left_event)
    gui.focusPreviousWidget(true);  // move focus to the previous column (goes to end of previous row if at front)
if (event == right_shoulder_button)
    some_tabs->select((some_tabs->getSelectedIndex() + 1) % some_tabs->getTabsCount());
if (event == left_shoulder_button)
    some_tabs->select((some_tabs->getSelectedIndex() + some_tabs->getTabsCount() - 1) % some_tabs->getTabsCount());
if (event == B_button) {
    panel1->setVisible(false);
    panel2->setVisible(true);
}
if (event == A_button) {
    tgui::Event event;
    event.type = tgui::Event::Type::KeyPressed;
    event.key = {};
    event.key.code = tgui::Event::KeyboardKey::Space;
}

There are definitely parts that TGUI could do to make things simpler, e.g. don't require you to manually translate the A button to a space button press or move a slider value on D-pad presses. I'll probably revisit this issue in the future, but on a short to medium term I really don't see myself adding this into TGUI, the library currently focuses more on giving you the tools to write an UI and less about automatically positioning widgets in layouts and making it easy to navigate them. While this is something that I would love to have as well, it would be too much work to do properly.

@gleblebedev
Copy link

mikke89/RmlUi#519

@texus
Copy link
Owner

texus commented Oct 2, 2023

I've given this another look and I've decided to add the basic functionality to navigate between widgets with the arrow keys. While proper controller support is still very far away, this at least provides the foundation.

For backwards compatibility, in order to use the code, you first need to call gui.setKeyboardNavigationEnabled(true);
Afterwards you can specify which widget should be focused with the setNavigationUp, setNavigationDown, setNavigationLeft and setNavigationRight functions in the Widget class.

For example, button1->setNavigationDown(button2); will specify that pressing the down arrow while button1 is focused will cause the focus to move to button2. In the Gui Builder there are also properties where you can specify the name of the widget that should gain focus.

There is currently no way to automatically choose a widget to navigate to, it has to be specified manually for each direction. If some kind of NavigatableContainer is added in the future then all it would need to do is use the existing setNavigation functions to set the relation between the widgets though.

I looked into adding D-pad support as well as the arrow keys, but apparently SFML doesn't provide an easy way to get access to it. So for now you would have to manually translate controller inputs to arrow key presses in order to use a controller to navigate.

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

3 participants