MrStahlfelge/gdx-controllerutils

Mapping display names

kennycason opened this issue · 4 comments

Hi :)

So far this library has worked amazing btw. My current question is how do i get a display name for the buttons per controller. For example, on PS4 the A button is really the X button, and the Y button is actually the Triangle button.

I'm wanting to display these names so user's can see what keys map to what in the pause screen. Currently I'm about to write my own mini library of a few key mapping display names.

There's no more information available than the internal button name, so if you connected a PS4 controller you should be aware that games will ask you to press Y and not the triangle button.

There are also some Nintendo-like controllers where A and B and X and Y are swapped.

But of course I am interested in your solution you already come up with.

For sure, I imagine for your implementation it would involve expanding the controller database to have a map from button to display name for each controller entry. That may be a JamePad issue though, so forgive me if i'm posting in the wrong place. :)

Since my game has a controller class that wraps your implementation and decorates it with other useful functions to my game, I added a getDisplayName(control: GameControl) function so that I could show what the keys are in places like pause menus and dialogues. (Obviously telling a user to pressY if they are using a PlayStation controller would not be a good experience).

My down and dirty solution which is FAR from complete was to just satisfy a few controllers and call it a day, but I recognized that an update to the controller database with this meta information would probably be best.

My dirty solution was to just do something like this:

    private fun buildDisplayNames(controller: AdvancedController): MutableMap<Int, String> {
        val displayNames: MutableMap<Int, String> = HashMap()

        val name = if (controller.name != null) {
            controller.name.trim().toLowerCase()
        } else {
            ""
        }

        if (name.contains("xbox") || name.contains("x-box")) {
            displayNames[controller.mapping.buttonX] = "Square"
            displayNames[controller.mapping.buttonY] = "Triangle"
            displayNames[controller.mapping.buttonA] = "X"
            displayNames[controller.mapping.buttonB] = "O"
            displayNames[controller.mapping.buttonL1] = "L BUMPER"
            displayNames[controller.mapping.buttonR1] = "R BUMPER"
            displayNames[controller.mapping.buttonL2] = "L TRIGGER"
            displayNames[controller.mapping.buttonR2] = "R TRIGGER"
            displayNames[controller.mapping.buttonBack] = "BACK"
            displayNames[controller.mapping.buttonStart] = "START"
        }
        else if (name.contains("playstation") || name.contains("ps4") || name.contains("ps3")) {
            displayNames[controller.mapping.buttonX] = "Square"
            displayNames[controller.mapping.buttonY] = "Triangle"
            displayNames[controller.mapping.buttonA] = "X"
            displayNames[controller.mapping.buttonB] = "O"
            displayNames[controller.mapping.buttonL1] = "L BUMPER"
            displayNames[controller.mapping.buttonR1] = "R BUMPER"
            displayNames[controller.mapping.buttonL2] = "L TRIGGER"
            displayNames[controller.mapping.buttonR2] = "R TRIGGER"
            displayNames[controller.mapping.buttonBack] = "SHARE"
            displayNames[controller.mapping.buttonStart] = "OPTIONS"
        }
        else if (name.contains("nintendo") || name == "pro controller") {
            displayNames[controller.mapping.buttonX] = "Y"
            displayNames[controller.mapping.buttonY] = "X"
            displayNames[controller.mapping.buttonA] = "B"
            displayNames[controller.mapping.buttonB] = "A"
            displayNames[controller.mapping.buttonL1] = "L BUMPER"
            displayNames[controller.mapping.buttonR1] = "R BUMPER"
            displayNames[controller.mapping.buttonL2] = "L TRIGGER"
            displayNames[controller.mapping.buttonR2] = "R TRIGGER"
            displayNames[controller.mapping.buttonBack] = "MINUS"
            displayNames[controller.mapping.buttonStart] = "PLUS"
        }
        else if (name.contains("logitech")) {
            displayNames[controller.mapping.buttonX] = "X"
            displayNames[controller.mapping.buttonY] = "Y"
            displayNames[controller.mapping.buttonA] = "A"
            displayNames[controller.mapping.buttonB] = "B"
            displayNames[controller.mapping.buttonL1] = "L BUMPER"
            displayNames[controller.mapping.buttonR1] = "R BUMPER"
            displayNames[controller.mapping.buttonL2] = "L TRIGGER"
            displayNames[controller.mapping.buttonR2] = "R TRIGGER"
            displayNames[controller.mapping.buttonBack] = "BACK"
            displayNames[controller.mapping.buttonStart] = "START"
        }
        else { // tuck head and pray these work :)
            displayNames[controller.mapping.buttonX] = "X"
            displayNames[controller.mapping.buttonY] = "Y"
            displayNames[controller.mapping.buttonA] = "A"
            displayNames[controller.mapping.buttonB] = "B"
            displayNames[controller.mapping.buttonL1] = "L BUMPER"
            displayNames[controller.mapping.buttonR1] = "R BUMPER"
            displayNames[controller.mapping.buttonL2] = "L TRIGGER"
            displayNames[controller.mapping.buttonR2] = "R TRIGGER"
            displayNames[controller.mapping.buttonBack] = "SELECT"
            displayNames[controller.mapping.buttonStart] = "START"
        }

        return displayNames
    }

I then of course pass the displayNames map into my controller implementation. Which does something like: displayNames.get(buttonMapper.get(control));

It's not even Jamepad territory, the controller db is SDL's territory (where the Jamepad's native implementation is based on). So best approach is to suggest the change to the SDL framework's maintainers, then Jamepad could adopt that and we could use it. But we are talking about years here. :)

@MrStahlfelge got it, thanks! Upon posting this I realized it's going to likely fall to a lower level library. Was not aware it went all the way back to SDL's territory. I'll explore whether I should create an issue for it or just continue my workaround. :)