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

为残障人士开发游戏语音控制软件,如何用Python实现游戏内按键长按?

实现Windows游戏中生效的键盘/鼠标长按功能

针对你开发残障人士游戏语音辅助软件的需求,核心解决方案是使用Windows原生的SendInput API——这是系统级的输入模拟接口,相比pynput、pyautogui等高层库,它能模拟更接近真实硬件的输入信号,更容易被DirectX/Unity等游戏引擎识别。

核心原理

多数游戏不会通过Windows消息队列读取输入,而是直接读取键盘/鼠标的硬件状态(比如DirectInput)。pynput这类库本质是发送WM_KEYDOWN/WM_KEYUP消息,无法被这类游戏识别;而SendInput会直接将输入事件注入到系统的输入流中,和真实按键/鼠标操作的逻辑一致,兼容性更强。

代码实现(Python + ctypes)

1. 键盘长按模拟

通过ctypes调用user32.dll中的SendInput,先定义所需的结构体和常量:

import ctypes
import time

# 加载user32.dll
user32 = ctypes.WinDLL('user32', use_last_error=True)

# 定义常量
INPUT_KEYBOARD = 1
KEYEVENTF_SCANCODE = 0x0008
KEYEVENTF_KEYUP = 0x0002

# 定义结构体
class INPUT(ctypes.Structure):
    _fields_ = [("type", ctypes.c_uint),
                ("ki", ctypes.c_void_p)]  # 共用体简化处理

class KEYBDINPUT(ctypes.Structure):
    _fields_ = [("wVk", ctypes.c_ushort),
                ("wScan", ctypes.c_ushort),
                ("dwFlags", ctypes.c_uint),
                ("time", ctypes.c_uint),
                ("dwExtraInfo", ctypes.c_void_p)]

# 辅助函数:转换虚拟键码到扫描码
def vk_to_scan(vk_code):
    return user32.MapVirtualKeyW(vk_code, 0)

# 按住按键
def hold_key(vk_code):
    scan_code = vk_to_scan(vk_code)
    ki = KEYBDINPUT(0, scan_code, KEYEVENTF_SCANCODE, 0, None)
    input_obj = INPUT(INPUT_KEYBOARD, ctypes.byref(ki))
    user32.SendInput(1, ctypes.byref(input_obj), ctypes.sizeof(INPUT))

# 松开按键
def release_key(vk_code):
    scan_code = vk_to_scan(vk_code)
    ki = KEYBDINPUT(0, scan_code, KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP, 0, None)
    input_obj = INPUT(INPUT_KEYBOARD, ctypes.byref(ki))
    user32.SendInput(1, ctypes.byref(input_obj), ctypes.sizeof(INPUT))

# 示例:按住W键2秒
if __name__ == "__main__":
    VK_W = 0x57
    hold_key(VK_W)
    time.sleep(2)
    release_key(VK_W)

2. 鼠标长按模拟

同样用SendInput实现鼠标按键的长按:

# 补充鼠标相关常量和结构体
INPUT_MOUSE = 0
MOUSEEVENTF_LEFTDOWN = 0x0002
MOUSEEVENTF_LEFTUP = 0x0004
MOUSEEVENTF_RIGHTDOWN = 0x0008
MOUSEEVENTF_RIGHTUP = 0x0010

class MOUSEINPUT(ctypes.Structure):
    _fields_ = [("dx", ctypes.c_long),
                ("dy", ctypes.c_long),
                ("mouseData", ctypes.c_uint),
                ("dwFlags", ctypes.c_uint),
                ("time", ctypes.c_uint),
                ("dwExtraInfo", ctypes.c_void_p)]

# 按住鼠标左键
def hold_left_mouse():
    mi = MOUSEINPUT(0, 0, 0, MOUSEEVENTF_LEFTDOWN, 0, None)
    input_obj = INPUT(INPUT_MOUSE, ctypes.byref(mi))
    user32.SendInput(1, ctypes.byref(input_obj), ctypes.sizeof(INPUT))

# 松开鼠标左键
def release_left_mouse():
    mi = MOUSEINPUT(0, 0, 0, MOUSEEVENTF_LEFTUP, 0, None)
    input_obj = INPUT(INPUT_MOUSE, ctypes.byref(mi))
    user32.SendInput(1, ctypes.byref(input_obj), ctypes.sizeof(INPUT))

# 示例:长按鼠标左键1秒
if __name__ == "__main__":
    hold_left_mouse()
    time.sleep(1)
    release_left_mouse()

关键注意事项

  • 管理员权限:部分游戏会限制非管理员程序的输入模拟,运行脚本时右键选择“以管理员身份运行”。
  • 扫描码兼容性:使用扫描码(而非虚拟键码)能更好兼容不同键盘布局和游戏,若vk_to_scan转换有问题,可直接使用对应按键的扫描码(比如W键的扫描码是0x11)。
  • 反作弊检测:多数主流反作弊系统(如Easy Anti-Cheat)不会拦截SendInput,但部分硬核反作弊可能会,此时需考虑使用驱动级模拟,但门槛较高。
  • 延迟控制:不要在短时间内频繁发送输入事件,给系统留足够的处理时间(比如用time.sleep控制长按时长)。
  • 测试顺序:先在记事本、画图等简单程序验证功能,再迁移到游戏中测试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 19:40:11