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

pynput模拟按键部分程序无法识别的问题求助

问题:pynput模拟按键无法在vba-m等游戏程序中生效,Chrome/记事本正常

我用socket和pynput实现手机远程控制电脑程序,Chrome、记事本等普通程序能正常识别pynput模拟的按键,但vba-m(GBA模拟器)这类目标游戏程序完全没响应。已经尝试用管理员权限运行脚本,问题依然存在。

我的代码如下:

import socket,threading
from pynput.keyboard import Key, Controller
PORT=12345
SERVER="192.168.1.160"
ADDR=(SERVER, PORT)
FORMAT="utf-8"
TERMINATED="ADIOS"
server=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)
conectados=[]
conectadosaddr=[]
keyboard = Controller()
def start(): #Función que se encarga de iniciar el servidor y escuchar nuevas conexiones
    server.listen()
    print("Servidor iniciado")
    while True:
        conn,addr=server.accept()
        conectados.append(conn)
        conectadosaddr.append(addr)
        thread=threading.Thread(target=handle_client, args=(conn, addr))
        thread.daemon=True
        thread.start()
        print(f"Conexiones activas: {len(conectados)}")
def handle_client(conn, addr): #Función que se encarga de manejar las conexiones
    print(f"Nueva conexion de {addr}")
    connected=True
    while connected:
        try:
            data=conn.recv(1024).decode(FORMAT)
            if data:
                print(f"Recibido: {data} de {addr}")
                if data==TERMINATED:
                    connected=False
                    print("Se ha cerrado la conexion pacíficamente de "+str(addr))
                elif data in "WASDZX":
                    keyboard.press(data)
                    keyboard.release(data)
                elif data=="BK":
                    keyboard.press(Key.backspace)
                    keyboard.release(Key.backspace)
                elif data=="ST":
                    keyboard.press(Key.enter)
                    keyboard.release(Key.enter)
        except Exception as e:
            connected=False
            print("ERROR: ",e)
    print(f"{addr} se ha desconectado")
    conectados.remove(conn)
    conectadosaddr.remove(addr)
    conn.close()
if __name__ == '__main__':
    start()

解决方案

1. 改用pynput低级键盘API模拟硬件输入

普通的Controller模拟基于Windows消息队列,部分游戏会直接读取硬件输入状态,因此无法识别。改用pynput的低级API可以绕过这个限制:

修改代码导入部分和键盘实例:

import socket,threading
from pynput.keyboard import Key, Controller, _win32
# ... 其他常量定义不变
keyboard = Controller()
low_level_keyboard = _win32.Keyboard()

然后在handle_client函数中替换按键操作:

# 替换原来的按键处理逻辑
elif data in "WASDZX":
    key_code = _win32.KeyCode.from_char(data.upper())
    low_level_keyboard.press(key_code)
    low_level_keyboard.release(key_code)
elif data=="BK":
    low_level_keyboard.press(Key.backspace)
    low_level_keyboard.release(Key.backspace)
elif data=="ST":
    low_level_keyboard.press(Key.enter)
    low_level_keyboard.release(Key.enter)

2. 直接调用Windows API的SendInput函数

如果低级API仍无效,可直接用ctypes调用SendInput,模拟最底层的硬件输入:

先添加以下工具函数:

import ctypes
from ctypes import wintypes

user32 = ctypes.WinDLL('user32', use_last_error=True)

INPUT_KEYBOARD = 1
KEYEVENTF_KEYUP = 0x0002
MAPVK_VK_TO_VSC = 0

class KEYBDINPUT(ctypes.Structure):
    _fields_ = (("wVk", wintypes.WORD),
                ("wScan", wintypes.WORD),
                ("dwFlags", wintypes.DWORD),
                ("time", wintypes.DWORD),
                ("dwExtraInfo", wintypes.WPARAM))

class INPUT(ctypes.Structure):
    class _INPUT(ctypes.Union):
        _fields_ = (("ki", KEYBDINPUT),)
    _anonymous_ = ("_input",)
    _fields_ = (("type", wintypes.DWORD),
                ("_input", _INPUT))

def press_key(key):
    if isinstance(key, str):
        vk = ord(key.upper())
    else:
        vk = key.value.vk
    scan_code = user32.MapVirtualKeyW(vk, MAPVK_VK_TO_VSC)
    # 模拟按下
    input_down = INPUT(type=INPUT_KEYBOARD,
                       ki=KEYBDINPUT(wVk=vk, wScan=scan_code, dwFlags=0))
    user32.SendInput(1, ctypes.byref(input_down), ctypes.sizeof(INPUT))
    # 模拟释放
    input_up = INPUT(type=INPUT_KEYBOARD,
                     ki=KEYBDINPUT(wVk=vk, wScan=scan_code, dwFlags=KEYEVENTF_KEYUP))
    user32.SendInput(1, ctypes.byref(input_up), ctypes.sizeof(INPUT))

然后在handle_client中替换按键操作:

elif data in "WASDZX":
    press_key(data)
elif data=="BK":
    press_key(Key.backspace)
elif data=="ST":
    press_key(Key.enter)

3. 确保游戏窗口处于前台

部分游戏仅在前台时响应输入,可在模拟按键前激活vba-m窗口:

用pygetwindow实现(需先安装:pip install pygetwindow):

import pygetwindow as gw

# 在handle_client的按键处理前添加
window_list = gw.getWindowsWithTitle("VisualBoyAdvance-M")
if window_list:
    window_list[0].activate()

或者用ctypes直接调用Windows API:

user32 = ctypes.WinDLL('user32')
hwnd = user32.FindWindowW(None, "VisualBoyAdvance-M")
if hwnd:
    user32.SetForegroundWindow(hwnd)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 08:45:28