You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python subprocess调用festival.exe时模拟按键输入无效程序阻塞

问题根因

你之前尝试的两种stdin写入方案全部失效,核心原因是festival.exe的按键等待逻辑根本没有读取标准输入流(stdin):它是直接调用Windows控制台原生API(比如_getch、ReadConsoleInput)从自身绑定的控制台窗口输入缓冲区读取事件,和stdin管道完全是两个独立的输入通道,你往PIPE里写入的内容永远不会被程序读到,自然无法触发程序继续执行。

可行解决方案

你可以根据自己是否需要保留程序的控制台窗口,选择对应的方案:

方案1:无窗口启动(最简单,无需额外依赖)

如果你不需要看到festival.exe的控制台界面,启动进程时加上CREATE_NO_WINDOW创建标志即可。这种模式下程序没有关联的控制台,调用读取按键的API会直接返回失败,不会进入阻塞等待状态,会自动走完后续流程(通常是直接退出)。
示例代码:

from subprocess import Popen, CREATE_NO_WINDOW

proc = Popen(
    "festival.exe level.sok",
    creationflags=CREATE_NO_WINDOW
)
# 等待进程执行结束即可,不会卡在按键等待步骤
proc.wait()

方案2:保留窗口,直接向控制台缓冲区写入按键事件

如果你需要查看程序的运行输出、不能隐藏控制台,可以通过Windows API直接向程序关联的控制台输入缓冲区写入模拟按键事件,和手动按键的效果完全一致。

注意:启动进程时不要把stdin重定向到PIPE,否则程序会失去和控制台的绑定,后续发送的事件无法被接收。如果需要收集输出,可以把stdout/stderr重定向到文件。

示例代码:

import ctypes
from ctypes import wintypes
from subprocess import Popen
import time

# Windows API常量定义
STD_INPUT_HANDLE = -10
KEY_EVENT_TYPE = 0x0001
VK_RETURN = 0x0D  # 回车键虚拟键码

# 定义控制台输入事件结构体
class KEY_EVENT_RECORD(ctypes.Structure):
    _fields_ = [
        ("bKeyDown", wintypes.BOOL),
        ("wRepeatCount", wintypes.WORD),
        ("wVirtualKeyCode", wintypes.WORD),
        ("wVirtualScanCode", wintypes.WORD),
        ("UnicodeChar", wintypes.WCHAR),
        ("dwControlKeyState", wintypes.DWORD)
    ]

class INPUT_RECORD(ctypes.Structure):
    _fields_ = [
        ("EventType", wintypes.WORD),
        ("KeyEvent", KEY_EVENT_RECORD)
    ]

# 启动进程,不要重定向stdin
proc = Popen("festival.exe level.sok")
# 等待程序运行到等待按键的阶段,等待时间根据程序实际运行速度调整
time.sleep(2)

# 加载kernel32.dll获取控制台操作接口
kernel32 = ctypes.WinDLL("kernel32.dll", use_last_error=True)
console_input_handle = kernel32.GetStdHandle(STD_INPUT_HANDLE)

# 构造回车按下事件
key_down = INPUT_RECORD()
key_down.EventType = KEY_EVENT_TYPE
key_down.KeyEvent.bKeyDown = True
key_down.KeyEvent.wRepeatCount = 1
key_down.KeyEvent.wVirtualKeyCode = VK_RETURN
key_down.KeyEvent.UnicodeChar = "\r"

# 构造回车抬起事件,避免按键状态异常
key_up = INPUT_RECORD()
key_up.EventType = KEY_EVENT_TYPE
key_up.KeyEvent.bKeyDown = False
key_up.KeyEvent.wRepeatCount = 1
key_up.KeyEvent.wVirtualKeyCode = VK_RETURN
key_up.KeyEvent.UnicodeChar = "\r"

written_count = wintypes.DWORD()
# 写入按键事件到控制台缓冲区
kernel32.WriteConsoleInputW(
    console_input_handle,
    ctypes.byref(key_down),
    1,
    ctypes.byref(written_count)
)
kernel32.WriteConsoleInputW(
    console_input_handle,
    ctypes.byref(key_up),
    1,
    ctypes.byref(written_count)
)

proc.wait()

方案3:使用第三方封装库简化模拟逻辑

如果不想手写ctypes调用逻辑,也可以使用pywin32库封装好的控制台操作接口,或者pynput等全局按键模拟工具发送按键。注意用全局按键模拟时需要确保festival.exe的控制台窗口处于前台激活状态,否则按键会被发送到当前激活的其他程序。


内容的提问来源于stack exchange,提问作者Tibcik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 18:39:17