hajimehoshi / ebiten

Ebitengine - A dead simple 2D game engine for Go
https://ebitengine.org
Apache License 2.0
10.78k stars 651 forks source link

internal/gamepad: non-gamepads are detected as gamepads on Linux #2039

Open divVerent opened 2 years ago

divVerent commented 2 years ago

(note: this only happens when the local user has been added to the "input" group; this is needed for games that use evdev to access gamepads)

I have a few computers where Ebiten detects non-gamepads as gamepads. This is usually harmless but wasteful, but in some cases can cause real issues.

I'm going to post examples of such devices here, more to come.

GamepadID 0
  GamepadAxisNum 8
  GamepadButtonNum 1
  GamepadName Goodix 
  GamepadSDLID 18000000160400008f03000060100000
  IsStandardGamepadLayoutAvailable false

First of all, why is the name just "Goodix"? The only device matching this that I have actually calls itself "Goodix Capacitive TouchScreen". According to evemu-describe, it has the following properties (condensed):

There is nothing obvious stating that it is NOT a gamepad.

Such a device can be an annoyance in a game with input settings dialog that listens to axis changes among other inputs to assign inputs to commands - touching something on screen (e.g. to exit selection) may be seen by a game as the new input event to assign which can get annoying. Also it clutters possible lists of gamepads.

divVerent commented 2 years ago

And here's my big spammer - the one that previousy exposed crashes in Ebiten:

GamepadID 0
  GamepadAxisNum 1
  GamepadButtonNum 69
  GamepadName ITE Tec
  GamepadSDLID 03000000cb060000f673000010010000
  IsStandardGamepadLayoutAvailable false
GamepadID 1
  GamepadAxisNum 7
  GamepadButtonNum 7
  GamepadName ITE Tec
  GamepadSDLID 03000000cb060000f673000010010000
  IsStandardGamepadLayoutAvailable false

The first one is a mystery, but must be the keyboard given:

Assuming that is true, it has:

The second one is actually "ITE Tech. Inc. ITE Device(8910) Touchpad" and has:

Just touching the screen activates two of the buttons, and finger pos on the touchpad is reported to the ABS_X and ABS_Y. This can be VERY annoying in an input settings dialog, where just moving the pointer is seen as button presses.

Sadly I can't suggest anything constructive for Ebiten to conclusively say they are NOT gamepads. ABS_X axis certainly exists on my gamepad too. The button enums are rather clearly not gamepad related and we might have luck excluding all multitouch or mouse specific buttons, which would already solve most of this. So maybe exclude any "gamepads" that don't at least have one gamepad specific button? IIRC some rudder devices don't have any buttons though, so that's not quite right either.

hajimehoshi commented 2 years ago

Interesting. Does this happen with GLFW?

divVerent commented 2 years ago

I didn't try with GLFW directly (how to do that?), but Ebiten 2.2.5 has this issue still, but less of it (to the point that it didn't crash anything on the device with the "spammy keyboard").

I'm gonna post another device, this time, as opposed to the other basically no-name devices (first one above was the "Topcom" 7 inch computer from Ali Express, and second one was an Acer Switch 10, but THIS one now is something really standard: a Lenovo ThinkPad E14):

GamepadID 0
  # NOTE: This one doesn't show up in Ebiten 2.2.5 (via GLFW, I guess).
  # However, on Ebiten 2.2.5, ID 0 is still "taken" and only ID 1 exists.
  GamepadAxisNum 1
  GamepadButtonNum 75
  GamepadName SONiX U
  GamepadSDLID 030000000f3200000d50000011010000
  IsStandardGamepadLayoutAvailable false
GamepadID 1
  # NOTE: This one does show up in Ebiten 2.2.5.
  GamepadAxisNum 10
  GamepadButtonNum 6
  GamepadName ETPS/2 
  GamepadSDLID 11000000455450532f32200000000000
  IsStandardGamepadLayoutAvailable false

The first one appears to be "SONiX USB DEVICE Consumer Control", which also has an ABS_VOLUME axis and lots of nonexisting buttons.

The second one is the "ETPS/2 Elantech Touchpad", which again has those mouse-ish and multitouch-ish buttons similar to the touchpad above.

divVerent commented 2 years ago

As I assume this is enough verification with GLFW, I'll try the "gold standard": SDL2. If any hack exists to fix this, I assume SDL2 has it. And indeed, SDL2 manages to ignore both "bad' devices but does accept my real gamepad. Wonder how they're doing that...

