Controlling a Windows Console App w/ stdin pipe

2019-06-05 05:42发布

I am trying to control a console application (JTAG app from Segger) from Python using the subprocess module. The application behaves correctly for stdout, but stdin doesn't seem to be read. If enable the shell, I can type into the input and control the application, but I need to do this programmatically. The same code works fine for issuing commands to something like cmd.exe.

I'm guessing that the keyboard is being read directly instead of stdin. Any ideas how I can send the application input?

from subprocess import Popen, PIPE, STDOUT
jtag = Popen('"C:/Program Files/SEGGER/JLinkARM_V402e/JLink.exe"', shell=True,
                        universal_newlines=True,
                        stdin=PIPE,
                        stdout=PIPE,
                        stderr=STDOUT)

jtag.stdin.write('usb\n')
jtag.stdin.flush()

print "Stdout:"
while True:
    s = jtag.stdout.readline()
    if not s:
        break
    print s,

jtag.terminate()

2条回答
Anthone
2楼-- · 2019-06-05 06:13

As shoosh says, I'd try to verify that the application really is looking for keyboard input. If it is, you can try Win32 message passing, or sending it keyboard input via automation.

For the message passing route, you could use the EnumWindows function via ctypes to find the window you're after, then using PostMessage to send it WM_KEYDOWN messages.

You can also send keyboard input via pywinauto, or the ActiveX control of AutoIt via win32com.

Using AutoIt:

from win32com.client import Dispatch

auto = Dispatch("AutoItX3.Control")
auto.WinActivate("The window's title", "")
auto.WinWaitActive("The window's title", "", 10)

auto.Send("The input")
查看更多
放我归山
3楼-- · 2019-06-05 06:13
I'm guessing that the keyboard is being read directly instead of stdin

This is a pretty strong assumption and before stitching a solution you should try to verify it somehow. There are different levels of doing this. Actually two I can think of right now:

  • Waiting for keyboard events from the main windows loop. if this is the case then you can simulate a keyboard simply by sending the window the right kind of message. these can be wither WM_KEYDOWN or WM_CHAR or perhaps some other related variants.
  • Actually polling the hardware, for instance using GetAsyncKeyState(). This is somewhat unlikely and if this is really what's going on, I doubt you can do anything to simulate it programatically.

Another take on this is trying to use the on-screen keyboard and see if it works with the application. if it does, figure out how to simulate what it does.

Some tools which might be helpful -

  • Spy++ (comes with Visual Studio) - allows you to see what messages go into a window
  • strace allows you to see what syscalls a process is making.
查看更多
登录 后发表回答