1# Copyright 2020 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""
6Provides uinput utils for generating user input events.
7"""
8
9# Please limit the use of the uinput library to this file. Try not to spread
10# dependencies and abstract as much as possible to make switching to a different
11# input library in the future easier.
12import uinput
13
14
15# Don't create a device during build_packages or for tests that don't need it.
16uinput_device_keyboard = None
17uinput_device_touch = None
18uinput_device_mouse_rel = None
19
20# Don't add more events to this list than are used. For a complete list of
21# available events check python2.7/site-packages/uinput/ev.py.
22UINPUT_DEVICE_EVENTS_KEYBOARD = [
23    uinput.KEY_F4,
24    uinput.KEY_F11,
25    uinput.KEY_KPPLUS,
26    uinput.KEY_KPMINUS,
27    uinput.KEY_LEFTCTRL,
28    uinput.KEY_TAB,
29    uinput.KEY_UP,
30    uinput.KEY_DOWN,
31    uinput.KEY_LEFT,
32    uinput.KEY_RIGHT,
33    uinput.KEY_RIGHTSHIFT,
34    uinput.KEY_LEFTALT,
35    uinput.KEY_A,
36    uinput.KEY_M,
37    uinput.KEY_Q,
38    uinput.KEY_V
39]
40# TODO(ihf): Find an ABS sequence that actually works.
41UINPUT_DEVICE_EVENTS_TOUCH = [
42    uinput.BTN_TOUCH,
43    uinput.ABS_MT_SLOT,
44    uinput.ABS_MT_POSITION_X + (0, 2560, 0, 0),
45    uinput.ABS_MT_POSITION_Y + (0, 1700, 0, 0),
46    uinput.ABS_MT_TRACKING_ID + (0, 10, 0, 0),
47    uinput.BTN_TOUCH
48]
49UINPUT_DEVICE_EVENTS_MOUSE_REL = [
50    uinput.REL_X,
51    uinput.REL_Y,
52    uinput.BTN_MOUSE,
53    uinput.BTN_LEFT,
54    uinput.BTN_RIGHT
55]
56
57
58def get_device_keyboard():
59    """
60    Lazy initialize device and return it. We don't want to create a device
61    during build_packages or for tests that don't need it, hence init with None.
62    """
63    global uinput_device_keyboard
64    if uinput_device_keyboard is None:
65        uinput_device_keyboard = uinput.Device(UINPUT_DEVICE_EVENTS_KEYBOARD)
66    return uinput_device_keyboard
67
68
69def get_device_mouse_rel():
70    """
71    Lazy initialize device and return it. We don't want to create a device
72    during build_packages or for tests that don't need it, hence init with None.
73    """
74    global uinput_device_mouse_rel
75    if uinput_device_mouse_rel is None:
76        uinput_device_mouse_rel = uinput.Device(UINPUT_DEVICE_EVENTS_MOUSE_REL)
77    return uinput_device_mouse_rel
78
79
80def get_device_touch():
81    """
82    Lazy initialize device and return it. We don't want to create a device
83    during build_packages or for tests that don't need it, hence init with None.
84    """
85    global uinput_device_touch
86    if uinput_device_touch is None:
87        uinput_device_touch = uinput.Device(UINPUT_DEVICE_EVENTS_TOUCH)
88    return uinput_device_touch
89
90
91def translate_name(event_name):
92    """
93    Translates string |event_name| to uinput event.
94    """
95    return getattr(uinput, event_name)
96
97
98def emit(device, event_name, value, syn=True):
99    """
100    Wrapper for uinput.emit. Emits event with value.
101    Example: ('REL_X', 20), ('BTN_RIGHT', 1)
102    """
103    event = translate_name(event_name)
104    device.emit(event, value, syn)
105
106
107def emit_click(device, event_name, syn=True):
108    """
109    Wrapper for uinput.emit_click. Emits click event. Only KEY and BTN events
110    are accepted, otherwise ValueError is raised. Example: 'KEY_A'
111    """
112    event = translate_name(event_name)
113    device.emit_click(event, syn)
114
115
116def emit_combo(device, event_names, syn=True):
117    """
118    Wrapper for uinput.emit_combo. Emits sequence of events.
119    Example: ['KEY_LEFTCTRL', 'KEY_LEFTALT', 'KEY_F5']
120    """
121    events = [translate_name(en) for en in event_names]
122    device.emit_combo(events, syn)
123