diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2018-03-01 10:04:11 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2018-03-19 14:24:15 +1000 |
commit | 6e4c83636a99acc6dedb413878bf535ca4f14f4a (patch) | |
tree | a59a67fb3d3960d14354cd4e0a5a9af0985ffab3 /tools/libinput-record-verify-yaml.py | |
parent | fd1cb049daf924de127de6039cb30e2b2a9d364a (diff) | |
download | libinput-6e4c83636a99acc6dedb413878bf535ca4f14f4a.tar.gz |
tools: libinput-record: add support for printing libinput events
Collect libinput events together with the evdev events and print them to the
log. This makes it possible to debug the full behavior of a user's machine
rather than having to replay it with potential different race conditions/side
effects.
Example event output:
- evdev:
- [ 2, 314443, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 314443, 1, 57, 1] # EV_KEY / KEY_SPACE 1
- [ 2, 314443, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +87ms
libinput:
- {time: 2.314443, type: KEYBOARD_KEY, key: 57, state: pressed}
- evdev:
- [ 2, 377203, 4, 4, 57] # EV_MSC / MSC_SCAN 57
- [ 2, 377203, 1, 57, 0] # EV_KEY / KEY_SPACE 0
- [ 2, 377203, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +63ms
libinput:
- {time: 2.377203, type: KEYBOARD_KEY, key: 57, state: released}
Note that the only way to know that events are within the same frame is to
check the timestamp. libinput keeps those intact which means we can tell that
if we just had an evdev frame with timestamp T and get a pointer motion with
timestamp T, that frame caused the motion event.
So far, only key, pointer and touch events are printed. We also
hardcode-enable tapping where available until we have options to enable this
on the commandline just because that's useful to have.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Diffstat (limited to 'tools/libinput-record-verify-yaml.py')
-rwxr-xr-x | tools/libinput-record-verify-yaml.py | 202 |
1 files changed, 198 insertions, 4 deletions
diff --git a/tools/libinput-record-verify-yaml.py b/tools/libinput-record-verify-yaml.py index 785bb1c1..9c8d39b7 100755 --- a/tools/libinput-record-verify-yaml.py +++ b/tools/libinput-record-verify-yaml.py @@ -41,6 +41,26 @@ class TestYaml(unittest.TestCase): with open(cls.filename) as f: cls.yaml = yaml.safe_load(f) + def dict_key_crosscheck(self, d, keys): + '''Check that each key in d is in keys, and that each key is in d''' + self.assertEqual(sorted(d.keys()), sorted(keys)) + + def libinput_events(self, filter=None): + '''Returns all libinput events in the recording, regardless of the + device''' + devices = self.yaml['devices'] + for d in devices: + events = d['events'] + for e in events: + try: + libinput = e['libinput'] + except KeyError: + continue + + for ev in libinput: + if filter is None or ev['type'] == filter: + yield ev + def test_sections_exist(self): sections = ['version', 'ndevices', 'libinput', 'system', 'devices'] for section in sections: @@ -148,19 +168,23 @@ class TestYaml(unittest.TestCase): # than one of the latter self.assertGreaterEqual(len(id_inputs), 2) - def test_events_have_evdev(self): + def test_events_have_section(self): devices = self.yaml['devices'] for d in devices: events = d['events'] for e in events: - self.assertIn('evdev', e) + self.assertTrue('evdev' in e or 'libinput' in e) def test_events_evdev(self): devices = self.yaml['devices'] for d in devices: events = d['events'] for e in events: - evdev = e['evdev'] + try: + evdev = e['evdev'] + except KeyError: + continue + for ev in evdev: self.assertEqual(len(ev), 5) @@ -175,10 +199,180 @@ class TestYaml(unittest.TestCase): for d in devices: events = d['events'] for e in events: - evdev = e['evdev'] + try: + evdev = e['evdev'] + except KeyError: + continue for ev in evdev[:-1]: self.assertFalse(ev[2] == 0 and ev[3] == 0) + def test_events_libinput(self): + devices = self.yaml['devices'] + for d in devices: + events = d['events'] + for e in events: + try: + libinput = e['libinput'] + except KeyError: + continue + + self.assertTrue(isinstance(libinput, list)) + for ev in libinput: + self.assertTrue(isinstance(ev, dict)) + + def test_events_libinput_type(self): + types = ['POINTER_MOTION', 'POINTER_MOTION_ABSOLUTE', + 'POINTER_BUTTON', 'DEVICE_ADDED', 'KEYBOARD_KEY', + 'TOUCH_DOWN', 'TOUCH_MOTION', 'TOUCH_UP', 'TOUCH_FRAME'] + for e in self.libinput_events(): + self.assertIn('type', e) + self.assertIn(e['type'], types) + + def test_events_libinput_time(self): + # DEVICE_ADDED has no time + # first event may have 0.0 time if the first frame generates a + # libinput event. + try: + for e in list(self.libinput_events())[2:]: + self.assertIn('time', e) + self.assertGreater(e['time'], 0.0) + self.assertLess(e['time'], 60.0) + except IndexError: + pass + + def test_events_libinput_device_added(self): + keys = ['type', 'seat', 'logical_seat'] + for e in self.libinput_events('DEVICE_ADDED'): + self.dict_key_crosscheck(e, keys) + self.assertEqual(e['seat'], 'seat0') + self.assertEqual(e['logical_seat'], 'default') + + def test_events_libinput_pointer_motion(self): + keys = ['type', 'time', 'delta', 'unaccel'] + for e in self.libinput_events('POINTER_MOTION'): + self.dict_key_crosscheck(e, keys) + delta = e['delta'] + self.assertTrue(isinstance(delta, list)) + self.assertEqual(len(delta), 2) + for d in delta: + self.assertTrue(isinstance(d, float)) + unaccel = e['unaccel'] + self.assertTrue(isinstance(unaccel, list)) + self.assertEqual(len(unaccel), 2) + for d in unaccel: + self.assertTrue(isinstance(d, float)) + + def test_events_libinput_pointer_button(self): + keys = ['type', 'time', 'button', 'state', 'seat_count'] + for e in self.libinput_events('POINTER_BUTTON'): + self.dict_key_crosscheck(e, keys) + button = e['button'] + self.assertGreater(button, 0x100) # BTN_0 + self.assertLess(button, 0x160) # KEY_OK + state = e['state'] + self.assertIn(state, ['pressed', 'released']) + scount = e['seat_count'] + self.assertGreaterEqual(scount, 0) + + def test_events_libinput_pointer_absolute(self): + keys = ['type', 'time', 'point', 'transformed'] + for e in self.libinput_events('POINTER_MOTION_ABSOLUTE'): + self.dict_key_crosscheck(e, keys) + point = e['point'] + self.assertTrue(isinstance(point, list)) + self.assertEqual(len(point), 2) + for p in point: + self.assertTrue(isinstance(p, float)) + self.assertGreater(p, 0.0) + self.assertLess(p, 300.0) + + transformed = e['transformed'] + self.assertTrue(isinstance(transformed, list)) + self.assertEqual(len(transformed), 2) + for t in transformed: + self.assertTrue(isinstance(t, float)) + self.assertGreater(t, 0.0) + self.assertLess(t, 100.0) + + def test_events_libinput_touch(self): + keys = ['type', 'time', 'slot', 'seat_slot'] + for e in self.libinput_events(): + if (not e['type'].startswith('TOUCH_') or + e['type'] == 'TOUCH_FRAME'): + continue + + for k in keys: + self.assertIn(k, e.keys()) + slot = e['slot'] + seat_slot = e['seat_slot'] + + self.assertGreaterEqual(slot, 0) + self.assertGreaterEqual(seat_slot, 0) + + def test_events_libinput_touch_down(self): + keys = ['type', 'time', 'slot', 'seat_slot', 'point', 'transformed'] + for e in self.libinput_events('TOUCH_DOWN'): + self.dict_key_crosscheck(e, keys); + point = e['point'] + self.assertTrue(isinstance(point, list)) + self.assertEqual(len(point), 2) + for p in point: + self.assertTrue(isinstance(p, float)) + self.assertGreater(p, 0.0) + self.assertLess(p, 300.0) + + transformed = e['transformed'] + self.assertTrue(isinstance(transformed, list)) + self.assertEqual(len(transformed), 2) + for t in transformed: + self.assertTrue(isinstance(t, float)) + self.assertGreater(t, 0.0) + self.assertLess(t, 100.0) + + def test_events_libinput_touch_motion(self): + keys = ['type', 'time', 'slot', 'seat_slot', 'point', 'transformed'] + for e in self.libinput_events('TOUCH_MOTION'): + self.dict_key_crosscheck(e, keys); + point = e['point'] + self.assertTrue(isinstance(point, list)) + self.assertEqual(len(point), 2) + for p in point: + self.assertTrue(isinstance(p, float)) + self.assertGreater(p, 0.0) + self.assertLess(p, 300.0) + + transformed = e['transformed'] + self.assertTrue(isinstance(transformed, list)) + self.assertEqual(len(transformed), 2) + for t in transformed: + self.assertTrue(isinstance(t, float)) + self.assertGreater(t, 0.0) + self.assertLess(t, 100.0) + + def test_events_libinput_touch_frame(self): + devices = self.yaml['devices'] + for d in devices: + events = d['events'] + for e in events: + try: + evdev = e['libinput'] + except KeyError: + continue + + need_frame = False + for ev in evdev: + t = ev['type'] + if not t.startswith('TOUCH_'): + self.assertFalse(need_frame) + continue + + self.assertTrue(need_frame) + need_frame = False + else: + need_frame = True + + self.assertFalse(need_frame) + if __name__ == '__main__': parser = argparse.ArgumentParser(description='Verify a YAML recording') |