blob: a6d54892a601b17ab4234b039adbe9ce00fc6997 [file] [log] [blame]
Nicolas Boichat8b3c51b2017-04-25 09:43:58 +08001# Copyright 2015 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
5import argparse
6# Get all evdev/uinput events in our namespace.
7# pylint: disable=wildcard-import, unused-wildcard-import
8from uinput.ev import *
9import subprocess
10import time
11import uinput
12
Nicolas Boichat7ac1acc2017-04-25 09:46:07 +080013
14# Time to wait after uinput device creation, before starting to type. This is
15# needed as kernel/Chrome takes some time to register the new input device.
16#
17# TODO(crbug.com/714950): This is a hack, we should figure out a way to check
18# when kernel/Chrome is ready (monitor udev events?), instead of waiting for
19# an arbitrary amount of time.
20STARTUP_DELAY = 0.2
21
Nicolas Boichat8b3c51b2017-04-25 09:43:58 +080022# Default delay between key presses in seconds. 12ms is the xdotool default.
Nicolas Boichat7ac1acc2017-04-25 09:46:07 +080023DEFAULT_DELAY = 0.012
24
Nicolas Boichat8b3c51b2017-04-25 09:43:58 +080025uinput_device_keyboard = None
26
27
28# This dictionary contains most 7 bit ASCII characters. Add more if needed.
29# TODO(ihf): Create this table using xkbcommon to support arbirtrary
30# character sets and keyboard layouts.
31_CROS_CHAR_MAP = {
32 "\b": [KEY_BACKSPACE],
33 "\t": [KEY_TAB],
34 "\n": [KEY_ENTER],
35
36 " ": [KEY_SPACE],
37 "!": [KEY_LEFTSHIFT, KEY_1],
38 '"': [KEY_LEFTSHIFT, KEY_APOSTROPHE],
39 "#": [KEY_LEFTSHIFT, KEY_3],
40 "$": [KEY_LEFTSHIFT, KEY_4],
41 "%": [KEY_LEFTSHIFT, KEY_5],
42 "&": [KEY_LEFTSHIFT, KEY_7],
43 "'": [KEY_APOSTROPHE],
44 "(": [KEY_LEFTSHIFT, KEY_9],
45 ")": [KEY_LEFTSHIFT, KEY_0],
46 "*": [KEY_KPASTERISK],
47 "+": [KEY_LEFTSHIFT, KEY_EQUAL],
48 ",": [KEY_COMMA],
49 "-": [KEY_MINUS],
50 ".": [KEY_DOT],
51 "/": [KEY_SLASH],
52
53 "0": [KEY_0],
54 "1": [KEY_1],
55 "2": [KEY_2],
56 "3": [KEY_3],
57 "4": [KEY_4],
58 "5": [KEY_5],
59 "6": [KEY_6],
60 "7": [KEY_7],
61 "8": [KEY_8],
62 "9": [KEY_9],
63
64 ":": [KEY_LEFTSHIFT, KEY_SEMICOLON],
65 ";": [KEY_SEMICOLON],
66 "<": [KEY_LEFTSHIFT, KEY_COMMA],
67 "=": [KEY_EQUAL],
68 ">": [KEY_LEFTSHIFT, KEY_DOT],
69 "?": [KEY_LEFTSHIFT, KEY_SLASH],
70 "@": [KEY_LEFTSHIFT, KEY_2],
71
72 "A": [KEY_LEFTSHIFT, KEY_A],
73 "B": [KEY_LEFTSHIFT, KEY_B],
74 "C": [KEY_LEFTSHIFT, KEY_C],
75 "D": [KEY_LEFTSHIFT, KEY_D],
76 "E": [KEY_LEFTSHIFT, KEY_E],
77 "F": [KEY_LEFTSHIFT, KEY_F],
78 "G": [KEY_LEFTSHIFT, KEY_G],
79 "H": [KEY_LEFTSHIFT, KEY_H],
80 "I": [KEY_LEFTSHIFT, KEY_I],
81 "J": [KEY_LEFTSHIFT, KEY_J],
82 "K": [KEY_LEFTSHIFT, KEY_K],
83 "L": [KEY_LEFTSHIFT, KEY_L],
84 "M": [KEY_LEFTSHIFT, KEY_M],
85 "N": [KEY_LEFTSHIFT, KEY_N],
86 "O": [KEY_LEFTSHIFT, KEY_O],
87 "P": [KEY_LEFTSHIFT, KEY_P],
88 "Q": [KEY_LEFTSHIFT, KEY_Q],
89 "R": [KEY_LEFTSHIFT, KEY_R],
90 "S": [KEY_LEFTSHIFT, KEY_S],
91 "T": [KEY_LEFTSHIFT, KEY_T],
92 "U": [KEY_LEFTSHIFT, KEY_U],
93 "V": [KEY_LEFTSHIFT, KEY_V],
94 "W": [KEY_LEFTSHIFT, KEY_W],
95 "X": [KEY_LEFTSHIFT, KEY_X],
96 "Y": [KEY_LEFTSHIFT, KEY_Y],
97 "Z": [KEY_LEFTSHIFT, KEY_Z],
98
99 "[": [KEY_LEFTBRACE],
100 "\\": [KEY_BACKSLASH],
101 "]": [KEY_RIGHTBRACE],
102 "^": [KEY_LEFTSHIFT, KEY_6],
103 "_": [KEY_LEFTSHIFT, KEY_MINUS],
104 "`": [KEY_GRAVE],
105
106 "a": [KEY_A],
107 "b": [KEY_B],
108 "c": [KEY_C],
109 "d": [KEY_D],
110 "e": [KEY_E],
111 "f": [KEY_F],
112 "g": [KEY_G],
113 "h": [KEY_H],
114 "i": [KEY_I],
115 "j": [KEY_J],
116 "k": [KEY_K],
117 "l": [KEY_L],
118 "m": [KEY_M],
119 "n": [KEY_N],
120 "o": [KEY_O],
121 "p": [KEY_P],
122 "q": [KEY_Q],
123 "r": [KEY_R],
124 "s": [KEY_S],
125 "t": [KEY_T],
126 "u": [KEY_U],
127 "v": [KEY_V],
128 "w": [KEY_W],
129 "x": [KEY_X],
130 "y": [KEY_Y],
131 "z": [KEY_Z],
132
133 "{": [KEY_LEFTSHIFT, KEY_LEFTBRACE],
134 "|": [KEY_LEFTSHIFT, KEY_BACKSLASH],
135 "}": [KEY_LEFTSHIFT, KEY_RIGHTBRACE],
136 "~": [KEY_LEFTSHIFT, KEY_GRAVE],
137}
138
139
140# A list of American English ChromeOS keys to define a keyboard device.
141_CROS_KEYS_ALL = [
142 # Function row.
143 KEY_ESC,
144 KEY_F1,
145 KEY_F2,
146 KEY_F3,
147 KEY_F4,
148 KEY_F5,
149 KEY_F6,
150 KEY_F7,
151 KEY_F8,
152 KEY_F9,
153 KEY_F10,
154 KEY_F11,
155 KEY_F12,
156 KEY_HOME,
157 KEY_END,
158 KEY_INSERT,
159 KEY_DELETE,
160 # First row.
161 KEY_GRAVE,
162 KEY_1,
163 KEY_2,
164 KEY_3,
165 KEY_4,
166 KEY_5,
167 KEY_6,
168 KEY_7,
169 KEY_8,
170 KEY_9,
171 KEY_0,
172 KEY_MINUS,
173 KEY_EQUAL,
174 KEY_BACKSPACE,
175 # Second row.
176 KEY_TAB,
177 KEY_Q,
178 KEY_W,
179 KEY_E,
180 KEY_R,
181 KEY_T,
182 KEY_Y,
183 KEY_U,
184 KEY_I,
185 KEY_O,
186 KEY_P,
187 KEY_LEFTBRACE,
188 KEY_RIGHTBRACE,
189 KEY_BACKSLASH,
190 # Third row
191 KEY_CAPSLOCK,
192 KEY_A,
193 KEY_S,
194 KEY_D,
195 KEY_F,
196 KEY_G,
197 KEY_H,
198 KEY_J,
199 KEY_K,
200 KEY_L,
201 KEY_SEMICOLON,
202 KEY_APOSTROPHE,
203 KEY_ENTER,
204 # Forth row.
205 KEY_LEFTSHIFT,
206 KEY_Z,
207 KEY_X,
208 KEY_C,
209 KEY_V,
210 KEY_B,
211 KEY_N,
212 KEY_M,
213 KEY_COMMA,
214 KEY_DOT,
215 KEY_SLASH,
216 KEY_RIGHTSHIFT,
217 # Fifth row.
218 KEY_LEFTCTRL,
219 KEY_FN,
220 KEY_SEARCH,
221 KEY_LEFTALT,
222 KEY_SPACE,
223 KEY_NUMLOCK,
224 KEY_SCROLLLOCK,
225 KEY_RIGHTALT,
226 KEY_RIGHTCTRL,
227 # Directional keys.
228 KEY_UP,
229 KEY_PAGEUP,
230 KEY_LEFT,
231 KEY_RIGHT,
232 KEY_DOWN,
233 KEY_PAGEDOWN,
234]
235
236
237def _chars_to_events(chars):
238 """
239 Translates string to key events.
240
241 @param chars: characters to translate to events.
242 @returns: list of lists of events representing characters.
243 """
244 events = []
245 for char in chars:
246 events.append(_CROS_CHAR_MAP[char])
247 return events
248
249
250def _get_uinput_device_keyboard():
251 """
252 Lazy initialize device and return it. We don't want to create a device
253 during build_packages or for tests that don't need it, hence init with None.
254 """
255 global uinput_device_keyboard
256 if uinput_device_keyboard is None:
257 # For DUTs without keyboard attached force load uinput.
258 subprocess.Popen(['modprobe', 'uinput']).wait()
259 uinput_device_keyboard = uinput.Device(_CROS_KEYS_ALL)
Nicolas Boichat7ac1acc2017-04-25 09:46:07 +0800260 time.sleep(STARTUP_DELAY)
Nicolas Boichat8b3c51b2017-04-25 09:43:58 +0800261 return uinput_device_keyboard
262
263
264def _uinput_translate_name(event_name):
265 """
266 Translates string |event_name| to uinput event.
267 """
268 return getattr(uinput, event_name)
269
270
271def _uinput_emit_keycombo(device, events, syn=True):
272 """
273 Wrapper for uinput.emit_combo. Emits sequence of events.
274 Example: [KEY_LEFTCTRL, KEY_LEFTALT, KEY_F5]
275 """
Nicolas Boichat7ac1acc2017-04-25 09:46:07 +0800276 time.sleep(DEFAULT_DELAY)
Nicolas Boichat8b3c51b2017-04-25 09:43:58 +0800277 device.emit_combo(events, syn)
278
279
280def press_keys(keys):
281 """Presses the given keys as one combination.
282
283 Please do not leak uinput dependencies outside of the file.
284
285 @param key: A simple list of key strings, e.g. ['LEFTCTRL', 'F4']
286 """
287 events = [_uinput_translate_name(en) for en in keys]
288 _uinput_emit_keycombo(_get_uinput_device_keyboard(), events)
289
290
291def type_chars(text):
292 """Translates ASCII text to keystrokes and sends them as events.
293
294 @param text: string to send as events to keyboard.
295 """
296 events = _chars_to_events(text)
297 device = _get_uinput_device_keyboard()
298 for keys in events:
299 _uinput_emit_keycombo(device, keys)