>>> import subprocess
>>> dva=subprocess.Popen(DVAname,stdin=subprocess.PIPE)
Unfortunately sending keystrokes with communicate() does not appear to work:
>>> dva.communicate('F2')
this does not produce any result but it does make IDLE become really idle.
>>> dva.terminate()
however does work fine and kills the program as it should.
Is there a way or do I have to go back to Visual Basic?
Regards,
Alex van der Spek
Amusing. :)
>>>> dva.terminate()
>
> however does work fine and kills the program as it should.
>
> Is there a way or do I have to go back to Visual Basic?
I've not used the subprocess module actually, and your post suggests
that what I've been doing may be suboptimal, but in the Yosemite
project I have this code:
import win32api
def dokey(key1,key2=None):
win32api.keybd_event(key1,0,0,0)
if key2!=None:
win32api.keybd_event(key2,0,0,0)
win32api.keybd_event(key2,0,2,0)
win32api.keybd_event(key1,0,2,0)
shift=16; ctrl=17; left=37; right=39; space=32
To send Shift-Right Arrow, I call:
dokey(shift,right)
(This code multiplexes its options for cross-platform capabilities,
taking advantage of the fact that Python allows you to define
functions inside an if block.)
win32api.keybd_event is a fairly "raw" call that just passes its
parameters straight through to the underlying keybd_event Windows API.
It doesn't send keys to a specific window, it instead sends keys to
"whichever window currently has focus" (which is what I want for
Yosemite). Not sure if that's suited to your needs.
Chris Angelico
I've just looked over the Python subprocess module. Is your subprocess
(named by the variable DVAname) one which takes key names on STDIN and
emits the appropriate keys?
dva.communicate('F2') will send the two-character string "F2" to the
STDIN of the process, and then wait for process termination. That's
why IDLE stops dead. If you want to send it a string and then keep
running, I think you want to use the stdin attribute:
dva.stdin.write('F2')
Chris Angelico
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