Sending keystrokes to Windows exe programs

eryksun () eryksun at gmail.com
Sun Apr 3 05:08:05 CEST 2011


On Saturday, April 2, 2011 12:48:44 PM UTC-4, Alex van der Spek wrote:
>
> I can start a windows program on Vista with:
> 
> >>> import subprocess
> >>> dva=subprocess.Popen(DVAname,stdin=subprocess.PIPE)
> 
> Unfortunately sending keystrokes with communicate() does not appear to work:
> 
> >>> dva.communicate('F2')

Is this a GUI process? If so, it probably doesn't have stdin unless it also has a console (possibly hidden). 

To send keys to a GUI Window, you can use win32com (from the pywin32 extensions) to execute WScript commands:

import time
import win32com
import win32com.client

shell = win32com.client.Dispatch('WScript.Shell')
shell.Run('notepad')
time.sleep(0.1)
shell.AppActivate('notepad')
shell.SendKeys("Hello World", 0)
shell.SendKeys("{Enter}", 0)
shell.SendKeys("{F5}", 0)   # F5 prints the time/date

Documentation for SendKeys:
http://msdn.microsoft.com/en-us/library/8c6yea83

SendKeys only sends to the active Window. If you need to send keys to a background Window, you can use win32 messaging. 

If you load the process with CreateProcess, you'll get the the main thread ID (tid) as well as the process ID (pid). Then you can enumerate handles for the thread's windows into a dictionary keyed by the window classes (or window class + window title). 

Here's the example with notepad, but this time using win32 messaging:

import time
import win32con
import win32api
import win32gui
import win32process

_, cmd = win32api.FindExecutable('notepad')

_, _, pid, tid = win32process.CreateProcess(
    None,    # name
    cmd,     # command line
    None,    # process attributes
    None,    # thread attributes
    0,       # inheritance flag
    0,       # creation flag
    None,    # new environment
    None,    # current directory
    win32process.STARTUPINFO ())

# wcallb is callback for EnumThreadWindows and 
# EnumChildWindows. It populates the dict 'handle' with 
# references by class name for each window and child 
# window of the given thread ID.

def wcallb(hwnd, handle):
    handle[win32gui.GetClassName(hwnd)] = hwnd
    win32gui.EnumChildWindows(hwnd, wcallb, handle)
    return True

handle = {}
while not handle:   # loop until the window is loaded
    time.sleep(0.1)
    win32gui.EnumThreadWindows(tid, wcallb, handle)

# Sending normal characters is a WM_CHAR message. 
# Function keys are sent as WM_KEYDOWN and WM_KEYUP 
# messages using the virtual keys defined in win32con, 
# such as VK_F5 for the f5 key.
#
# Notepad has a separate 'Edit' window to which you can 
# write, but function keys are processed by the main 
# window. 

for c in "Hello World\n":
    win32api.PostMessage(
        handle['Edit'], 
        win32con.WM_CHAR, 
        ord(c), 
        0)

win32api.PostMessage(
    handle['Notepad'], 
    win32con.WM_KEYDOWN, 
    win32con.VK_F5, 
    0)
win32api.PostMessage(
    handle['Notepad'], 
    win32con.WM_KEYUP, 
    win32con.VK_F5, 
    0)

# SendMessage waits for a response, but PostMessage 
# queues the message and returns immediately




More information about the Python-list mailing list