jgeumlek / MoltenGamepad

Flexible Linux input device translator, geared for gamepads
MIT License
275 stars 42 forks source link

Cannot map TL2 & TR2 on Speedlink THUNDERSTRIKE SL-6545-BK #129

Open ChristophFranzen opened 2 months ago

ChristophFranzen commented 2 months ago

NOTICE: Sorry, I just saw that I have mistyped the name of the device, and copied the wrong name to several places. The correct name (and use in file names) is "SL-6515-BK", the wrong one is "SL-6545-BK". Perhaps this is causing the problem of "weird implicit assumptions" described below. <—No: TESTED: Correcting the name in all places does not change anything in the behaviour described below. I leave the comments here instead of updating the whole text below to only use the correct name.

Hello,

I tried to get the "Thunderstrike" gamepad to work; the result: many hours of testing, and still no success.

Here's the "native" event list copied over from "evtest":

Input` driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x79 product 0x6 version 0x110
Input device name: "Microntek              USB Joystick          "
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 288 (BTN_TRIGGER)
    Event code 289 (BTN_THUMB)
    Event code 290 (BTN_THUMB2)
    Event code 291 (BTN_TOP)
    Event code 292 (BTN_TOP2)
    Event code 293 (BTN_PINKIE)
    Event code 294 (BTN_BASE)
    Event code 295 (BTN_BASE2)
    Event code 296 (BTN_BASE3)
    Event code 297 (BTN_BASE4)
    Event code 298 (BTN_BASE5)
    Event code 299 (BTN_BASE6)
  Event type 3 (EV_ABS)
    Event code 0 (ABS_X)
      Value    128
      Min        0
      Max      255
      Flat      15
    Event code 1 (ABS_Y)
      Value    128
      Min        0
      Max      255
      Flat      15
    Event code 2 (ABS_Z)
      Value    128
      Min        0
      Max      255
      Flat      15
    Event code 5 (ABS_RZ)
      Value    128
      Min        0
      Max      255
      Flat      15
    Event code 16 (ABS_HAT0X)
      Value      0
      Min       -1
      Max        1
    Event code 17 (ABS_HAT0Y)
      Value      0
      Min       -1
      Max        1
  Event type 4 (EV_MSC)
    Event code 4 (MSC_SCAN)
  Event type 21 (EV_FF)
    Event code 80 (FF_RUMBLE)
    Event code 81 (FF_PERIODIC)
    Event code 88 (FF_SQUARE)
    Event code 89 (FF_TRIANGLE)
    Event code 90 (FF_SINE)
    Event code 96 (FF_GAIN)
Properties:
Testing ... (interrupt to exit)

As you can see, they've used BTN_TRIGGER (which I assume is meant for the first button of old, simple, non-gamepad joysticks) for the first button, and simply continued the assignment by increasing the key code by one for the 11 remaining "normal" buttons. This is a severe problem, because even "configurable" games, where you can remap buttons to in-game functions, ignore the events from most of the "special" buttons, so you cannot use them.

Oddly, the right stick uses the two "Z" axis events. This seems to be related to the problem I have with MG.

The game pad has got a "mode" button, but that does not trigger an event on its own. Pressing it without pressing any other button produces events for the primary left stick's ABS_X and ABS_Y with the center values 128 (LED off->on), and 127 (LED on->off). It just changes the mode of operation, indicated through the LED. The event list doesn't change, but in the startup mode with LED=off, misleadingly named "digital", the "hat" events from the d-pad on the left side are remapped to the left stick events, and the right stick's events are remapped to the 4 "direction" buttons on the right side, so the startup mode after attaching the pad produces less different events, because the left stick and the d-pad do the same, as well as the right stick and the 4 buttons. So you generally want to use it in the "analogue" mode with LED=on.

So I've created a "generic driver definition" as follows, using the "gamepad" profile in my first attempt:

# Speedlink THUNDERSTRIKE SL-6545-BK
# iManufacturer = "Microntek"
# iProduct      = "USB Joystick"
#[name="DragonRise Inc. PC TWIN SHOCK Gamepad"]
[vendor=0079 product=0006]

# Options
name = "THUNDERSTRIKE_SL-6545-BK"
devname = "thstr_"
exclusive = "false"
change_permissions = "false"
flatten = "false"
#rumble = "false"
rumble = "true"
device_type = "gamepad"
#device_type = "THUNDERSTRIKE_SL-6545-BK"

# Event mappings

# Buttons/Stick with same code values in both modes:
# left stick is always in analogue mode 
# ABS_X
abs(000) = "lx", "left stick X axis"
# ABS_Y
abs(001) = "ly", "left stick Y axis"
# BTN_TRIGGER 
key(288) = "b1", "1 top button"
# BTN_THUMB
key(289) = "b2", "2 right button"
# BTN_THUMB2
key(290) = "b3", "3 bottom button"
# BTN_TOP
key(291) = "b4", "4 left button"
# BTN_TOP2
key(292) = "b5l1", "L1 front top left button"
# BTN_PINKIE
key(293) = "b6r1", "R1 front top right button"
# BTN_BASE
key(294) = "b7l2", "L2 front bottom left button"
# BTN_BASE2
key(295) = "b8r2", "R2 front bottom right button"
# BTN_BASE3
key(296) = "b9", "left rectangular button labeled 9"
# BTN_BASE4
key(297) = "b10", "right triangular button labeled 10"
# BTN_BASE5
key(298) = "b11ls", "left stick click"
# BTN_BASE6
key(299) = "b12rs", "right stick click"

# "analogue mode" (LED on):
# ABS_Z
abs(002) = "rx", "right stick X axis"
# ABS_RZ
abs(005) = "ry", "right stick Y axis"
# ABS_HAT0X
abs(016) = "lr", "d-pad X axis"
# ABS_HAT0Y
abs(017) = "ud", "d-pad Y axis"
# weird change when using this driver definition
# from BTN_BASE2/BTN_BASE3 to ABS_Z/ABS_RZ:
# ABS_Z
#abs(002) = "b7fbl2", "L2 front bottom left button"
# ABS_RZ
#abs(005) = "b8fbr2", "R2 front bottom right button"

# "digital mode" (LED off):
# D-pad makes same "axis" events as left analogue stick
#abs(000)
#abs(001)
# right stick makes same "button" events as the 1/2/3/4 buttons
#key(288)
#key(289)
#key(290)
#key(291)
# The names for the modes are very misleading,
# since the d-pad and left stick "remain analogue",
# producing axis events even in "digital" mode.

# Aliases

alias left_x lx
alias left_y ly
alias right_x rx
alias right_y ry
alias leftright lr
alias updown ud

# BTN_NORTH
alias third b1
# BTN_EAST
alias secondary b2
# BTN_SOUTH
alias primary b3
# BTN_WEST
alias fourth b4

#alias Y b1
#alias B b2
#alias A b3
#alias X b4

#alias triangle b1
#alias circle b2
#alias cross b3
#alias square b4

alias start b10
alias select b9

alias tl b5l1
alias tr b6r1
alias tl2 b7l2
alias tr2 b8r2
#alias tl2_axis b7fbl2
#alias tr2_axis b8fbr2

alias thumbl b11ls
alias thumbr b12rs

For my own event names for this pad I followed the button numbering by the manufacturer, and the actual button/stick locations and functions, I did not check for possibly overlapping definitions in the profiles in the repository.

This is my configuration file:

socket_path = "/var/tmp/moltengamepad.sock"
  #  Location to create the socket
rumble = false
  #  Process controller rumble effects
monitor = true
  #  Listen for device connections/disconnections
enumerate = true
  #  Check for already connected devices
auto_profile_subdir = "auto/"
  #  automatically load profiles in this subdir. of the profile dir. on start up
num_gamepads = 1
  #  Number of virtual gamepads to create
mimic_xpad = false
#true
  #  Set virtual devices to match a wired Xbox 360 controller
fifo_path = "/var/tmp/moltengamepad.fifo"
  #  Location to create the FIFO
gendev_dir = "/usr/local/etc/moltengamepad/gendevices"
  #  A directory to check for generic driver descriptions before the config directories
make_socket = true
  #  Make a socket to communicate with clients
replace_fifo = true
  #  Before making the FIFO, tell any existing listeners to exit
profile_dir = "/usr/local/etc/moltengamepad/profiles"
  #  A directory to check for profiles before the config directories
dpad_as_hat = false
  #  Use a hat to represent the dpad, instead of 4 separate buttons
make_fifo = true
  #  Make a FIFO that processes any commands written to **it**
make_keyboard = true
  #  Make a virtual keyboard/mouse device
uinput_path = "/usr/local/dev/uinput"
  #  Location of the uinput node

## You can specify profiles to load at start up with lines like the following:
#load profiles from THUNDERSTRIKE_SL-6515-BK.cfg

I've not yet chosen an install method, to facilitate debugging I've also not grabbed/hidden the original event device (tried both, just to be sure). Everything resides in /usr/local and /var/tmp.

Now the big problem is: the driver definition above seems to be correct to me, but the two lower front buttons do NOT get mapped to TL2/TR2 as defined, they produce axis events ABS_Z & ABS_RZ instead. Those even get "picked up" as core events from Xorg's "joystick" driver, resulting the pointer to be "dragged" to the top of the screen as soon as I press TR2. Conclusion: it gets somehow mapped to the left Y axis, but I don't see such events in "evtest" (I probably will, if I find the correct /dev/input/event# and look into it). Without MG running, the ABS_RZ event from the gamepad's right stick does not lead to an Xorg core pointer event. MG should be able to coexist with the "joystick" driver, and not silently create weird mappings.

Various attempts to remap those 2 buttons again in a second step have failed, also using the analogue trigger names of the internal gamepad profile instead. In most cases the buttons simply didn't do anything.

This is the event list created, note the missing TL2/TR2:

Input device name: "Virtual Gamepad (MoltenGamepad)"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 304 (BTN_SOUTH)
    Event code 305 (BTN_EAST)
    Event code 307 (BTN_NORTH)
    Event code 308 (BTN_WEST)
    Event code 310 (BTN_TL)
    Event code 311 (BTN_TR)
    Event code 314 (BTN_SELECT)
    Event code 315 (BTN_START)
    Event code 316 (BTN_MODE)
    Event code 317 (BTN_THUMBL)
    Event code 318 (BTN_THUMBR)
    Event code 544 (BTN_DPAD_UP)
    Event code 545 (BTN_DPAD_DOWN)
    Event code 546 (BTN_DPAD_LEFT)
    Event code 547 (BTN_DPAD_RIGHT)
  Event type 3 (EV_ABS)
    Event code 0 (ABS_X)
      Value      0
      Min   -32768
      Max    32767
      Flat    1024
    Event code 1 (ABS_Y)
      Value      0
      Min   -32768
      Max    32767
      Flat    1024
    Event code 2 (ABS_Z)
      Value      0
      Min        0
      Max      255
    Event code 3 (ABS_RX)
      Value      0
      Min   -32768
      Max    32767
      Flat    1024
    Event code 4 (ABS_RY)
      Value      0
      Min   -32768
      Max    32767
      Flat    1024
    Event code 5 (ABS_RZ)
      Value      0
      Min        0
      Max      255
Properties:
Testing ... (interrupt to exit)

Note also that switching on "rumble" does not create/copy over the events EV_FF from the original event device.

My last attempt was to do everything on my own, trying not to use the gamepad profile, but the following profile definition:

# Speedlink THUNDERSTRIKE SL-6545-BK
# iManufacturer = "Microntek"
# iProduct      = "USB Joystick"
#[name="DragonRise Inc. PC TWIN SHOCK Gamepad"]
#[vendor=0079 product=0006]

# Digital-Knöpfe statt Achse
#gamepad.abs_hat0x = axis2btns(btn_dpad_left, btn_dpad_right)
#gamepad.abs_hat0y = axis2btns(btn_dpad_up, btn_dpad_down)
#gamepad.leftright = (left, right)
#gamepad.updown = (up, down)
#gamepad.leftright = axis2btns(btn_dpad_left, btn_dpad_right)
#gamepad.updown = axis2btns(btn_dpad_up, btn_dpad_down)
#gamepad.tl2_axis_btn = axis2btns(tl2, tl2)
#gamepad.tr2_axis_btn = axis2btns(tr2, tr2)
#gamepad.tl2 = tl
#gamepad.tr2 = tr
#bfbl2 = tl2_axis_btn
#bfbr2 = tr2_axis_btn
#gamepad.tl2_axis = axis2btns(btn_tl2, btn_tl)
#gamepad.tr2_axis = axis2btns(btn_tr2, btn_tr)
#abs(002) = abs_hat2y
#abs(005) = abs_hat2x

THUNDERSTRIKE_SL-6545-BK.lx = axis2axis(abs_x)
THUNDERSTRIKE_SL-6545-BK.ly = axis2axis(abs_y)
THUNDERSTRIKE_SL-6545-BK.rx = axis2axis(abs_rx)
THUNDERSTRIKE_SL-6545-BK.ry = axis2axis(abs_ry)
THUNDERSTRIKE_SL-6545-BK.lr = axis2btns(btn_dpad_left, btn_dpad_right)
THUNDERSTRIKE_SL-6545-BK.ud = axis2btns(btn_dpad_up, btn_dpad_down)
THUNDERSTRIKE_SL-6545-BK.b1 = key(btn_north)
THUNDERSTRIKE_SL-6545-BK.b2 = key(btn_east)
THUNDERSTRIKE_SL-6545-BK.b3 = key(btn_south)
THUNDERSTRIKE_SL-6545-BK.b4 = key(btn_west)
THUNDERSTRIKE_SL-6545-BK.b5l1 = key(btn_tl)
THUNDERSTRIKE_SL-6545-BK.b6r1 = key(btn_tr)
THUNDERSTRIKE_SL-6545-BK.b7l2 = key(btn_tl2)
THUNDERSTRIKE_SL-6545-BK.b8r2 = key(btn_tr2)
THUNDERSTRIKE_SL-6545-BK.b9 = key(btn_select)
THUNDERSTRIKE_SL-6545-BK.b10 = key(btn_start)
THUNDERSTRIKE_SL-6545-BK.b11ls = key(btn_thumbl)
THUNDERSTRIKE_SL-6545-BK.b12rs = key(btn_thumbr)

The lines commented out are from previous futile attempts to remap things from the gamepad profile.

To switch to this configuration, I load the profile above, set device_type = "THUNDERSTRIKE_SL-6545-BK", and (optionally, tried both) comment out the alias definitions.

With that done – deliberately avoiding any "gamepad profile names", MGP says the following:

loading /usr/local/etc/moltengamepad/moltengamepad.cfg
Replacing FIFO at /var/tmp/moltengamepad.fifo
Made socket at /var/tmp/moltengamepad.sock
driver: THUNDERSTRIKE_SL-6545-BK driver initialized.
Loading profiles from /usr/local/etc/moltengamepad/profiles/THUNDERSTRIKE_SL-6515-BK.cfg
parse: setting THUNDERSTRIKE_SL-6545-BK.lx = left_x+
parse: setting THUNDERSTRIKE_SL-6545-BK.ly = left_y+
parse: setting THUNDERSTRIKE_SL-6545-BK.rx = right_x+
parse: setting THUNDERSTRIKE_SL-6545-BK.ry = right_y+
parse: setting THUNDERSTRIKE_SL-6545-BK.lr = (left,right)
parse: setting THUNDERSTRIKE_SL-6545-BK.ud = (up,down)
parse: setting THUNDERSTRIKE_SL-6545-BK.b1 = key(fourth)
parse: setting THUNDERSTRIKE_SL-6545-BK.b2 = key(second)
parse: setting THUNDERSTRIKE_SL-6545-BK.b3 = key(first)
parse: setting THUNDERSTRIKE_SL-6545-BK.b4 = key(third)
parse: setting THUNDERSTRIKE_SL-6545-BK.b5l1 = key(tl)
parse: setting THUNDERSTRIKE_SL-6545-BK.b6r1 = key(tr)
parse: setting THUNDERSTRIKE_SL-6545-BK.b7l2 = key(tl2)
parse: setting THUNDERSTRIKE_SL-6545-BK.b8r2 = key(tr2)
parse: setting THUNDERSTRIKE_SL-6545-BK.b9 = key(select)
parse: setting THUNDERSTRIKE_SL-6545-BK.b10 = key(start)
parse: setting THUNDERSTRIKE_SL-6545-BK.b11ls = key(thumbl)
parse: setting THUNDERSTRIKE_SL-6545-BK.b12rs = key(thumbr)
plug: thstr_1 added
stdin: ready to read commands from standard input. Try "help" for more info.

Note that MG still uses the internal "gamepad profile names".

This one makes the analogue remappings axis2… work, but all the normal digital buttons don't do anything. (Remark added later: it seems that this approach "sends" them to the "virtual keyboard" instead.)

The event list reported is exactly the same as the one created when using the "gamepad" profile. So this is implicitly still used?

My latest attempt:

THUNDERSTRIKE_SL-6545-BK.b1 = btn2btn(btn_north)
THUNDERSTRIKE_SL-6545-BK.b2 = btn2btn(btn_east)
THUNDERSTRIKE_SL-6545-BK.b3 = btn2btn(btn_south)
THUNDERSTRIKE_SL-6545-BK.b4 = btn2btn(btn_west)
THUNDERSTRIKE_SL-6545-BK.b5l1 = btn2btn(btn_tl)
THUNDERSTRIKE_SL-6545-BK.b6r1 = btn2btn(btn_tr)
THUNDERSTRIKE_SL-6545-BK.b7l2 = btn2btn(btn_tl2)
THUNDERSTRIKE_SL-6545-BK.b8r2 = btn2btn(btn_tr2)
THUNDERSTRIKE_SL-6545-BK.b9 = btn2btn(btn_select)
THUNDERSTRIKE_SL-6545-BK.b10 = btn2btn(btn_start)
THUNDERSTRIKE_SL-6545-BK.b11ls = btn2btn(btn_thumbl)
THUNDERSTRIKE_SL-6545-BK.b12rs = btn2btn(btn_thumbr)

Using "btn2btn" instead of "key" works, but creates wrong mappings! "btn_north" is translated to "first", which creates the event "btn_west" for me: effectively "north" and "west" get swapped. MG seems to have an inconsistent "view" of "first" and "third" being "north" or "west".

However, this doesn't change anything regarding TL2 & TR2: they get mapped to the two Z axis.

Now trying to avoid TL2 & TR2 entirely:

#THUNDERSTRIKE_SL-6545-BK.b7l2 = btn2btn(btn_tl2)
#THUNDERSTRIKE_SL-6545-BK.b8r2 = btn2btn(btn_tr2)
THUNDERSTRIKE_SL-6545-BK.b7l2 = btn2btn(btn_joystick)
THUNDERSTRIKE_SL-6545-BK.b8r2 = btn2btn(btn_c)

"Sort of" works:

loading /usr/local/etc/moltengamepad/moltengamepad.cfg
Replacing FIFO at /var/tmp/moltengamepad.fifo
Made socket at /var/tmp/moltengamepad.sock
driver: THUNDERSTRIKE_SL-6545-BK driver initialized.
Loading profiles from /usr/local/etc/moltengamepad/profiles/THUNDERSTRIKE_SL-6515-BK.cfg
parse: setting THUNDERSTRIKE_SL-6545-BK.lx = left_x+
parse: setting THUNDERSTRIKE_SL-6545-BK.ly = left_y+
parse: setting THUNDERSTRIKE_SL-6545-BK.rx = right_x+
parse: setting THUNDERSTRIKE_SL-6545-BK.ry = right_y+
parse: setting THUNDERSTRIKE_SL-6545-BK.lr = (left,right)
parse: setting THUNDERSTRIKE_SL-6545-BK.ud = (up,down)
parse: setting THUNDERSTRIKE_SL-6545-BK.b1 = second
parse: setting THUNDERSTRIKE_SL-6545-BK.b2 = fourth
parse: setting THUNDERSTRIKE_SL-6545-BK.b3 = first
parse: setting THUNDERSTRIKE_SL-6545-BK.b4 = third
parse: setting THUNDERSTRIKE_SL-6545-BK.b5l1 = tl
parse: setting THUNDERSTRIKE_SL-6545-BK.b6r1 = tr
### Note: ###
parse: setting THUNDERSTRIKE_SL-6545-BK.b7l2 = btn_joystick
parse: setting THUNDERSTRIKE_SL-6545-BK.b8r2 = btn_c
#############
parse: setting THUNDERSTRIKE_SL-6545-BK.b9 = select
parse: setting THUNDERSTRIKE_SL-6545-BK.b10 = start
parse: setting THUNDERSTRIKE_SL-6545-BK.b11ls = thumbl
parse: setting THUNDERSTRIKE_SL-6545-BK.b12rs = thumbr
plug: thstr_1 added
stdin: ready to read commands from standard input. Try "help" for more info.
slot: thstr_1 assigned to slot virtpad1

Well, BTN_JOYSTICK is silently ignored, and BTN_C is silently remapped to BTN_EAST, despite having another "official" key code of 132. BTN_Z instead of BTN_JOYSTICK is also ignored.

How can I prevent MG from making wrong assumptions, or how can I get keycodes included into the created event device, which MG stubbornly considers to be "non-gamepad"? Perhaps the game would listen to the "ancient joystick trigger button", or the "esoteric" buttons "C" and "Z"…

ChristophFranzen commented 2 months ago

Suggestion (apart from fixing the "wrong silent remapping" issue above):

Even if not assigning them by default, let MG make all event codes assignable to a virtual gamepad device; that includes at least adding _BTNC=0x132, as well as _BTNZ=0x135.

It would also be nice to have predefinded alias names for A, B, C, X, Y, Z according to the table below, as well as "cross" (A), "circle" (B), "square" (Y), "triangle" (X).

I see the difficulty here: NORTH=X, EAST=Y as defined in libevdev is the other way around as normally seen on most pads.

Since I have actually got a gamepad natively using codes from the "joystick block", please consider to make those usable as well in the virtual gamepad event device. I used the game "Dex", a "platform action adventure RPG" to test, which did not "see" the codes, which lead me to try MG as a possible solution, so this would not have helped me here, but would extend MG to be useful for games made for old joysticks, but not gamepads.

From "input-event-codes.h" from "libevdev": Event codes for "old-fashioned joysticks":

#define BTN_JOYSTICK        0x120
#define BTN_TRIGGER     0x120
#define BTN_THUMB       0x121
#define BTN_THUMB2      0x122
#define BTN_TOP         0x123
#define BTN_TOP2        0x124
#define BTN_PINKIE      0x125
#define BTN_BASE        0x126
#define BTN_BASE2       0x127
#define BTN_BASE3       0x128
#define BTN_BASE4       0x129
#define BTN_BASE5       0x12a
#define BTN_BASE6       0x12b
#define BTN_DEAD        0x12f

Event codes for "modern gamepads":

#define BTN_GAMEPAD     0x130
#define BTN_SOUTH       0x130
#define BTN_A           BTN_SOUTH
#define BTN_EAST        0x131
#define BTN_B           BTN_EAST
#define BTN_C           0x132
#define BTN_NORTH       0x133
#define BTN_X           BTN_NORTH
#define BTN_WEST        0x134
#define BTN_Y           BTN_WEST
#define BTN_Z           0x135
#define BTN_TL          0x136
#define BTN_TR          0x137
#define BTN_TL2         0x138
#define BTN_TR2         0x139
#define BTN_SELECT      0x13a
#define BTN_START       0x13b
#define BTN_MODE        0x13c
#define BTN_THUMBL      0x13d
#define BTN_THUMBR      0x13e
ChristophFranzen commented 2 months ago

I've read a lot of your documentation and the examples, as well as other stuff as of now, though I think reading C++ is a pain for people not having written the programme; so I, at least, don't fully understand what is going on, but I can guess:

I think when seeing a Z axis on the input side, you assume that this must be an analogue trigger, and therefore refuse by some means to use the digital buttons TL2 and TR2. As we see here, this is not always true, and I also do not understand why they should not be able to happily coexist anyway – just because there is no known device having both? The "libevdev" event codes they create are different, so there's no problem there, or do I miss something important here?

The current state effectively "subtracts" 2 buttons from my gamepad, they are eiter "dead" or mapped to existing buttons – wait – I didn't try remapping to "mode" yet…

Remapping to "mode" works!

Conclusion: having a Z axis on the input side "kills" L2/R2 digital button assignment in MG. This is clearly a bug, then.