Управление консольным приложением Windows с помощью стандартного канала

Я пытаюсь управлять консольным приложением (приложение JTAG от Segger) из Python с помощью модуля подпроцесса. Приложение ведет себя правильно для стандартного вывода, но стандартный ввод не читается. Если включить оболочку, я могу вводить данные и управлять приложением, но мне нужно делать это программно. Тот же код отлично работает для выдачи команд чему-то вроде cmd.exe.

Я предполагаю, что клавиатура читается напрямую, а не на стандартный ввод. Любые идеи, как я могу отправить ввод приложения?

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()

person Eric    schedule 06.04.2009    source источник


Ответы (2)


Как говорит Shoosh, я бы попытался убедиться, что приложение действительно ищет ввод с клавиатуры. Если это так, вы можете попробовать передачу сообщений Win32 или отправку ввода с клавиатуры с помощью автоматизации.

Для маршрута передачи сообщений вы можете использовать функцию EnumWindows через ctypes чтобы найти нужное окно, а затем с помощью PostMessage отправить ему сообщения WM_KEYDOWN.

Вы также можете отправлять ввод с клавиатуры через pywinauto или элемент управления ActiveX AutoIt через win32com.

Использование 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")
person Ryan Ginstrom    schedule 07.04.2009
comment
Этот код работает. Единственная проблема заключается в том, что если пользователь щелкает где-либо, он теряет фокус ввода, и мне приходится открывать внешний терминал, а не скрывать его. Любые мысли о том, как это сделать, сохраняя при этом дочерний процесс скрытым? - person Eric; 07.04.2009
comment
EnumWindows -> PostMessage(hwnd, WM_KEYDOWN, ...) должен позволить вам скрыть дочерний процесс, если на самом деле проблема заключается в том, что дочерний процесс читает ввод с помощью клавиш, а не stdin. - person Ryan Ginstrom; 07.04.2009

I'm guessing that the keyboard is being read directly instead of stdin

Это довольно сильное предположение, и прежде чем сшивать решение, вы должны попытаться его как-то проверить. Есть разные уровни этого. На самом деле два, о которых я могу думать прямо сейчас:

  • Ожидание событий клавиатуры из основного цикла Windows. если это так, то вы можете имитировать клавиатуру, просто отправив окну правильное сообщение. это могут быть увядания WM_KEYDOWN или WM_CHAR или, возможно, некоторые другие родственные варианты.
  • На самом деле опрос оборудования, например, с помощью GetAsyncKeyState(). Это несколько маловероятно, и если это действительно то, что происходит, я сомневаюсь, что вы можете сделать что-нибудь, чтобы смоделировать это программно.

Другой вариант — попытаться использовать экранную клавиатуру и посмотреть, работает ли она с приложением. если это так, выясните, как имитировать то, что он делает.

Некоторые инструменты, которые могут быть полезны -

  • Spy++ (поставляется с Visual Studio) — позволяет увидеть, какие сообщения попадают в окно.
  • strace позволяет увидеть, какие системные вызовы выполняет процесс.
person shoosh    schedule 06.04.2009
comment
Похоже, что программа прослушивает события сообщений WM_KEYDOWN / WM_CHAR, а не смотрит на стандартный ввод. Я не знал о StraceNT - спасибо! - person Eric; 07.04.2009