divVerent commented 2 years ago

SDL's logic to detect joystick-ish devices is this (including the early returns to make this show the correct condition) is rather ad hoc:

    /* X, Y, Z axes but no buttons probably means an accelerometer */
    if (test_bit(EV_ABS, bitmask_ev) &&
        test_bit(ABS_X, bitmask_abs) &&
        test_bit(ABS_Y, bitmask_abs) &&
        test_bit(ABS_Z, bitmask_abs) &&
        !test_bit(EV_KEY, bitmask_ev)) {
        return SDL_UDEV_DEVICE_ACCELEROMETER;
    }

    /* RX, RY, RZ axes but no buttons also probably means an accelerometer */
    if (test_bit(EV_ABS, bitmask_ev) &&
        test_bit(ABS_RX, bitmask_abs) &&
        test_bit(ABS_RY, bitmask_abs) &&
        test_bit(ABS_RZ, bitmask_abs) &&
        !test_bit(EV_KEY, bitmask_ev)) {
        return SDL_UDEV_DEVICE_ACCELEROMETER;
    }

        if (test_bit(BTN_TRIGGER, bitmask_key) ||
            test_bit(BTN_A, bitmask_key) ||
            test_bit(BTN_1, bitmask_key) ||
            test_bit(ABS_RX, bitmask_abs) ||
            test_bit(ABS_RY, bitmask_abs) ||
            test_bit(ABS_RZ, bitmask_abs) ||
            test_bit(ABS_THROTTLE, bitmask_abs) ||
            test_bit(ABS_RUDDER, bitmask_abs) ||
            test_bit(ABS_WHEEL, bitmask_abs) ||
            test_bit(ABS_GAS, bitmask_abs) ||
            test_bit(ABS_BRAKE, bitmask_abs)) {
            devclass |= SDL_UDEV_DEVICE_JOYSTICK; /* ID_INPUT_JOYSTICK */
        }

In addition, anything without a mapping is just a "joystick", not a "gamecontroller" - but that's a layer later, just like in Ebiten.

divVerent commented 2 years ago

GLFW's conditions, on the other hand, are just "must have EV_KEY and EV_ABS". I wonder why Ebiten 2.2.5 then doesn't show the keyboard.

divVerent commented 2 years ago

Ebiten had:

                // A gamepad can be detected even though there are not. Apparently, some special devices are
                // recognized as gamepads by GLFW. In this case, the number of the 'buttons' can exceeds the
                // maximum. Skip such devices as a tentative solution (#1173).
                if len(buttons) > driver.GamepadButtonNum {
                        continue
                }

So that's why keyboards were previously excluded: too many buttons :)

hajimehoshi commented 2 years ago

GLFW's conditions, on the other hand, are just "must have EV_KEY and EV_ABS". I wonder why Ebiten 2.2.5 then doesn't show the keyboard.

I think I just copied GLFW's implementation, but you meant Ebiten didn't so, right? Would imitating this way solve this issue?

divVerent commented 2 years ago

As I wrote above, raw GLFW has the same issue, but it was not quite as bad in Ebiten 2.2.5 as it skipped devices with too many buttons.

On Mon, Mar 28, 2022, 09:41 Hajime Hoshi @.***> wrote:

GLFW's conditions, on the other hand, are just "must have EV_KEY and EV_ABS". I wonder why Ebiten 2.2.5 then doesn't show the keyboard.

I think I just copied GLFW's implementation, but you meant Ebiten didn't so, right? Would imitating this way solve this issue?

— Reply to this email directly, view it on GitHub https://github.com/hajimehoshi/ebiten/issues/2039#issuecomment-1080667561, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAB5NMGNBQ57UHK46DXOKADVCGZJFANCNFSM5RZU6OEQ . You are receiving this because you authored the thread.Message ID: @.***>

hajimehoshi commented 2 years ago

https://github.com/hajimehoshi/ebiten/commit/d08f57e6106eabf50a09f4f91bfca1b566d9dea1 This change? I forgot why I removed this. I'll revisit this soon

hajimehoshi commented 2 years ago

I removed this logic wrongly when I introduced internal/gamepad package (probably. I'm checking this now). Reintroducing this means that we will add the restriction on numbers of buttons. So our changes in inpututil (#2027) will no longer be needed. @divVerent Is my understanding that correct?

If so, 1) I want to reintroduce this fix. 2) Our changes in inpututil is not valid in 2.2.5 so I'll revert them at least in 2.2.5.

hajimehoshi commented 2 years ago

