blob: 634be62ccefd1fd3f650d5f85c057438dadd66d7 [file] [log] [blame]
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
# Get all evdev/uinput events in our namespace.
# pylint: disable=wildcard-import, unused-wildcard-import
from uinput.ev import *
import subprocess
import time
import uinput
# Time to wait after uinput device creation, before starting to type. This is
# needed as kernel/Chrome takes some time to register the new input device.
#
# TODO(crbug.com/714950): This is a hack, we should figure out a way to check
# when kernel/Chrome is ready (monitor udev events?), instead of waiting for
# an arbitrary amount of time.
STARTUP_DELAY = 0.2
# Default delay between key presses in seconds. 12ms is the xdotool default.
DEFAULT_DELAY = 0.012
uinput_device_keyboard = None
# This dictionary contains most 7 bit ASCII characters. Add more if needed.
# TODO(ihf): Create this table using xkbcommon to support arbirtrary
# character sets and keyboard layouts.
_CROS_CHAR_MAP = {
"\b": [KEY_BACKSPACE],
"\t": [KEY_TAB],
"\n": [KEY_ENTER],
" ": [KEY_SPACE],
"!": [KEY_LEFTSHIFT, KEY_1],
'"': [KEY_LEFTSHIFT, KEY_APOSTROPHE],
"#": [KEY_LEFTSHIFT, KEY_3],
"$": [KEY_LEFTSHIFT, KEY_4],
"%": [KEY_LEFTSHIFT, KEY_5],
"&": [KEY_LEFTSHIFT, KEY_7],
"'": [KEY_APOSTROPHE],
"(": [KEY_LEFTSHIFT, KEY_9],
")": [KEY_LEFTSHIFT, KEY_0],
"*": [KEY_KPASTERISK],
"+": [KEY_LEFTSHIFT, KEY_EQUAL],
",": [KEY_COMMA],
"-": [KEY_MINUS],
".": [KEY_DOT],
"/": [KEY_SLASH],
"0": [KEY_0],
"1": [KEY_1],
"2": [KEY_2],
"3": [KEY_3],
"4": [KEY_4],
"5": [KEY_5],
"6": [KEY_6],
"7": [KEY_7],
"8": [KEY_8],
"9": [KEY_9],
":": [KEY_LEFTSHIFT, KEY_SEMICOLON],
";": [KEY_SEMICOLON],
"<": [KEY_LEFTSHIFT, KEY_COMMA],
"=": [KEY_EQUAL],
">": [KEY_LEFTSHIFT, KEY_DOT],
"?": [KEY_LEFTSHIFT, KEY_SLASH],
"@": [KEY_LEFTSHIFT, KEY_2],
"A": [KEY_LEFTSHIFT, KEY_A],
"B": [KEY_LEFTSHIFT, KEY_B],
"C": [KEY_LEFTSHIFT, KEY_C],
"D": [KEY_LEFTSHIFT, KEY_D],
"E": [KEY_LEFTSHIFT, KEY_E],
"F": [KEY_LEFTSHIFT, KEY_F],
"G": [KEY_LEFTSHIFT, KEY_G],
"H": [KEY_LEFTSHIFT, KEY_H],
"I": [KEY_LEFTSHIFT, KEY_I],
"J": [KEY_LEFTSHIFT, KEY_J],
"K": [KEY_LEFTSHIFT, KEY_K],
"L": [KEY_LEFTSHIFT, KEY_L],
"M": [KEY_LEFTSHIFT, KEY_M],
"N": [KEY_LEFTSHIFT, KEY_N],
"O": [KEY_LEFTSHIFT, KEY_O],
"P": [KEY_LEFTSHIFT, KEY_P],
"Q": [KEY_LEFTSHIFT, KEY_Q],
"R": [KEY_LEFTSHIFT, KEY_R],
"S": [KEY_LEFTSHIFT, KEY_S],
"T": [KEY_LEFTSHIFT, KEY_T],
"U": [KEY_LEFTSHIFT, KEY_U],
"V": [KEY_LEFTSHIFT, KEY_V],
"W": [KEY_LEFTSHIFT, KEY_W],
"X": [KEY_LEFTSHIFT, KEY_X],
"Y": [KEY_LEFTSHIFT, KEY_Y],
"Z": [KEY_LEFTSHIFT, KEY_Z],
"[": [KEY_LEFTBRACE],
"\\": [KEY_BACKSLASH],
"]": [KEY_RIGHTBRACE],
"^": [KEY_LEFTSHIFT, KEY_6],
"_": [KEY_LEFTSHIFT, KEY_MINUS],
"`": [KEY_GRAVE],
"a": [KEY_A],
"b": [KEY_B],
"c": [KEY_C],
"d": [KEY_D],
"e": [KEY_E],
"f": [KEY_F],
"g": [KEY_G],
"h": [KEY_H],
"i": [KEY_I],
"j": [KEY_J],
"k": [KEY_K],
"l": [KEY_L],
"m": [KEY_M],
"n": [KEY_N],
"o": [KEY_O],
"p": [KEY_P],
"q": [KEY_Q],
"r": [KEY_R],
"s": [KEY_S],
"t": [KEY_T],
"u": [KEY_U],
"v": [KEY_V],
"w": [KEY_W],
"x": [KEY_X],
"y": [KEY_Y],
"z": [KEY_Z],
"{": [KEY_LEFTSHIFT, KEY_LEFTBRACE],
"|": [KEY_LEFTSHIFT, KEY_BACKSLASH],
"}": [KEY_LEFTSHIFT, KEY_RIGHTBRACE],
"~": [KEY_LEFTSHIFT, KEY_GRAVE],
}
# A list of American English ChromeOS keys to define a keyboard device.
_CROS_KEYS_ALL = [
# Function row.
KEY_ESC,
KEY_F1,
KEY_F2,
KEY_F3,
KEY_F4,
KEY_F5,
KEY_F6,
KEY_F7,
KEY_F8,
KEY_F9,
KEY_F10,
KEY_F11,
KEY_F12,
KEY_HOME,
KEY_END,
KEY_INSERT,
KEY_DELETE,
# First row.
KEY_GRAVE,
KEY_1,
KEY_2,
KEY_3,
KEY_4,
KEY_5,
KEY_6,
KEY_7,
KEY_8,
KEY_9,
KEY_0,
KEY_MINUS,
KEY_EQUAL,
KEY_BACKSPACE,
# Second row.
KEY_TAB,
KEY_Q,
KEY_W,
KEY_E,
KEY_R,
KEY_T,
KEY_Y,
KEY_U,
KEY_I,
KEY_O,
KEY_P,
KEY_LEFTBRACE,
KEY_RIGHTBRACE,
KEY_BACKSLASH,
# Third row
KEY_CAPSLOCK,
KEY_A,
KEY_S,
KEY_D,
KEY_F,
KEY_G,
KEY_H,
KEY_J,
KEY_K,
KEY_L,
KEY_SEMICOLON,
KEY_APOSTROPHE,
KEY_ENTER,
# Forth row.
KEY_LEFTSHIFT,
KEY_102ND,
KEY_Z,
KEY_X,
KEY_C,
KEY_V,
KEY_B,
KEY_N,
KEY_M,
KEY_COMMA,
KEY_DOT,
KEY_SLASH,
KEY_RIGHTSHIFT,
# Fifth row.
KEY_LEFTCTRL,
KEY_FN,
KEY_SEARCH,
KEY_LEFTALT,
KEY_SPACE,
KEY_NUMLOCK,
KEY_SCROLLLOCK,
KEY_RIGHTALT,
KEY_RIGHTCTRL,
# Directional keys.
KEY_UP,
KEY_PAGEUP,
KEY_LEFT,
KEY_RIGHT,
KEY_DOWN,
KEY_PAGEDOWN,
]
def _chars_to_events(chars):
"""
Translates string to key events.
@param chars: characters to translate to events.
@returns: list of lists of events representing characters.
"""
events = []
for char in chars:
events.append(_CROS_CHAR_MAP[char])
return events
def _get_uinput_device_keyboard():
"""
Lazy initialize device and return it. We don't want to create a device
during build_packages or for tests that don't need it, hence init with None.
"""
global uinput_device_keyboard
if uinput_device_keyboard is None:
# For DUTs without keyboard attached force load uinput.
subprocess.Popen(['modprobe', 'uinput']).wait()
uinput_device_keyboard = uinput.Device(_CROS_KEYS_ALL)
time.sleep(STARTUP_DELAY)
return uinput_device_keyboard
def _uinput_translate_name(event_name):
"""
Translates string |event_name| to uinput event.
"""
return getattr(uinput, event_name)
def _uinput_emit_keycombo(device, events, syn=True):
"""
Wrapper for uinput.emit_combo. Emits sequence of events.
Example: [KEY_LEFTCTRL, KEY_LEFTALT, KEY_F5]
"""
time.sleep(DEFAULT_DELAY)
device.emit_combo(events, syn)
def press_keys(keys):
"""Presses the given keys as one combination.
Please do not leak uinput dependencies outside of the file.
@param key: A simple list of key strings, e.g. ['LEFTCTRL', 'F4']
"""
events = [_uinput_translate_name(en) for en in keys]
_uinput_emit_keycombo(_get_uinput_device_keyboard(), events)
def type_chars(text):
"""Translates ASCII text to keystrokes and sends them as events.
@param text: string to send as events to keyboard.
"""
events = _chars_to_events(text)
device = _get_uinput_device_keyboard()
for keys in events:
_uinput_emit_keycombo(device, keys)