- add sources.
[platform/framework/web/crosswalk.git] / src / tools / site_compare / drivers / win32 / keyboard.py
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.
5
6 """SiteCompare module for simulating keyboard input.
7
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 """
12
13 import time             # for sleep
14 import win32api         # for keybd_event and VkKeyCode
15 import win32con         # Windows constants
16
17 # TODO(jhaas): Ask the readability guys if this would be acceptable:
18 #
19 #  from win32con import VK_SHIFT, VK_CONTROL, VK_MENU, VK_LWIN, KEYEVENTF_KEYUP
20 #
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
24
25
26 def PressKey(down, key):
27   """Presses or unpresses a key.
28
29   Uses keybd_event to simulate either depressing or releasing
30   a key
31
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   """
36
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)
41
42
43 def TypeKey(key, keystroke_time=0):
44   """Simulate a keypress of a virtual key.
45
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
50
51   Returns:
52     None
53   """
54
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)
59
60
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.
66
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
77
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
82
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
85
86   Returns:
87     None
88   """
89
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
93
94   next_escaped = False
95   escape_chars = {
96     'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v'}
97
98   for char in string_to_type:
99     vk = None
100     handled = False
101
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
120
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]
124
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
130
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
137
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
142
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)
148
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))
155
156       if new_shift_held != shift_held:
157         PressKey(new_shift_held, win32con.VK_SHIFT)
158         shift_held = new_shift_held
159
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)
163
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)
168
169
170 def main():
171   # We're being invoked rather than imported. Let's do some tests
172
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)
177
178   # Wait a sec to make sure it comes up
179   time.sleep(1)
180
181   # Invoke Notepad through the Run dialog
182   TypeString("wordpad\n")
183
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)
198
199
200 if __name__ == "__main__":
201   sys.exit(main())