summaryrefslogtreecommitdiffstats
path: root/tools/site_compare/drivers/win32/keyboard.py
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:12:16 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:12:16 +0000
commit920c091ac3ee15079194c82ae8a7a18215f3f23c (patch)
treed28515d1e7732e2b6d077df1b4855ace3f4ac84f /tools/site_compare/drivers/win32/keyboard.py
parentae2c20f398933a9e86c387dcc465ec0f71065ffc (diff)
downloadchromium_src-920c091ac3ee15079194c82ae8a7a18215f3f23c.zip
chromium_src-920c091ac3ee15079194c82ae8a7a18215f3f23c.tar.gz
chromium_src-920c091ac3ee15079194c82ae8a7a18215f3f23c.tar.bz2
Add tools to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/site_compare/drivers/win32/keyboard.py')
-rw-r--r--tools/site_compare/drivers/win32/keyboard.py223
1 files changed, 223 insertions, 0 deletions
diff --git a/tools/site_compare/drivers/win32/keyboard.py b/tools/site_compare/drivers/win32/keyboard.py
new file mode 100644
index 0000000..5888318
--- /dev/null
+++ b/tools/site_compare/drivers/win32/keyboard.py
@@ -0,0 +1,223 @@
+#!/usr/bin/python2.4
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""SiteCompare module for simulating keyboard input.
+
+This module contains functions that can be used to simulate a user
+pressing keys on a keyboard. Support is provided for formatted strings
+including special characters to represent modifier keys like CTRL and ALT
+"""
+
+import time # for sleep
+import win32api # for keybd_event and VkKeyCode
+import win32con # Windows constants
+
+# TODO(jhaas): Ask the readability guys if this would be acceptable:
+#
+# from win32con import VK_SHIFT, VK_CONTROL, VK_MENU, VK_LWIN, KEYEVENTF_KEYUP
+#
+# This is a violation of the style guide but having win32con. everywhere
+# is just plain ugly, and win32con is a huge import for just a handful of
+# constants
+
+
+def PressKey(down, key):
+ """Presses or unpresses a key.
+
+ Uses keybd_event to simulate either depressing or releasing
+ a key
+
+ Args:
+ down: Whether the key is to be pressed or released
+ key: Virtual key code of key to press or release
+ """
+
+ # keybd_event injects key events at a very low level (it's the
+ # Windows API keyboard device drivers call) so this is a very
+ # reliable way of simulating user input
+ win32api.keybd_event(key, 0, (not down) * win32con.KEYEVENTF_KEYUP)
+
+
+def TypeKey(key, keystroke_time=0):
+ """Simulate a keypress of a virtual key.
+
+ Args:
+ key: which key to press
+ keystroke_time: length of time (in seconds) to "hold down" the key
+ Note that zero works just fine
+
+ Returns:
+ None
+ """
+
+ # This just wraps a pair of PressKey calls with an intervening delay
+ PressKey(True, key)
+ time.sleep(keystroke_time)
+ PressKey(False, key)
+
+
+def TypeString(string_to_type,
+ use_modifiers=False,
+ keystroke_time=0,
+ time_between_keystrokes=0):
+ """Simulate typing a string on the keyboard.
+
+ Args:
+ string_to_type: the string to print
+ use_modifiers: specifies whether the following modifier characters
+ should be active:
+ {abc}: type characters with ALT held down
+ [abc]: type characters with CTRL held down
+ \ escapes {}[] and treats these values as literal
+ standard escape sequences are valid even if use_modifiers is false
+ \p is "pause" for one second, useful when driving menus
+ \1-\9 is F-key, \0 is F10
+
+ TODO(jhaas): support for explicit control of SHIFT, support for
+ nonprintable keys (F-keys, ESC, arrow keys, etc),
+ support for explicit control of left vs. right ALT or SHIFT,
+ support for Windows key
+
+ keystroke_time: length of time (in secondes) to "hold down" the key
+ time_between_keystrokes: length of time (seconds) to pause between keys
+
+ Returns:
+ None
+ """
+
+ shift_held = win32api.GetAsyncKeyState(win32con.VK_SHIFT ) < 0
+ ctrl_held = win32api.GetAsyncKeyState(win32con.VK_CONTROL) < 0
+ alt_held = win32api.GetAsyncKeyState(win32con.VK_MENU ) < 0
+
+ next_escaped = False
+ escape_chars = {
+ 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v'}
+
+ for char in string_to_type:
+ vk = None
+ handled = False
+
+ # Check to see if this is the start or end of a modified block (that is,
+ # {abc} for ALT-modified keys or [abc] for CTRL-modified keys
+ if use_modifiers and not next_escaped:
+ handled = True
+ if char == "{" and not alt_held:
+ alt_held = True
+ PressKey(True, win32con.VK_MENU)
+ elif char == "}" and alt_held:
+ alt_held = False
+ PressKey(False, win32con.VK_MENU)
+ elif char == "[" and not ctrl_held:
+ ctrl_held = True
+ PressKey(True, win32con.VK_CONTROL)
+ elif char == "]" and ctrl_held:
+ ctrl_held = False
+ PressKey(False, win32con.VK_CONTROL)
+ else:
+ handled = False
+
+ # If this is an explicitly-escaped character, replace it with the
+ # appropriate code
+ if next_escaped and char in escape_chars: char = escape_chars[char]
+
+ # If this is \p, pause for one second.
+ if next_escaped and char == 'p':
+ time.sleep(1)
+ next_escaped = False
+ handled = True
+
+ # If this is \(d), press F key
+ if next_escaped and char.isdigit():
+ fkey = int(char)
+ if not fkey: fkey = 10
+ next_escaped = False
+ vk = win32con.VK_F1 + fkey - 1
+
+ # If this is the backslash, the next character is escaped
+ if not next_escaped and char == "\\":
+ next_escaped = True
+ handled = True
+
+ # If we make it here, it's not a special character, or it's an
+ # escaped special character which should be treated as a literal
+ if not handled:
+ next_escaped = False
+ if not vk: vk = win32api.VkKeyScan(char)
+
+ # VkKeyScan() returns the scan code in the low byte. The upper
+ # byte specifies modifiers necessary to produce the given character
+ # from the given scan code. The only one we're concerned with at the
+ # moment is Shift. Determine the shift state and compare it to the
+ # current state... if it differs, press or release the shift key.
+ new_shift_held = bool(vk & (1<<8))
+
+ if new_shift_held != shift_held:
+ PressKey(new_shift_held, win32con.VK_SHIFT)
+ shift_held = new_shift_held
+
+ # Type the key with the specified length, then wait the specified delay
+ TypeKey(vk & 0xFF, keystroke_time)
+ time.sleep(time_between_keystrokes)
+
+ # Release the modifier keys, if held
+ if shift_held: PressKey(False, win32con.VK_SHIFT)
+ if ctrl_held: PressKey(False, win32con.VK_CONTROL)
+ if alt_held: PressKey(False, win32con.VK_MENU)
+
+if __name__ == "__main__":
+ # We're being invoked rather than imported. Let's do some tests
+
+ # Press command-R to bring up the Run dialog
+ PressKey(True, win32con.VK_LWIN)
+ TypeKey(ord('R'))
+ PressKey(False, win32con.VK_LWIN)
+
+ # Wait a sec to make sure it comes up
+ time.sleep(1)
+
+ # Invoke Notepad through the Run dialog
+ TypeString("wordpad\n")
+
+ # Wait another sec, then start typing
+ time.sleep(1)
+ TypeString("This is a test of SiteCompare's Keyboard.py module.\n\n")
+ TypeString("There should be a blank line above and below this one.\n\n")
+ TypeString("This line has control characters to make "
+ "[b]boldface text[b] and [i]italic text[i] and normal text.\n\n",
+ use_modifiers=True)
+ TypeString(r"This line should be typed with a visible delay between "
+ "characters. When it ends, there should be a 3-second pause, "
+ "then the menu will select File/Exit, then another 3-second "
+ "pause, then No to exit without saving. Ready?\p\p\p{f}x\p\p\pn",
+ use_modifiers=True,
+ keystroke_time=0.05,
+ time_between_keystrokes=0.05)
+
+ \ No newline at end of file