Confirmed ef450580370cdf84f8795181d6898cfbaebae6e2 removed that logic.

divVerent commented 2 years ago

Sounds right.

Now I am not convinced that we should have a limit on button and axis count, but right now I cannot find any gamepad being sold that exceeds it.

However if you just reintroduce the button count limit, the touchpad issue remains - those also should not count as gamepads. That they have just two real axes and one button is the smaller issue - the bigger problem is that they behave rather illogical on the extra axes and buttons, which only make real sense when using the multitouch events to read them (they then exist once per finger).

On Tue, Mar 29, 2022, 11:39 Hajime Hoshi @.***> wrote:

Confirmed ef45058 https://github.com/hajimehoshi/ebiten/commit/ef450580370cdf84f8795181d6898cfbaebae6e2 removed that logic.

— Reply to this email directly, view it on GitHub https://github.com/hajimehoshi/ebiten/issues/2039#issuecomment-1082035813, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAB5NMAYGMO23W7J67QVWW3VCMPY7ANCNFSM5RZU6OEQ . You are receiving this because you were mentioned.Message ID: @.***>

hajimehoshi commented 2 years ago

Now I'm thinking about the touchpad issue (ITE Tech. Inc. ITE Device(8910) Touchpad). Did this happen with the original GLFW? (Sorry if you have already answered)

divVerent commented 2 years ago

Yes, it happened with GLFW too, so this part is not a regression.

In my own game it is not very serious and just spams stderr a bit, as I reject gamepads without standard layout mapping - this however may affect games with an ingame remapping menu more.

On Thu, Mar 31, 2022, 13:29 Hajime Hoshi @.***> wrote:

Now I'm thinking about the touchpad issue (ITE Tech. Inc. ITE Device(8910) Touchpad). Did this happen with the original GLFW? (Sorry if you have already answered)

— Reply to this email directly, view it on GitHub https://github.com/hajimehoshi/ebiten/issues/2039#issuecomment-1084901516, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAB5NMBQOOK56XDGXL7NRO3VCXOINANCNFSM5RZU6OEQ . You are receiving this because you were mentioned.Message ID: @.***>

divVerent commented 2 years ago

As for touchpads, I wonder if we should just go an SDL-ish route, except maybe even simpler: require at least one gamepad specific button OR at least one gamepad specific axis.

Right now, on Linux the following buttons likely indicate a gamepad:

These sure do:

This is a bit more than what SDL matches. As for axes, what SDL does seems to be as reasonable as it gets :( but it seems to me like ABS_HAT* should also all be included in the supported axes.

Furthermore, I'd recommend not even mapping anything outside these regions to Ebiten buttons, however this may be too late now as it would be a breaking change to fix even for gamepad devices in case e.g. a gamepad and a tocuhpad share the same device node (could imagine that on devices like the GPD Win ones, but never had one). Maybe make this a TODO for a later version. Not sure if even possible or if this would break interpretation of SDL_GameControllerDB mappings.

hajimehoshi commented 2 years ago

require at least one gamepad specific button OR at least one gamepad specific axis.

I think it is possible to have a gamepad without axes. On the other hand, buttons must exist. I'll try the former way.

hajimehoshi commented 2 years ago

@divVerent Does this branch https://github.com/hajimehoshi/ebiten/tree/issue-2039-btn work to you?

hajimehoshi commented 2 years ago

Oops, this doesn't work my Linux (on Parallels) with a PS4 gamepad... The recognized buttons are out of _BTN_0-9:

304
305
307
308
310
311
312
313
314
315
316
317
318
divVerent commented 1 year ago

same for my xbox compatible one - it has buttons in the BTN_GAMEPAD range.

And I bet some only have them in the BTN_JOYSTICK range. However some others have them all in the BTN_MISC range.

Also, for BTN_MISC ones, my touchpads have BTN_0 but no higher ones, so your change would not even exclude those touchpads.

On Sat, Apr 9, 2022, 01:46 Hajime Hoshi @.***> wrote:

Oops, this doesn't work my Linux (on Parallels) with a PS4 gamepad... The recognized buttons are out of _BTN_0-9:

304 305 307 308 310 311 312 313 314 315 316 317 318

— Reply to this email directly, view it on GitHub https://github.com/hajimehoshi/ebiten/issues/2039#issuecomment-1093711808, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAB5NMCXMWFLNS3Y2MZKZYTVEEKRXANCNFSM5RZU6OEQ . You are receiving this because you were mentioned.Message ID: @.***>