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

Python使用Pynput实现scrcpy多按键映射下同步鼠标按下事件方案

问题根源

你当前代码无法实现多点操作的核心原因是:你通过pynput模拟的是电脑端单鼠标的左键点击,普通鼠标硬件本身就不支持同时在多个不同位置触发点击,自然无法对应安卓端的多点触控需求。

实现方案

完全可以用Python实现该需求,你需要放弃模拟电脑鼠标的思路,改为直接通过adb向安卓设备发送独立的多点触控事件,每个映射按键对应一个独立的触控点ID,不同按键的操作互不干扰。

具体修改步骤

  1. 确保你的电脑已经通过adb连接了安卓设备(使用scrcpy时默认已经完成adb连接,无需额外操作)
  2. 将原有的模拟鼠标点击逻辑替换为调用adb命令发送触控事件,每个功能按键分配唯一的触点ID,例如:
    • WASD移动对应触点ID 0
    • 空格键跳跃对应触点ID 1
    • 其他功能键依次分配ID 2、3、4...
  3. 按键按下时发送对应触点的DOWN事件,按键松开时发送对应触点的UP事件,互不影响。

修改后代码示例

import subprocess
from pynput.keyboard import Key, KeyCode, Listener

# 配置参数
CENTER = 315
HEIGHT = 800
LISTEN = None

# 每个按键对应唯一的触控点ID,避免冲突
POINTER_ID_MAP = {
    'w': 0,
    's': 0,
    'a': 0,
    'd': 0,
    'space': 1,
    'c': 2,
    'r': 3,
    'f': 4,
    'shift_l': 5,
    'q': 6,
    '1': 7,
    '2': 8,
    '3': 9
}

def adb_touch_down(pointer_id, x, y):
    """发送指定触点的按下事件"""
    subprocess.run(
        ['adb', 'shell', 'input', 'motionevent', f'DOWN/{pointer_id}', str(x), str(y)],
        capture_output=True
    )

def adb_touch_up(pointer_id, x, y):
    """发送指定触点的抬起事件"""
    subprocess.run(
        ['adb', 'shell', 'input', 'motionevent', f'UP/{pointer_id}', str(x), str(y)],
        capture_output=True
    )

def adb_touch_move(pointer_id, x, y):
    """发送指定触点的移动事件"""
    subprocess.run(
        ['adb', 'shell', 'input', 'motionevent', f'MOVE/{pointer_id}', str(x), str(y)],
        capture_output=True
    )

# 功能函数
def w():
    adb_touch_move(POINTER_ID_MAP['w'], CENTER, HEIGHT - 100)

def s():
    adb_touch_move(POINTER_ID_MAP['s'], CENTER, HEIGHT + 100)

def a():
    adb_touch_move(POINTER_ID_MAP['a'], CENTER - 100, HEIGHT)

def d():
    adb_touch_move(POINTER_ID_MAP['d'], CENTER + 100, HEIGHT)

def space():
    adb_touch_down(POINTER_ID_MAP['space'], int(CENTER*5.75), int(HEIGHT*0.95))

def c():
    adb_touch_down(POINTER_ID_MAP['c'], int(CENTER*5.15), int(HEIGHT*1.2))

def r():
    adb_touch_down(POINTER_ID_MAP['r'], int(CENTER*4.75), int(HEIGHT*1.15))

def f():
    adb_touch_down(POINTER_ID_MAP['f'], int(CENTER*0.5), int(HEIGHT*0.7))

def ctrl():
    adb_touch_down(POINTER_ID_MAP['shift_l'], int(CENTER*5.15), HEIGHT)

def q():
    adb_touch_down(POINTER_ID_MAP['q'], int(CENTER*5.3), int(HEIGHT*0.77))

def switch1():
    adb_touch_down(POINTER_ID_MAP['1'], int(CENTER*2.75), int(HEIGHT*1.15))

def switch2():
    adb_touch_down(POINTER_ID_MAP['2'], int(CENTER*3.3), int(HEIGHT*1.15))

def switch3():
    adb_touch_down(POINTER_ID_MAP['3'], int(CENTER*3), int(HEIGHT*1.05))

# 按下移动键时先按下移动触点
move_pressed = False
def on_press(key):
    global move_pressed
    try:
        if key == KeyCode(char='w'):
            if not move_pressed:
                adb_touch_down(POINTER_ID_MAP['w'], CENTER, HEIGHT)
                move_pressed = True
            w()
        elif key == KeyCode(char='s'):
            if not move_pressed:
                adb_touch_down(POINTER_ID_MAP['s'], CENTER, HEIGHT)
                move_pressed = True
            s()
        elif key == KeyCode(char='a'):
            if not move_pressed:
                adb_touch_down(POINTER_ID_MAP['a'], CENTER, HEIGHT)
                move_pressed = True
            a()
        elif key == KeyCode(char='d'):
            if not move_pressed:
                adb_touch_down(POINTER_ID_MAP['d'], CENTER, HEIGHT)
                move_pressed = True
            d()
        elif key == Key.space:
            space()
        elif key == KeyCode(char='c'):
            c()
        elif key == KeyCode(char='r'):
            r()
        elif key == KeyCode(char='f'):
            f()
        elif key == Key.shift_l:
            ctrl()
        elif key == KeyCode(char='q'):
            q()
        elif key == KeyCode(char='1'):
            switch1()
        elif key == KeyCode(char='2'):
            switch2()
        elif key == KeyCode(char='3'):
            switch3()
        elif key == Key.tab:
            LISTEN.stop()
    except AttributeError:
        pass

def on_release(key):
    global move_pressed
    try:
        # 处理移动键释放
        if key in [KeyCode(char='w'), KeyCode(char='s'), KeyCode(char='a'), KeyCode(char='d')]:
            adb_touch_up(POINTER_ID_MAP['w'], CENTER, HEIGHT)
            move_pressed = False
        # 处理其他按键释放
        elif key == Key.space:
            adb_touch_up(POINTER_ID_MAP['space'], int(CENTER*5.75), int(HEIGHT*0.95))
        elif key == KeyCode(char='c'):
            adb_touch_up(POINTER_ID_MAP['c'], int(CENTER*5.15), int(HEIGHT*1.2))
        elif key == KeyCode(char='r'):
            adb_touch_up(POINTER_ID_MAP['r'], int(CENTER*4.75), int(HEIGHT*1.15))
        elif key == KeyCode(char='f'):
            adb_touch_up(POINTER_ID_MAP['f'], int(CENTER*0.5), int(HEIGHT*0.7))
        elif key == Key.shift_l:
            adb_touch_up(POINTER_ID_MAP['shift_l'], int(CENTER*5.15), HEIGHT)
        elif key == KeyCode(char='q'):
            adb_touch_up(POINTER_ID_MAP['q'], int(CENTER*5.3), int(HEIGHT*0.77))
        elif key == KeyCode(char='1'):
            adb_touch_up(POINTER_ID_MAP['1'], int(CENTER*2.75), int(HEIGHT*1.15))
        elif key == KeyCode(char='2'):
            adb_touch_up(POINTER_ID_MAP['2'], int(CENTER*3.3), int(HEIGHT*1.15))
        elif key == KeyCode(char='3'):
            adb_touch_up(POINTER_ID_MAP['3'], int(CENTER*3), int(HEIGHT*1.05))
    except AttributeError:
        pass

# 启动监听
with Listener(on_press=on_press, on_release=on_release) as LISTEN:
    LISTEN.join()

优化建议

如果觉得adb命令调用延迟较高,可以改用Python的adb-shell库直接通过socket发送adb指令,减少进程调用开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 12:36:03