jgeumlek / MoltenGamepad

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

multiple joysticks same device id, how to handle that? #60

Closed werpu closed 5 years ago

werpu commented 5 years ago

Hi, first of all thanks for the great project, as an opensource developer I know how hard it is to find time to work on such things. So my biggest thanks to you. So dont see this question as a high priority question, whenever you have time...

But now to the problem, I am currently working on a custom arcade panel, and I am using MoltenGamepad to get everything up and running, so far it looks promising however I encountered a showstopper. Following. My panel consists of two analog joysticks registered as separate game controllers with their own ids, then i have a central pcb exposing the controllers for possible 4 players including the buttons. The main issue I face atm, is that I have everything wired up on the PCB for 2 players and it works, but the pcb exposes two generic controllers with the same device id. This is registered in linux as /dev/input/js0 and /dev/input/js1

and also in separate event devices /dev/input/event0 and /dev/input/event1

The problem I face now is both seem to have the same vendor and device id, but are registered as separate controllers. I now try to map all of this into a generic controller with one analog stick and only one digital one (taking half of the connected pcb) Now due to the same names device ids and vendor ids both pcb joysticks are taken into account. Resulting in the same events if I trigger for player 1 or 2.

(Player 2 triggers are unwanted)

Any idea how to resolve this? A possible solution would be to restrict the incoming events to one joystick or one event node, but I cannot find a way how to do it.

I tried to filter out via uniq and the event ids and or js0 but to no result. (I tried with the latest dev version because I ran into issues with the head, which were resolved by the current dev branch)

werpu commented 5 years ago

Ok I have some additional info: The main difference between the two joysticks seem to be the pyhsical device info

cat /proc/bus/input/devices
I: Bus=0003 Vendor=d209 Product=0410 Version=0111
N: Name="Ultimarc I-PAC Ultimate"
P: Phys=usb-12110000.usb-1.3/input0
S: Sysfs=/devices/12110000.usb/usb1/1-1/1-1.3/1-1.3:1.0/input/input0
U: Uniq=7
H: Handlers=sysrq kbd event0 
B: PROP=0
B: EV=120013
B: KEY=e080ffdf 1cfffff ffffffff fffffffe
B: MSC=10
B: LED=1f

I: Bus=0003 Vendor=d209 Product=0410 Version=0111
N: Name="Ultimarc I-PAC Ultimate"
P: Phys=usb-12110000.usb-1.3/input1
S: Sysfs=/devices/12110000.usb/usb1/1-1/1-1.3/1-1.3:1.1/input/input1
U: Uniq=7
H: Handlers=kbd mouse0 event1 
B: PROP=0
B: EV=17
B: KEY=70000 0 0 7a c000 1e0000 0 0 0
B: REL=3
B: MSC=10

I now also understand the Uniq parameter you allow to be queried, and why it did not work. I thought that might be a general query but instead it is a device info value. Either way the value I need to query here for filtering is the phys or sysfs parameter. I will check the code maybe I can find where this is resolved (my c/c++ is rusty due to 20 years of non usage)

werpu commented 5 years ago

Ok I think I found it


void add_to_match(device_match& current_match, const std::string& field, const std::string& value) {
  if (!value.empty()) {
    if (field == "name")
      current_match.name = value;
    if (field == "product")
      current_match.product = parse_hex(value);
    if (field == "vendor")
      current_match.vendor = parse_hex(value);
    if (field == "phys")
      current_match.phys = value;

So there is a phys parameter for the config, I just either have missed it in the docs or it just was not documented. Either way if this works out then I can proceed. I will close the issue once I know more.

werpu commented 5 years ago

Ok the phys trick worked, but after further sourcecode consultation I found that it only checks for a perfect match. It would be more interesting to have some kind of regexp or indexof check because depending on the port this can change (another port the usb number changes) while the input id itself is rather likely to stay the same.

Also I ran into a problem/bug. I have wired everything together (all four devices) and it works to 90% the analog sticks work like a charm and trigger their events perfectly. However the combined digital device runs into a situation where one device eradicates the other:

[phys="usb-0000:05:00.0-3.1.3/input2" events="superset"]

name = "u_board1"
devname = "digital1_"
exclusive = "false"
change_permissions = "true"
flatten = "false"
rumble = "false"
split = 1

abs_hat0x = "leftright", "D-pad X axis"
abs_hat0y = "updown", "D-pad Y axis"

#abs(003) = "right_x", "Right stick X axis"
#abs(004) = "right_y", "Right stick Y axis"

key(288) = "cross", "Cross (X) face button"
key(289) = "circle", "Circle face button"
key(290) = "triangle", "Triangle face button"
key(291) = "square", "Square face button"
key(292) = "l1", "L1 shoulder button"
key(293) = "r1", "R1 shoulder button"
key(294) = "l2", "L2 shoulder button"
key(295) = "r2", "R2 shoulder button"
key(296) = "l3", "Left stick click"

key(298) = "options", "Options button"

[phys="usb-0000:05:00.0-3.1.3/input3" events="superset"]

name = "u_board2"
devname = "digital2_"
exclusive = "false"
change_permissions = "true"
flatten = "false"
rumble = "false"
split = 1

key(296) = "r3", "Right stick click"

What happens now is that when I start moltengamepad the input3 becomes exclusive for the buttons (key(xxx) and from input2 only the hat_ codes are passed through. I tried with the various parameters (invert exclusive - flatten etc... ) but it did not help. Also changing the order parameter did not help at all. It is either or. It is almost as if the phys parameter is not taken into consideration when the event comes in or the input/event file is ignored and the wrong one taken as source

I will try to debug out what happens here sometime the next few days, unless you are faster to answer.

Help would be appreciated ;-)

werpu commented 5 years ago

Ok after several debugging sessions I found out what the problem was. The problem simply was to combine all my settings into one config file. I now have split everything apart into 4 config files (one for each physical event source) and checked the config for only 1 gamepad is exposed. And it started to work. 1 logical gamepad now is visible but the events for this gamepad stem from 4 phyiscal event sources.

Every physical device now emits events and they are translated properly according to their config settings into one logical gamepad.

I just wanted to drop the info for further reference. I guess I can close the bug now.

jgeumlek commented 5 years ago

Sorry for not getting back to you on this, things have been busy.

I am glad that that phys matching was somewhat helpful, Since most of my testing was through bluetooth controllers, that field was not something I could test easily on my setup.

Correct me if I'm wrong, but it sounds like this was your goal: you had 2 ambiguous analog devices, and 2 ambiguous digital devices, and you wanted to make 2 pairs (analog + digital) out of those ( and currently you have one virtual gamepad instead of 2).

If that is the case, MG doesn't really have any infrastructure for matching those pairs together, and in my head I would imagine hard-matching each of the four devices as distinct input sources (with completely unambiguous event names), and then hard-assigning each input the correct virtpad. The current structure does not have a clean way to say "these two input sources are logically the same input source". And perhaps more importantly, not a clean way to say that in a way that supports hotplugging these input sources.

The flatten property unfortunately would only flatten the two analogs together, or the two digitals together, which doesn't help here.

The phys property was included for such hard-coding, with the idea that you don't change USB ports. I'm not sure what you mean by the input ID staying stable. I would imagine that would depend heavily on the order the devices are recognized by the kernel.