15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""SiteCompare module for simulating keyboard input. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This module contains functions that can be used to simulate a user 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)pressing keys on a keyboard. Support is provided for formatted strings 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)including special characters to represent modifier keys like CTRL and ALT 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time # for sleep 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import win32api # for keybd_event and VkKeyCode 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import win32con # Windows constants 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# TODO(jhaas): Ask the readability guys if this would be acceptable: 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# from win32con import VK_SHIFT, VK_CONTROL, VK_MENU, VK_LWIN, KEYEVENTF_KEYUP 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This is a violation of the style guide but having win32con. everywhere 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# is just plain ugly, and win32con is a huge import for just a handful of 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# constants 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def PressKey(down, key): 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Presses or unpresses a key. 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Uses keybd_event to simulate either depressing or releasing 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) a key 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) down: Whether the key is to be pressed or released 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key: Virtual key code of key to press or release 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # keybd_event injects key events at a very low level (it's the 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Windows API keyboard device drivers call) so this is a very 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # reliable way of simulating user input 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) win32api.keybd_event(key, 0, (not down) * win32con.KEYEVENTF_KEYUP) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def TypeKey(key, keystroke_time=0): 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Simulate a keypress of a virtual key. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key: which key to press 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keystroke_time: length of time (in seconds) to "hold down" the key 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Note that zero works just fine 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) None 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # This just wraps a pair of PressKey calls with an intervening delay 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PressKey(True, key) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(keystroke_time) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PressKey(False, key) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def TypeString(string_to_type, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_modifiers=False, 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keystroke_time=0, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_between_keystrokes=0): 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Simulate typing a string on the keyboard. 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string_to_type: the string to print 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_modifiers: specifies whether the following modifier characters 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should be active: 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) {abc}: type characters with ALT held down 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) [abc]: type characters with CTRL held down 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) \ escapes {}[] and treats these values as literal 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) standard escape sequences are valid even if use_modifiers is false 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) \p is "pause" for one second, useful when driving menus 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) \1-\9 is F-key, \0 is F10 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TODO(jhaas): support for explicit control of SHIFT, support for 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nonprintable keys (F-keys, ESC, arrow keys, etc), 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) support for explicit control of left vs. right ALT or SHIFT, 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) support for Windows key 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keystroke_time: length of time (in secondes) to "hold down" the key 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_between_keystrokes: length of time (seconds) to pause between keys 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) None 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shift_held = win32api.GetAsyncKeyState(win32con.VK_SHIFT ) < 0 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_held = win32api.GetAsyncKeyState(win32con.VK_CONTROL) < 0 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alt_held = win32api.GetAsyncKeyState(win32con.VK_MENU ) < 0 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_escaped = False 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) escape_chars = { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v'} 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for char in string_to_type: 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vk = None 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handled = False 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Check to see if this is the start or end of a modified block (that is, 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # {abc} for ALT-modified keys or [abc] for CTRL-modified keys 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if use_modifiers and not next_escaped: 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handled = True 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if char == "{" and not alt_held: 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alt_held = True 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PressKey(True, win32con.VK_MENU) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif char == "}" and alt_held: 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) alt_held = False 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PressKey(False, win32con.VK_MENU) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif char == "[" and not ctrl_held: 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_held = True 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PressKey(True, win32con.VK_CONTROL) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif char == "]" and ctrl_held: 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ctrl_held = False 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PressKey(False, win32con.VK_CONTROL) 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handled = False 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If this is an explicitly-escaped character, replace it with the 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # appropriate code 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if next_escaped and char in escape_chars: char = escape_chars[char] 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If this is \p, pause for one second. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if next_escaped and char == 'p': 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(1) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_escaped = False 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handled = True 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If this is \(d), press F key 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if next_escaped and char.isdigit(): 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fkey = int(char) 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not fkey: fkey = 10 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_escaped = False 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vk = win32con.VK_F1 + fkey - 1 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If this is the backslash, the next character is escaped 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not next_escaped and char == "\\": 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_escaped = True 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) handled = True 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If we make it here, it's not a special character, or it's an 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # escaped special character which should be treated as a literal 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not handled: 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_escaped = False 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not vk: vk = win32api.VkKeyScan(char) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # VkKeyScan() returns the scan code in the low byte. The upper 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # byte specifies modifiers necessary to produce the given character 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # from the given scan code. The only one we're concerned with at the 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # moment is Shift. Determine the shift state and compare it to the 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # current state... if it differs, press or release the shift key. 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_shift_held = bool(vk & (1<<8)) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if new_shift_held != shift_held: 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PressKey(new_shift_held, win32con.VK_SHIFT) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) shift_held = new_shift_held 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Type the key with the specified length, then wait the specified delay 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeKey(vk & 0xFF, keystroke_time) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(time_between_keystrokes) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Release the modifier keys, if held 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if shift_held: PressKey(False, win32con.VK_SHIFT) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ctrl_held: PressKey(False, win32con.VK_CONTROL) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if alt_held: PressKey(False, win32con.VK_MENU) 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main(): 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # We're being invoked rather than imported. Let's do some tests 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Press command-R to bring up the Run dialog 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PressKey(True, win32con.VK_LWIN) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeKey(ord('R')) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PressKey(False, win32con.VK_LWIN) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Wait a sec to make sure it comes up 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(1) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Invoke Notepad through the Run dialog 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeString("wordpad\n") 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Wait another sec, then start typing 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time.sleep(1) 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeString("This is a test of SiteCompare's Keyboard.py module.\n\n") 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeString("There should be a blank line above and below this one.\n\n") 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeString("This line has control characters to make " 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "[b]boldface text[b] and [i]italic text[i] and normal text.\n\n", 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_modifiers=True) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeString(r"This line should be typed with a visible delay between " 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "characters. When it ends, there should be a 3-second pause, " 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "then the menu will select File/Exit, then another 3-second " 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "pause, then No to exit without saving. Ready?\p\p\p{f}x\p\p\pn", 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_modifiers=True, 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) keystroke_time=0.05, 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) time_between_keystrokes=0.05) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == "__main__": 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.exit(main()) 202