Skip to content
Snippets Groups Projects
Commit 50a510e5 authored by Simon McVittie's avatar Simon McVittie
Browse files

input-device: Implement and test parsing input-device-monitor output


We can use this later, in diagnostic tools.

Signed-off-by: default avatarSimon McVittie <smcv@collabora.com>
parent 5f84d30d
No related branches found
No related tags found
1 merge request!158Input device interface
......@@ -106,3 +106,5 @@ struct _SrtSimpleInputDeviceClass
{
GObjectClass parent;
};
SrtSimpleInputDevice *_srt_simple_input_device_new_from_json (JsonObject *obj);
......@@ -31,6 +31,7 @@
#include "steam-runtime-tools/glib-backports-internal.h"
#include "steam-runtime-tools/input-device.h"
#include "steam-runtime-tools/input-device-internal.h"
#include "steam-runtime-tools/json-utils-internal.h"
#include "steam-runtime-tools/utils-internal.h"
static void srt_simple_input_device_iface_init (SrtInputDeviceInterface *iface);
......@@ -365,3 +366,183 @@ srt_simple_input_device_iface_init (SrtInputDeviceInterface *iface)
#undef IMPLEMENT
}
static gchar *
dup_json_string_member (JsonObject *obj,
const gchar *name)
{
JsonNode *node = json_object_get_member (obj, name);
if (node == NULL)
return NULL;
/* This returns NULL without error if it is a non-string */
return json_node_dup_string (node);
}
static unsigned long
get_json_hex_member (JsonObject *obj,
const gchar *name)
{
JsonNode *node = json_object_get_member (obj, name);
const char *s;
if (node == NULL)
return 0;
s = json_node_get_string (node);
if (s == NULL)
return 0;
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
s += 2;
return strtoul (s, NULL, 16);
}
static JsonObject *
get_json_object_member (JsonObject *obj,
const char *name)
{
JsonNode *node = json_object_get_member (obj, name);
if (node != NULL && JSON_NODE_HOLDS_OBJECT (node))
return json_node_get_object (node);
return NULL;
}
static gchar *
dup_json_uevent (JsonObject *obj)
{
return _srt_json_object_dup_array_of_lines_member (obj, "uevent");
}
static void
get_json_evdev_caps (JsonObject *obj,
const char *name,
unsigned long *longs,
size_t n_longs)
{
JsonNode *node = json_object_get_member (obj, name);
/* The first pointer that is out of bounds for longs */
unsigned char *limit = (unsigned char *) &longs[n_longs];
/* The output position in longs */
unsigned char *out = (unsigned char *) longs;
/* The input position in the string we are parsing */
const char *iter;
size_t i;
if (node == NULL)
return;
iter = json_node_get_string (node);
if (iter == NULL)
return;
while (*iter != '\0')
{
unsigned int this_byte;
int used;
while (*iter == ' ')
iter++;
if (sscanf (iter, "%x%n", &this_byte, &used) == 1)
iter += used;
else
break;
if (out < limit)
*(out++) = (unsigned char) this_byte;
else
break;
}
for (i = 0; i < n_longs; i++)
longs[i] = GULONG_FROM_LE (longs[i]);
}
SrtSimpleInputDevice *
_srt_simple_input_device_new_from_json (JsonObject *obj)
{
SrtSimpleInputDevice *self = g_object_new (SRT_TYPE_SIMPLE_INPUT_DEVICE,
NULL);
JsonObject *sub;
self->sys_path = dup_json_string_member (obj, "sys_path");
self->dev_node = dup_json_string_member (obj, "dev_node");
self->subsystem = dup_json_string_member (obj, "subsystem");
self->bus_type = get_json_hex_member (obj, "bus_type");
self->vendor_id = get_json_hex_member (obj, "vendor_id");
self->product_id = get_json_hex_member (obj, "product_id");
self->version = get_json_hex_member (obj, "version");
self->iface_flags = srt_get_flags_from_json_array (SRT_TYPE_INPUT_DEVICE_INTERFACE_FLAGS,
obj,
"interface_flags",
SRT_INPUT_DEVICE_INTERFACE_FLAGS_NONE);
self->type_flags = srt_get_flags_from_json_array (SRT_TYPE_INPUT_DEVICE_TYPE_FLAGS,
obj,
"type_flags",
SRT_INPUT_DEVICE_TYPE_FLAGS_NONE);
if ((sub = get_json_object_member (obj, "evdev")) != NULL)
{
get_json_evdev_caps (sub, "raw_types", self->evdev_caps.ev,
G_N_ELEMENTS (self->evdev_caps.ev));
get_json_evdev_caps (sub, "raw_abs", self->evdev_caps.abs,
G_N_ELEMENTS (self->evdev_caps.abs));
get_json_evdev_caps (sub, "raw_rel", self->evdev_caps.rel,
G_N_ELEMENTS (self->evdev_caps.rel));
get_json_evdev_caps (sub, "raw_keys", self->evdev_caps.keys,
G_N_ELEMENTS (self->evdev_caps.keys));
get_json_evdev_caps (sub, "raw_input_properties",
self->evdev_caps.props,
G_N_ELEMENTS (self->evdev_caps.props));
}
self->udev_properties = _srt_json_object_dup_strv_member (obj, "udev_properties", NULL);
self->uevent = dup_json_uevent (obj);
if ((sub = get_json_object_member (obj, "hid_ancestor")) != NULL)
{
self->hid_ancestor.sys_path = dup_json_string_member (sub, "sys_path");
self->hid_ancestor.name = dup_json_string_member (sub, "name");
self->hid_ancestor.bus_type = get_json_hex_member (sub, "bus_type");
self->hid_ancestor.vendor_id = get_json_hex_member (sub, "vendor_id");
self->hid_ancestor.product_id = get_json_hex_member (sub, "product_id");
self->hid_ancestor.uniq = dup_json_string_member (sub, "uniq");
self->hid_ancestor.phys = dup_json_string_member (sub, "phys");
self->hid_ancestor.uevent = dup_json_uevent (sub);
}
if ((sub = get_json_object_member (obj, "input_ancestor")) != NULL)
{
self->input_ancestor.sys_path = dup_json_string_member (sub, "sys_path");
self->input_ancestor.name = dup_json_string_member (sub, "name");
self->input_ancestor.bus_type = get_json_hex_member (sub, "bus_type");
self->input_ancestor.vendor_id = get_json_hex_member (sub, "vendor_id");
self->input_ancestor.product_id = get_json_hex_member (sub, "product_id");
self->input_ancestor.version = get_json_hex_member (sub, "version");
self->input_ancestor.uniq = dup_json_string_member (sub, "uniq");
self->input_ancestor.phys = dup_json_string_member (sub, "phys");
self->input_ancestor.uevent = dup_json_uevent (sub);
}
if ((sub = get_json_object_member (obj, "usb_device_ancestor")) != NULL)
{
self->usb_device_ancestor.sys_path = dup_json_string_member (sub, "sys_path");
self->usb_device_ancestor.vendor_id = get_json_hex_member (sub, "vendor_id");
self->usb_device_ancestor.product_id = get_json_hex_member (sub, "product_id");
self->usb_device_ancestor.device_version = get_json_hex_member (sub, "version");
self->usb_device_ancestor.manufacturer = dup_json_string_member (sub, "manufacturer");
self->usb_device_ancestor.product = dup_json_string_member (sub, "product");
self->usb_device_ancestor.serial = dup_json_string_member (sub, "serial");
self->usb_device_ancestor.uevent = dup_json_uevent (sub);
}
return self;
}
This diff is collapsed.
{"added" : {}}
{
"added" : {
"interface_flags" : [
"raw-hid",
"__future__"
],
"type_flags" : [
"__future__"
],
"evdev" : {
"raw_abs" : "01 02 03 04 05 06 07 08 ff ff ff ff",
"raw_input_properties" : "12 34 56 78 87 65 43 21 ff ff ff ff"
},
"hid_ancestor" : {
"sys_path" : "/...",
"name" : "Acme Weird Device",
"bus_type" : "0xfff1",
"vendor_id" : "0xfff1",
"product_id" : "0xfff1",
"uniq" : "12345678"
},
"input_ancestor" : {
"sys_path" : "/...",
"bus_type" : "0xfff2",
"vendor_id" : "0xfff2",
"product_id" : "0xfff2",
"uniq" : "1234-5678"
},
"usb_device_ancestor" : {
"sys_path" : "/...",
"vendor_id" : "0xfff3",
"product_id" : "0xfff3",
"serial" : "12:34:56:78"
}
}
}
{
"added" : {
"interface_flags" : [
"event"
],
"type_flags" : [
"keyboard",
"has-keys",
"mouse"
],
"dev_node" : "/dev/input/event20",
"subsystem" : "input",
"sys_path" : "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:28DE:1142.00DD/input/input308/event20",
"bus_type" : "0x0003",
"vendor_id" : "0x28de",
"product_id" : "0x1142",
"version" : "0x0111",
"evdev" : {
"types" : [
"SYN",
"KEY",
"REL",
"MSC",
"LED",
"REP"
],
"raw_types" : "17 00 12 00 00 00 00 00 ",
"absolute_axes" : [],
"raw_abs" : "00 00 00 00 00 00 00 00 ",
"relative_axes" : [
"X",
"Y",
"WHEEL",
"WHEEL_HI_RES"
],
"raw_rel" : "03 09 00 00 00 00 00 00 ",
"keys" : [
"KEY_ESC",
"KEY_0",
"KEY_A",
"KEY_KP0",
"BTN_MOUSE",
"BTN_RIGHT",
"BTN_MIDDLE",
"BTN_SIDE",
"BTN_EXTRA"
],
"raw_keys" : "fe ff ff ff ff ff ff ff ff ff cf 01 df ff 80 e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ",
"input_properties" : [],
"raw_input_properties" : "00 00 00 00 00 00 00 00 ",
"guessed_type_flags" : [
"keyboard",
"has-keys",
"mouse"
]
},
"udev_properties" : [
"BACKSPACE=guess",
"DEVLINKS=/dev/input/by-id/usb-Valve_Software_Steam_Controller-event-mouse /dev/input/by-path/pci-0000:00:14.0-usb-0:1.1:1.0-event-mouse",
"DEVNAME=/dev/input/event20",
"DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:28DE:1142.00DD/input/input308/event20",
"ID_BUS=usb",
"ID_INPUT=1",
"ID_INPUT_KEY=1",
"ID_INPUT_KEYBOARD=1",
"ID_INPUT_MOUSE=1",
"ID_MODEL=Steam_Controller",
"ID_MODEL_ENC=Steam\\x20Controller",
"ID_MODEL_ID=1142",
"ID_PATH=pci-0000:00:14.0-usb-0:1.1:1.0",
"ID_PATH_TAG=pci-0000_00_14_0-usb-0_1_1_1_0",
"ID_REVISION=0001",
"ID_SERIAL=Valve_Software_Steam_Controller",
"ID_TYPE=hid",
"ID_USB_DRIVER=usbhid",
"ID_USB_INTERFACES=:030101:030000:",
"ID_USB_INTERFACE_NUM=00",
"ID_VENDOR=Valve_Software",
"ID_VENDOR_ENC=Valve\\x20Software",
"ID_VENDOR_ID=28de",
"LIBINPUT_DEVICE_GROUP=3/28de/1142:usb-0000:00:14.0-1",
"MAJOR=13",
"MINOR=84",
"SUBSYSTEM=input",
"TAGS=:power-switch:",
"USEC_INITIALIZED=1162877255953",
"XKBLAYOUT=gb",
"XKBMODEL=pc105"
],
"uevent" : [
"MAJOR=13",
"MINOR=84",
"DEVNAME=input/event20"
],
"hid_ancestor" : {
"sys_path" : "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:28DE:1142.00DD",
"name" : "Valve Software Steam Controller",
"bus_type" : "0x0003",
"vendor_id" : "0x28de",
"product_id" : "0x1142",
"uniq" : "",
"phys" : "usb-0000:00:14.0-1.1/input0",
"uevent" : [
"DRIVER=hid-steam",
"HID_ID=0003:000028DE:00001142",
"HID_NAME=Valve Software Steam Controller",
"HID_PHYS=usb-0000:00:14.0-1.1/input0",
"HID_UNIQ=",
"MODALIAS=hid:b0003g0001v000028DEp00001142"
]
},
"input_ancestor" : {
"sys_path" : "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.1/1-1.1:1.0/0003:28DE:1142.00DD/input/input308",
"name" : "Valve Software Steam Controller",
"bus_type" : "0x0003",
"vendor_id" : "0x28de",
"product_id" : "0x1142",
"version" : "0x0111",
"phys" : "usb-0000:00:14.0-1.1/input0",
"uevent" : [
"PRODUCT=3/28de/1142/111",
"NAME=\"Valve Software Steam Controller\"",
"PHYS=\"usb-0000:00:14.0-1.1/input0\"",
"UNIQ=\"\"",
"PROP=0",
"EV=120017",
"KEY=1f0000 0 0 e080ffdf01cfffff fffffffffffffffe",
"REL=903",
"MSC=10",
"LED=1f",
"MODALIAS=input:b0003v28DEp1142e0111-e0,1,2,4,11,14,k77,7D,7E,7F,110,111,112,113,114,r0,1,8,B,am4,l0,1,2,3,4,sfw"
]
},
"usb_device_ancestor" : {
"sys_path" : "/sys/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1.1",
"vendor_id" : "0x28de",
"product_id" : "0x1142",
"version" : "0x0001",
"manufacturer" : "Valve Software",
"product" : "Steam Controller",
"serial" : null,
"uevent" : [
"MAJOR=189",
"MINOR=66",
"DEVNAME=bus/usb/001/067",
"DEVTYPE=usb_device",
"DRIVER=usb",
"PRODUCT=28de/1142/1",
"TYPE=0/0/0",
"BUSNUM=001",
"DEVNUM=067"
]
}
}
}
......@@ -113,6 +113,7 @@ install_subdir('expectations_with_missings', install_dir : tests_dir)
# Vulkan *.json files. (The order of EGL *.json files is well-defined.)
install_subdir('fake-icds', install_dir : tests_dir)
install_subdir('fake-steam-runtime', install_dir : tests_dir)
install_subdir('input-monitor-output', install_dir : tests_dir)
install_subdir('json-report', install_dir : tests_dir)
meson.add_postconf_script(
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment