Add ICU message format support
[chromium-blink-merge.git] / tools / site_compare / drivers / win32 / keyboard.py
blobe3410e1ab777fb18a641e4a14ee8e6f4a65647ce
1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """SiteCompare module for simulating keyboard input.
8 This module contains functions that can be used to simulate a user
9 pressing keys on a keyboard. Support is provided for formatted strings
10 including special characters to represent modifier keys like CTRL and ALT
11 """
13 import time # for sleep
14 import win32api # for keybd_event and VkKeyCode
15 import win32con # Windows constants
17 # TODO(jhaas): Ask the readability guys if this would be acceptable:
19 # from win32con import VK_SHIFT, VK_CONTROL, VK_MENU, VK_LWIN, KEYEVENTF_KEYUP
21 # This is a violation of the style guide but having win32con. everywhere
22 # is just plain ugly, and win32con is a huge import for just a handful of
23 # constants
26 def PressKey(down, key):
27 """Presses or unpresses a key.
29 Uses keybd_event to simulate either depressing or releasing
30 a key
32 Args:
33 down: Whether the key is to be pressed or released
34 key: Virtual key code of key to press or release
35 """
37 # keybd_event injects key events at a very low level (it's the
38 # Windows API keyboard device drivers call) so this is a very
39 # reliable way of simulating user input
40 win32api.keybd_event(key, 0, (not down) * win32con.KEYEVENTF_KEYUP)
43 def TypeKey(key, keystroke_time=0):
44 """Simulate a keypress of a virtual key.
46 Args:
47 key: which key to press
48 keystroke_time: length of time (in seconds) to "hold down" the key
49 Note that zero works just fine
51 Returns:
52 None
53 """
55 # This just wraps a pair of PressKey calls with an intervening delay
56 PressKey(True, key)
57 time.sleep(keystroke_time)
58 PressKey(False, key)
61 def TypeString(string_to_type,
62 use_modifiers=False,
63 keystroke_time=0,
64 time_between_keystrokes=0):
65 """Simulate typing a string on the keyboard.
67 Args:
68 string_to_type: the string to print
69 use_modifiers: specifies whether the following modifier characters
70 should be active:
71 {abc}: type characters with ALT held down
72 [abc]: type characters with CTRL held down
73 \ escapes {}[] and treats these values as literal
74 standard escape sequences are valid even if use_modifiers is false
75 \p is "pause" for one second, useful when driving menus
76 \1-\9 is F-key, \0 is F10
78 TODO(jhaas): support for explicit control of SHIFT, support for
79 nonprintable keys (F-keys, ESC, arrow keys, etc),
80 support for explicit control of left vs. right ALT or SHIFT,
81 support for Windows key
83 keystroke_time: length of time (in secondes) to "hold down" the key
84 time_between_keystrokes: length of time (seconds) to pause between keys
86 Returns:
87 None
88 """
90 shift_held = win32api.GetAsyncKeyState(win32con.VK_SHIFT ) < 0
91 ctrl_held = win32api.GetAsyncKeyState(win32con.VK_CONTROL) < 0
92 alt_held = win32api.GetAsyncKeyState(win32con.VK_MENU ) < 0
94 next_escaped = False
95 escape_chars = {
96 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v'}
98 for char in string_to_type:
99 vk = None
100 handled = False
102 # Check to see if this is the start or end of a modified block (that is,
103 # {abc} for ALT-modified keys or [abc] for CTRL-modified keys
104 if use_modifiers and not next_escaped:
105 handled = True
106 if char == "{" and not alt_held:
107 alt_held = True
108 PressKey(True, win32con.VK_MENU)
109 elif char == "}" and alt_held:
110 alt_held = False
111 PressKey(False, win32con.VK_MENU)
112 elif char == "[" and not ctrl_held:
113 ctrl_held = True
114 PressKey(True, win32con.VK_CONTROL)
115 elif char == "]" and ctrl_held:
116 ctrl_held = False
117 PressKey(False, win32con.VK_CONTROL)
118 else:
119 handled = False
121 # If this is an explicitly-escaped character, replace it with the
122 # appropriate code
123 if next_escaped and char in escape_chars: char = escape_chars[char]
125 # If this is \p, pause for one second.
126 if next_escaped and char == 'p':
127 time.sleep(1)
128 next_escaped = False
129 handled = True
131 # If this is \(d), press F key
132 if next_escaped and char.isdigit():
133 fkey = int(char)
134 if not fkey: fkey = 10
135 next_escaped = False
136 vk = win32con.VK_F1 + fkey - 1
138 # If this is the backslash, the next character is escaped
139 if not next_escaped and char == "\\":
140 next_escaped = True
141 handled = True
143 # If we make it here, it's not a special character, or it's an
144 # escaped special character which should be treated as a literal
145 if not handled:
146 next_escaped = False
147 if not vk: vk = win32api.VkKeyScan(char)
149 # VkKeyScan() returns the scan code in the low byte. The upper
150 # byte specifies modifiers necessary to produce the given character
151 # from the given scan code. The only one we're concerned with at the
152 # moment is Shift. Determine the shift state and compare it to the
153 # current state... if it differs, press or release the shift key.
154 new_shift_held = bool(vk & (1<<8))
156 if new_shift_held != shift_held:
157 PressKey(new_shift_held, win32con.VK_SHIFT)
158 shift_held = new_shift_held
160 # Type the key with the specified length, then wait the specified delay
161 TypeKey(vk & 0xFF, keystroke_time)
162 time.sleep(time_between_keystrokes)
164 # Release the modifier keys, if held
165 if shift_held: PressKey(False, win32con.VK_SHIFT)
166 if ctrl_held: PressKey(False, win32con.VK_CONTROL)
167 if alt_held: PressKey(False, win32con.VK_MENU)
170 def main():
171 # We're being invoked rather than imported. Let's do some tests
173 # Press command-R to bring up the Run dialog
174 PressKey(True, win32con.VK_LWIN)
175 TypeKey(ord('R'))
176 PressKey(False, win32con.VK_LWIN)
178 # Wait a sec to make sure it comes up
179 time.sleep(1)
181 # Invoke Notepad through the Run dialog
182 TypeString("wordpad\n")
184 # Wait another sec, then start typing
185 time.sleep(1)
186 TypeString("This is a test of SiteCompare's Keyboard.py module.\n\n")
187 TypeString("There should be a blank line above and below this one.\n\n")
188 TypeString("This line has control characters to make "
189 "[b]boldface text[b] and [i]italic text[i] and normal text.\n\n",
190 use_modifiers=True)
191 TypeString(r"This line should be typed with a visible delay between "
192 "characters. When it ends, there should be a 3-second pause, "
193 "then the menu will select File/Exit, then another 3-second "
194 "pause, then No to exit without saving. Ready?\p\p\p{f}x\p\p\pn",
195 use_modifiers=True,
196 keystroke_time=0.05,
197 time_between_keystrokes=0.05)
200 if __name__ == "__main__":
201 sys.exit(main())