diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:12:16 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:12:16 +0000 |
commit | 920c091ac3ee15079194c82ae8a7a18215f3f23c (patch) | |
tree | d28515d1e7732e2b6d077df1b4855ace3f4ac84f /tools/site_compare/drivers/win32/keyboard.py | |
parent | ae2c20f398933a9e86c387dcc465ec0f71065ffc (diff) | |
download | chromium_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.py | 223 |
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 |