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

How the testevdev test cases are produced #7801

Closed
iacore opened this issue Jun 11, 2023 · 8 comments
Closed

How the testevdev test cases are produced #7801

iacore opened this issue Jun 11, 2023 · 8 comments

Comments

@iacore
Copy link

iacore commented Jun 11, 2023

I saw the commits below

How do I add a new controller test case for this? Is there some special software used to produce this?

@slouken
Copy link
Collaborator

slouken commented Jun 11, 2023

@smcv can help you here

@iacore
Copy link
Author

iacore commented Jun 12, 2023

Is there a way to use only USB vendor and product to detect gamepad? The current GUID is too strict. See this case, where an older version of the same gamepad isn't detected.

@slouken
Copy link
Collaborator

slouken commented Jun 12, 2023

Yes, the latest version of SDL will match USB VID/PID if the version doesn't match.

@iacore
Copy link
Author

iacore commented Jun 12, 2023

Closing for now. If anyone knows how to produce test data (see first comment) please tell.

@iacore iacore closed this as completed Jun 12, 2023
@smcv
Copy link
Contributor

smcv commented Jun 13, 2023

That test data is currently only used to test SDL_EVDEV_GuessDeviceClass(), which is about the evdev capability bits, not the USB vendor/product IDs - so if your device is being mis-detected based on its vendor/product IDs, this is probably not going to help you yet. Our test data does include the vendor/product, but currently only as reference information, and they're not actually inputs to the function under test.

I'd like to expand our test coverage to make more use of this data to test other functions over time, though!

The test data mostly comes from the output of the evemu-describe tool. For example, output for the laptop keyboard that I'm using to type this comment is quoted below, and that happens to be the same one I used to provide .name = "Thinkpad T520 and X280 keyboards" in SDL's test data. Because it's a keyboard, and access to those is restricted to prevent keyloggers, I had to use sudo evemu-describe - but for gamepads you will generally have access to the evdev device node (and if you don't, SDL will be unable to use that gamepad), so you won't need sudo.

If you're interested in providing more test data for an unusual device, you can either translate it yourself and open a pull request, or post the evemu-describe output on an issue and I'll try to turn it into test data at some point. If you open a pull request, please leave the source data as a comment on the pull request, so that we have something to go back to if we're not sure whether your translation into the test data format was correct.

In general we don't need test data for ordinary Xbox/Playstation-style gamepads (particularly third-party clones of Microsoft/Sony/Nintendo controllers), unless they're something that SDL mis-detects. They can usually be grouped into very similar devices that only differ by their vendor/product/version, and if you look through the commit history you'll see that I added some of my colleague's test devices as comments rather than machine-readable data, because there's not much point in repeating the unit tests on a functionally equivalent device.

If you have a device that is unusual, like a specialized simulation controller, then test data for that is a lot more interesting, because our heuristics for classifying devices might give the wrong answer for those. When a console manufacturer introduces a new generation (for instance the Playstation 6 will presumably have a new controller type), that's often also interesting to have listed, since it often has features that the previous generation didn't.

$ sudo evemu-describe /dev/input/event0
# EVEMU 1.3
...
# Supported events:
#   Event type 0 (EV_SYN)
...
#   Event type 1 (EV_KEY)
...
#   Event type 4 (EV_MSC)
...
#   Event type 17 (EV_LED)
...
#   Event type 20 (EV_REP)
...

The "Supported events" become the .ev field. The mapping to a list of hex bytes is not instantly obvious (you have to calculate it based on the EV_ codes from /usr/include/linux/input-event-codes.h), but in practice it's usually possible to copy/paste from a different device that supports the same list of event types. Most gamepads have SYN/KEY/ABS/MSC and sometimes FF.

I: 0011 0001 0001 ab54

This translates to .bus_type: 0x0011, .vendor: 0x0001, .product: 0x0001, .version: 0xab54.

P: 00 00 00 00 00 00 00 00

