如何在Windows上通过Python控制交互式控制台的输入/输出? [英] How to control interactive console input/output from Python on Windows?
问题描述
我需要控制一个Windows程序,该程序通过从< conio.h>
调用 _kbhit
和 _getch
直接从控制台读取输入.可以在此处找到此类程序的示例: https://stackoverflow.com/a/15603102/365492
I need to control a Windows program, which reads input directly from console by calling _kbhit
and _getch
from <conio.h>
. An example of such program can be found here: https://stackoverflow.com/a/15603102/365492
在Linux上,我可以使用 pty.openpty()
创建新的伪终端并模拟按键.请参见以下示例: https://code.google.com/p/lilykde/source/browse/trunk/lilykde/py/runpty.py
On Linux I can use pty.openpty()
to create new pseudo-terminal and to emulate key presses. See this example: https://code.google.com/p/lilykde/source/browse/trunk/lilykde/py/runpty.py
在Windows上,我尝试写入 CONIN $
/ CONOUT $
,但是我只能看到我的数据出现在控制台上,而子进程却忽略了它.
On Windows I tried to write to CONIN$
/CONOUT$
but all I can see is that my data is appearing on the console, while child process ignores it.
这是代码:
#!/usr/bin/env python
import subprocess
import time
TEST_EXECUTABLE = 'C:\\dev\\test.exe'
TEST_INPUT = 'C:\\dev\\input.txt'
def main():
with open(TEST_INPUT, mode='r') as test_input, open('CONOUT$', mode='wb') as conout:
test_exec = subprocess.Popen([TEST_EXECUTABLE],
bufsize=0,
stdin=None,
stdout=None,
stderr=None)
for cmd in test_input:
cmd = cmd.strip('\r\n')
conout.write(cmd)
conout.flush()
time.sleep(1)
ret = test_exec.wait()
print '%s (%d): %d' % (TEST_EXECUTABLE, test_exec.pid, ret)
pass
if __name__ == "__main__":
main()
有可能吗?如何模拟用户与子进程的交互?
Is it possible at all? How can I emulate user interaction with the child process?
谢谢.亚历克斯
推荐答案
我找到了答案.不幸的是,没有内置模块可以执行此操作,因此我不得不使用 ctypes
和一些Win32 API来完成此操作.这是代码:
I found the answer. Unfortunately, there is no built-in modules to do this, so I had to use ctypes
and some Win32 API to accomplish this. Here is the code:
#!/usr/bin/env python
from ctypes import *
import msvcrt
import os
import subprocess
import time
TEST_EXECUTABLE = 'C:\\dev\\test.exe'
TEST_INPUT = 'C:\\dev\\input.txt'
# input event types
KEY_EVENT = 0x0001
# constants, flags
MAPVK_VK_TO_VSC = 0
# structures
class CHAR_UNION(Union):
_fields_ = [("UnicodeChar", c_wchar),
("AsciiChar", c_char)]
def to_str(self):
return ''
class KEY_EVENT_RECORD(Structure):
_fields_ = [("bKeyDown", c_byte),
("pad2", c_byte),
("pad1", c_short),
("wRepeatCount", c_short),
("wVirtualKeyCode", c_short),
("wVirtualScanCode", c_short),
("uChar", CHAR_UNION),
("dwControlKeyState", c_int)]
def to_str(self):
return ''
class INPUT_UNION(Union):
_fields_ = [("KeyEvent", KEY_EVENT_RECORD)]
def to_str(self):
return ''
class INPUT_RECORD(Structure):
_fields_ = [("EventType", c_short),
("Event", INPUT_UNION)]
def to_str(self):
return ''
def write_key_to_console(hcon, key):
li = INPUT_RECORD * 2
list_input = li()
ke = KEY_EVENT_RECORD()
ke.bKeyDown = c_byte(1)
ke.wRepeatCount = c_short(1)
cnum = ord(key)
ke.wVirtualKeyCode = windll.user32.VkKeyScanW(cnum)
ke.wVirtualScanCode = c_short(windll.user32.MapVirtualKeyW(int(cnum),
MAPVK_VK_TO_VSC))
ke.uChar.UnicodeChar = unichr(cnum)
kc = INPUT_RECORD(KEY_EVENT)
kc.Event.KeyEvent = ke
list_input[0] = kc
list_input[1] = list_input[0]
list_input[1].Event.KeyEvent.bKeyDown = c_byte(0)
events_written = c_int()
ret = windll.kernel32.WriteConsoleInputW(hcon,
list_input,
2,
byref(events_written))
return ret
def main():
with open(TEST_INPUT, mode='r') as test_input:
fdcon = os.open('CONIN$', os.O_RDWR | os.O_BINARY)
hconin = msvcrt.get_osfhandle(fdcon)
test_exec = subprocess.Popen([TEST_EXECUTABLE])
for cmd in test_input:
cmd = cmd.strip('\r\n')
write_key_to_console(hconin, cmd)
time.sleep(1)
os.close(fdcon)
ret = test_exec.wait()
print '%s (%d): %d' % (TEST_EXECUTABLE, test_exec.pid, ret)
pass
if __name__ == "__main__":
main()
input.txt
文件每行包含一个字符. write_key_to_console
函数可以轻松扩展为一次写入多个字符.
The input.txt
file contains one character per line. write_key_to_console
function can be easily extended to write several characters at once.
如果调用进程没有控制台,或者其控制台与子进程中的控制台不同,则在打开<之前,我们需要使用子进程ID作为参数调用 AttachConsole
函数.code> CONIN $ 文件.
If the calling process doesn't have a console or its console is different from the one of the child process, then we need to call AttachConsole
function with child process ID as parameter before we open CONIN$
file.
这篇关于如何在Windows上通过Python控制交互式控制台的输入/输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!