If it wasn't all zeroes, we'd put this in .props after reformatting it as a list of C hex integers. A real example is that the Dual Shock touchpad is P: 05 00 00 00 00 00 00 00 which becomes .props = { 0x05 } (trailing zeroes don't need to be written out explicitly).

B: 00 0b 00 00 00 00 00 00 00

The line starting with B: 00 is not useful, as far as I know: it probably only depends on your kernel version, and not the actual device.

B: 01 fe ff ff ff ff ff ff ff
B: 01 ff ff ef ff df ff ff fe
B: 01 01 d0 00 f8 78 30 80 03
B: 01 00 00 00 02 04 00 00 00
B: 01 00 00 00 00 00 00 00 00
B: 01 00 00 00 00 00 00 00 00
B: 01 00 00 00 00 00 00 00 00
B: 01 00 00 00 00 00 00 00 00
B: 01 00 00 00 00 00 00 00 00
B: 01 00 00 00 00 00 00 00 00
B: 01 00 00 00 00 00 00 00 00
B: 01 00 00 00 00 00 00 00 00

All the lines starting with B: 01 are button/key codes, and turn into the .keys field in the test data (remove the B: 01 prefix, and reformat the rest into C hex integers). Any trailing zeroes can be omitted, and we have some macros for shorthand representations of large blocks of zeroes.

B: 02 00 00 00 00 00 00 00 00

Everything after B: 02 is a relative axis (EV_REL), and would go in .rel after removing the B: 02 prefix, if it was non-zero. This keyboard doesn't have any relative axes, but mice do.

B: 03 00 00 00 00 00 00 00 00

Similarly everything after B: 03 is an absolute axis, EV_ABS (joysticks, touchpads, touchscreens)...

B: 04 10 00 00 00 00 00 00 00

... B: 04 is EV_MSC, miscellaneous axes, which are not interesting to SDL so we don't transcribe them ...

B: 05 00 00 00 00 00 00 00 00

... B: 05 is EV_SW, switches, which again are not interesting to SDL ...

B: 11 07 00 00 00 00 00 00 00

... B: 11 is EV_LED, keyboard LEDs, which again are not interesting ...

B: 12 00 00 00 00 00 00 00 00

... B: 12 is EV_SND, sound devices (sound card jack-detection and things like that), which again are not interesting ...

B: 14 03 00 00 00 00 00 00 00

... keyboard autorepeat ...

B: 15 00 00 00 00 00 00 00 00
B: 15 00 00 00 00 00 00 00 00

... and force feedback/haptics, which are certainly interesting for gamers, but not very interesting from the point of view of identifying whether something is a joystick or not, so we don't transcribe these either.

Steam's steam-runtime-input-monitor tool will give you most of this information, but in a slightly different format, and it can unfortunately be incomplete for some devices. One of the various things on my to-do list is to try to fix it to provide complete information, to make it more convenient for Steam users to provide test data like this.

@smcv
Copy link
Contributor

smcv commented Jun 13, 2023

Another piece of information which we don't collect yet, but we should, is the raw HID descriptor for the device. Not all input devices have one of these, but it should be available for all Bluetooth gamepads and most non-Xbox USB gamepads with a command like od -t x1 /sys/class/input/event${N}/device/device/report_descriptor, like this:

$ od -t x1 /sys/class/input/event5/device/device/report_descriptor
0000000 05 01 09 02 a1 01 85 01 09 01 a1 00 05 09 19 01
0000020 29 03 15 00 25 01 95 03 75 01 81 02 95 01 75 05
0000040 81 01 05 01 09 30 09 31 15 81 25 7f 95 02 75 08
0000060 81 06 c0 c0 05 01 09 80 a1 01 85 02 05 01 15 00
0000100 25 01 95 08 75 01 19 81 29 88 81 02 c0 05 0c 09
0000120 01 a1 01 85 03 95 08 75 01 15 00 25 01 09 e9 09
0000140 ea 09 e2 09 b7 09 cd 09 b5 09 b6 0a 94 01 81 02
0000160 09 03 a1 02 05 09 19 10 29 17 81 02 05 09 19 18
0000200 29 1f 81 02 c0 05 08 95 02 09 09 09 21 91 02 95
0000220 01 75 06 91 03 c0 06 01 ff 09 01 a1 01 85 04 95
0000240 01 75 08 15 00 26 ff 00 09 20 b1 03 09 21 b1 03
0000260 09 22 b1 03 09 23 b1 03 c0
0000271

evemu-describe and steam-runtime-input-monitor don't currently collect this, but I want to add it to steam-runtime-input-monitor to make it easy for Steam users to collect this information.

@iacore
Copy link
Author

iacore commented Jun 13, 2023

Is it possible for you to enable Github discussion and turn this into a discussion thread? That way it's useful for other people as well.

@smcv
Copy link
Contributor

smcv commented Dec 5, 2023

evemu-describe and steam-runtime-input-monitor don't currently collect this, but I want to add it to steam-runtime-input-monitor to make it easy for Steam users to collect this information.

An update on this: in current versions of Steam (stable or beta, doesn't matter), you can run:

~/.steam/root/ubuntu12_32/steam-runtime/run.sh -- steam-runtime-input-monitor

and it will output all the information we need, one blob of JSON per device. It has some options for which devices to inspect and how to present the information (use --help if unsure).

Usually the easiest way to use it is this:

  • start with the device of interest unplugged or disconnected
  • run ~/.steam/root/ubuntu12_32/steam-runtime/run.sh -- steam-runtime-input-monitor --only-new
  • the tool will log {"#": "devices that are already connected are not shown"}
  • connect the device of interest (power-on/connect a Bluetooth device or plug in a USB device)
  • the tool will log a blob of JSON; please send that JSON to an issue report
  • press Ctrl+C when finished using the tool

If you want to also send a pull request that adds a mockup of your device to the unit test, first please copy/paste the whole JSON blob into an issue request or the PR description, so that we have the source information to refer back to if we add more features or we think there might be a mistake. Then, the JSON maps into the testevdev.c data structures like this:

  • .name is a human-readable description of the device, for example "Xbox 360 wired USB controller"
  • .expected is a bitmask of how you think the device should be classified by SDL
  • .bus_type, .vendor_id, .product_id, .version are at top-level in the JSON
  • .eviocgname is specifically input_ancestor → name in the JSON, whatever that is
  • .usb_vendor_name is usb_device_ancestor → manufacturer in the JSON
  • .usb_product_name is usb_device_ancestor → product in the JSON
  • .ev is raw_types in the JSON (you can copy/paste it as/is, or delete any number of zeroes from the end to make it a bit shorter)
  • .abs is raw_abs in the JSON
  • .keys is raw_keys in the JSON (as well as removing zeroes from the end, you can shorten it by replacing long runs of zeroes with the macros ZEROx8 or ZEROx4 if appropriate)
  • .rel is raw_rel in the JSON
  • I don't think we log the supported force-feedback properties .ff but in any case they're probably uninteresting for device classification
  • .props is raw_input_properties in the JSON
  • .hid_report_descriptor_length is hid_ancestor → report_descriptor_length in the JSON
  • .hid_report_descriptor is hid_ancestor → report_descriptor in the JSON
  • Set .todo non-null if SDL doesn't classify your device according to expected today, but you think it should in future

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