Skip to content

Conversation

@MistEO
Copy link
Member

@MistEO MistEO commented Dec 11, 2025

Summary by Sourcery

基于通过 ViGEm 的虚拟 Xbox 360 手柄,新增一种 Win32 手柄输入方法,并在各语言绑定和文档中公开该功能。

新增特性:

  • 引入一种通过 ViGEm 驱动虚拟 Xbox 360 手柄的 Win32 手柄输入方法。
  • 在 CLI 配置解析以及 Node.js 和 Python 的语言绑定中公开该手柄输入方法。
  • 添加捆绑的 ViGEm 客户端头文件,以支持虚拟手柄集成。

文档:

  • 在英文版 Win32 控制方法指南中记录新的手柄控制方法,包括其需求和特性。
Original summary in English

Summary by Sourcery

Add a new Win32 gamepad input method based on a virtual Xbox 360 controller via ViGEm and expose it across bindings and documentation.

New Features:

  • Introduce a Gamepad Win32 input method that drives a virtual Xbox 360 controller via ViGEm.
  • Expose the Gamepad input method in CLI configuration parsing and language bindings for Node.js and Python.
  • Add bundled ViGEm client header to support virtual gamepad integration.

Documentation:

  • Document the new Gamepad control method in the English Win32 control methods guide, including its requirements and characteristics.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 11, 2025

Reviewer's Guide

新增一个 Win32 输入方法,通过 ViGEm 模拟虚拟 Xbox 360 手柄,并将其串联到 C++ 控制单元、语言绑定和文档中,同时将 ViGEm 客户端头文件以 vendoring 方式引入,以便在运行时动态使用。

通过 ViGEm 初始化 GamepadInput 的序列图

sequenceDiagram
    participant Win32ControlUnitMgr
    participant GamepadInput
    participant Kernel as ViGEmClientDLL

    Win32ControlUnitMgr->>GamepadInput: constructor()
    activate GamepadInput
    GamepadInput->>GamepadInput: load_vigem()
    activate GamepadInput
    GamepadInput->>Kernel: LoadLibraryW(ViGEmClient.dll)
    Kernel-->>GamepadInput: HMODULE
    GamepadInput->>Kernel: GetProcAddress(vigem_alloc ... vigem_target_x360_update)
    Kernel-->>GamepadInput: function_pointers
    GamepadInput-->>GamepadInput: load_vigem() success?
    deactivate GamepadInput
    alt ViGEm_loaded
        GamepadInput->>GamepadInput: init_gamepad()
        activate GamepadInput
        GamepadInput->>Kernel: fn_alloc_()
        Kernel-->>GamepadInput: PVIGEM_CLIENT client_
        GamepadInput->>Kernel: fn_connect_(client_)
        Kernel-->>GamepadInput: VIGEM_ERROR
        GamepadInput->>Kernel: fn_target_x360_alloc_()
        Kernel-->>GamepadInput: PVIGEM_TARGET pad_
        GamepadInput->>Kernel: fn_target_add_(client_, pad_)
        Kernel-->>GamepadInput: VIGEM_ERROR
        GamepadInput-->>GamepadInput: XUSB_REPORT_INIT(report_)
        GamepadInput-->>Win32ControlUnitMgr: inited_ = true
        deactivate GamepadInput
    else load_failed
        GamepadInput-->>Win32ControlUnitMgr: inited_ = false
    end
    deactivate GamepadInput
Loading

新的 GamepadInput Win32 输入方法的类图

classDiagram
    class InputBase {
        <<abstract>>
        +MaaControllerFeature get_features()
        +bool click(int x, int y)
        +bool swipe(int x1, int y1, int x2, int y2, int duration)
        +bool touch_down(int contact, int x, int y, int pressure)
        +bool touch_move(int contact, int x, int y, int pressure)
        +bool touch_up(int contact)
        +bool click_key(int key)
        +bool input_text(const std::string& text)
        +bool key_down(int key)
        +bool key_up(int key)
        +bool scroll(int dx, int dy)
    }

    class GamepadInput {
        +GamepadInput()
        +~GamepadInput()
        +MaaControllerFeature get_features() const
        +bool click(int x, int y)
        +bool swipe(int x1, int y1, int x2, int y2, int duration)
        +bool touch_down(int contact, int x, int y, int pressure)
        +bool touch_move(int contact, int x, int y, int pressure)
        +bool touch_up(int contact)
        +bool click_key(int key)
        +bool input_text(const std::string& text)
        +bool key_down(int key)
        +bool key_up(int key)
        +bool scroll(int dx, int dy)
        +bool set_button(WORD button, bool pressed)
        +bool set_left_stick(SHORT x, SHORT y)
        +bool set_right_stick(SHORT x, SHORT y)
        +bool set_left_trigger(BYTE value)
        +bool set_right_trigger(BYTE value)
        -bool load_vigem()
        -void unload_vigem()
        -bool init_gamepad()
        -void uninit_gamepad()
        -bool send_state()
        -HMODULE vigem_module_
        -PVIGEM_CLIENT client_
        -PVIGEM_TARGET pad_
        -XUSB_REPORT report_
        -bool inited_
        -PFN_vigem_alloc fn_alloc_
        -PFN_vigem_free fn_free_
        -PFN_vigem_connect fn_connect_
        -PFN_vigem_disconnect fn_disconnect_
        -PFN_vigem_target_x360_alloc fn_target_x360_alloc_
        -PFN_vigem_target_free fn_target_free_
        -PFN_vigem_target_add fn_target_add_
        -PFN_vigem_target_remove fn_target_remove_
        -PFN_vigem_target_x360_update fn_target_x360_update_
    }

    class ViGEmClientDLL {
        +PVIGEM_CLIENT vigem_alloc()
        +void vigem_free(PVIGEM_CLIENT vigem)
        +VIGEM_ERROR vigem_connect(PVIGEM_CLIENT vigem)
        +void vigem_disconnect(PVIGEM_CLIENT vigem)
        +PVIGEM_TARGET vigem_target_x360_alloc()
        +void vigem_target_free(PVIGEM_TARGET target)
        +VIGEM_ERROR vigem_target_add(PVIGEM_CLIENT vigem, PVIGEM_TARGET target)
        +VIGEM_ERROR vigem_target_remove(PVIGEM_CLIENT vigem, PVIGEM_TARGET target)
        +VIGEM_ERROR vigem_target_x360_update(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, XUSB_REPORT report)
    }

    class XUSB_REPORT {
        +USHORT wButtons
        +BYTE bLeftTrigger
        +BYTE bRightTrigger
        +SHORT sThumbLX
        +SHORT sThumbLY
        +SHORT sThumbRX
        +SHORT sThumbRY
    }

    InputBase <|-- GamepadInput
    GamepadInput ..> ViGEmClientDLL : dynamic_load
    GamepadInput --> XUSB_REPORT : uses
Loading

文件级变更

Change Details Files
引入基于 Gamepad 的 Win32 输入方法,并将其接入 Win32 控制单元管理器。
  • 在 Win32 输入方法定义中添加 MaaWin32InputMethod_Gamepad 位标志。
  • 更新 Win32 控制单元管理器工厂,在选择 Gamepad 方法时构造 GamepadInput 实例。
  • 扩展 CLI 配置解析器,接受字符串 "Gamepad" 并将其映射到新的输入方法标志。
include/MaaFramework/MaaDef.h
source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.cpp
source/MaaPiCli/Impl/Configurator.cpp
通过 Node.js 与 Python 绑定暴露新的 Gamepad 输入方法,并更新控制方法文档。
  • 扩展 Node.js TypeScript 常量定义和原生常量加载器以包含 Gamepad 方法。
  • 在 Python 的 MaaWin32InputMethodEnum 中新增 Gamepad 枚举值。
  • 在英文版 Win32 控制方法指南中记录 Gamepad 控制方法,并注明其模拟 Xbox 360 控制器且需要安装 ViGEmBus 驱动。
  • 更新中文控制方法文档和接口 schema 以反映新的 Gamepad 方法(schema 和中文文档的具体内容在 diff 中未完全展示)。
source/binding/NodeJS/src/apis/constant.d.ts
source/binding/NodeJS/src/apis/constant.cpp
source/binding/Python/maa/define.py
docs/en_us/2.4-ControlMethods.md
docs/zh_cn/2.4-控制方法说明.md
tools/interface.schema.json
使用 ViGEm 实现 GamepadInput,以驱动虚拟 Xbox 360 控制器,并在运行时动态加载 ViGEmClient。
  • 添加从 InputBase 派生的 GamepadInput 新类,该类报告键盘风格的特性,并对不支持的指针/触摸/文本/滚动操作进行拒绝且输出日志。
  • 在运行时动态加载 ViGEmClient.dll,解析所需的 ViGEm API 函数指针,并在加载或符号解析失败时记录错误日志。
  • 创建并连接 ViGEm 客户端,分配并添加虚拟 Xbox 360 目标,初始化一个 XUSB_REPORT,并在析构时干净地移除/断开/释放所有资源。
  • 在 GamepadInput 中实现按钮、摇杆和扳机的 setter,这些接口会更新 XUSB 报告并通过 vigem_target_x360_update 推送新状态,同时包含初始化检查与错误日志。
  • 新增内置的 ViGEm Client.h 头文件,描述 GamepadInput 使用到的公共 ViGEm API 类型、常量和函数指针 typedef。
source/MaaWin32ControlUnit/Input/GamepadInput.h
source/MaaWin32ControlUnit/Input/GamepadInput.cpp
3rdparty/include/ViGEm/Client.h

Tips and commands

Interacting with Sourcery

  • 触发新的代码审查: 在 pull request 上评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub Issue: 通过回复审查评论来请求 Sourcery 从该评论创建 issue。你也可以回复审查评论 @sourcery-ai issue 来从中创建 issue。
  • 生成 pull request 标题: 在 pull request 标题中的任意位置写入 @sourcery-ai 即可随时生成标题。你也可以在 pull request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request body 中任意位置写入 @sourcery-ai summary,即可在该位置生成 PR 摘要。你也可以在 pull request 中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成审查者指南: 在 pull request 上评论 @sourcery-ai guide,可随时(重新)生成审查者指南。
  • 一次性解决所有 Sourcery 评论: 在 pull request 上评论 @sourcery-ai resolve,即可将所有 Sourcery 评论标记为已解决。如果你已经处理完所有评论且不想再看到它们,这会很有用。
  • 撤销所有 Sourcery 审查: 在 pull request 上评论 @sourcery-ai dismiss,即可撤销所有现有的 Sourcery 审查。若你希望从一次全新的审查开始,尤其有用——别忘了随后评论 @sourcery-ai review 以触发新的审查!

Customizing Your Experience

访问你的 dashboard 以:

  • 启用或禁用诸如 Sourcery 自动生成的 PR 摘要、审查者指南等审查功能。
  • 更改审查语言。
  • 添加、移除或编辑自定义审查指令。
  • 调整其他审查相关设置。

Getting Help

Original review guide in English

Reviewer's Guide

Adds a new Win32 input method that simulates a virtual Xbox 360 gamepad via ViGEm, wiring it through the C++ control unit, language bindings, and documentation, and vendoring the ViGEm client header for dynamic use at runtime.

Sequence diagram for GamepadInput initialization via ViGEm

sequenceDiagram
    participant Win32ControlUnitMgr
    participant GamepadInput
    participant Kernel as ViGEmClientDLL

    Win32ControlUnitMgr->>GamepadInput: constructor()
    activate GamepadInput
    GamepadInput->>GamepadInput: load_vigem()
    activate GamepadInput
    GamepadInput->>Kernel: LoadLibraryW(ViGEmClient.dll)
    Kernel-->>GamepadInput: HMODULE
    GamepadInput->>Kernel: GetProcAddress(vigem_alloc ... vigem_target_x360_update)
    Kernel-->>GamepadInput: function_pointers
    GamepadInput-->>GamepadInput: load_vigem() success?
    deactivate GamepadInput
    alt ViGEm_loaded
        GamepadInput->>GamepadInput: init_gamepad()
        activate GamepadInput
        GamepadInput->>Kernel: fn_alloc_()
        Kernel-->>GamepadInput: PVIGEM_CLIENT client_
        GamepadInput->>Kernel: fn_connect_(client_)
        Kernel-->>GamepadInput: VIGEM_ERROR
        GamepadInput->>Kernel: fn_target_x360_alloc_()
        Kernel-->>GamepadInput: PVIGEM_TARGET pad_
        GamepadInput->>Kernel: fn_target_add_(client_, pad_)
        Kernel-->>GamepadInput: VIGEM_ERROR
        GamepadInput-->>GamepadInput: XUSB_REPORT_INIT(report_)
        GamepadInput-->>Win32ControlUnitMgr: inited_ = true
        deactivate GamepadInput
    else load_failed
        GamepadInput-->>Win32ControlUnitMgr: inited_ = false
    end
    deactivate GamepadInput
Loading

Class diagram for new GamepadInput Win32 input method

classDiagram
    class InputBase {
        <<abstract>>
        +MaaControllerFeature get_features()
        +bool click(int x, int y)
        +bool swipe(int x1, int y1, int x2, int y2, int duration)
        +bool touch_down(int contact, int x, int y, int pressure)
        +bool touch_move(int contact, int x, int y, int pressure)
        +bool touch_up(int contact)
        +bool click_key(int key)
        +bool input_text(const std::string& text)
        +bool key_down(int key)
        +bool key_up(int key)
        +bool scroll(int dx, int dy)
    }

    class GamepadInput {
        +GamepadInput()
        +~GamepadInput()
        +MaaControllerFeature get_features() const
        +bool click(int x, int y)
        +bool swipe(int x1, int y1, int x2, int y2, int duration)
        +bool touch_down(int contact, int x, int y, int pressure)
        +bool touch_move(int contact, int x, int y, int pressure)
        +bool touch_up(int contact)
        +bool click_key(int key)
        +bool input_text(const std::string& text)
        +bool key_down(int key)
        +bool key_up(int key)
        +bool scroll(int dx, int dy)
        +bool set_button(WORD button, bool pressed)
        +bool set_left_stick(SHORT x, SHORT y)
        +bool set_right_stick(SHORT x, SHORT y)
        +bool set_left_trigger(BYTE value)
        +bool set_right_trigger(BYTE value)
        -bool load_vigem()
        -void unload_vigem()
        -bool init_gamepad()
        -void uninit_gamepad()
        -bool send_state()
        -HMODULE vigem_module_
        -PVIGEM_CLIENT client_
        -PVIGEM_TARGET pad_
        -XUSB_REPORT report_
        -bool inited_
        -PFN_vigem_alloc fn_alloc_
        -PFN_vigem_free fn_free_
        -PFN_vigem_connect fn_connect_
        -PFN_vigem_disconnect fn_disconnect_
        -PFN_vigem_target_x360_alloc fn_target_x360_alloc_
        -PFN_vigem_target_free fn_target_free_
        -PFN_vigem_target_add fn_target_add_
        -PFN_vigem_target_remove fn_target_remove_
        -PFN_vigem_target_x360_update fn_target_x360_update_
    }

    class ViGEmClientDLL {
        +PVIGEM_CLIENT vigem_alloc()
        +void vigem_free(PVIGEM_CLIENT vigem)
        +VIGEM_ERROR vigem_connect(PVIGEM_CLIENT vigem)
        +void vigem_disconnect(PVIGEM_CLIENT vigem)
        +PVIGEM_TARGET vigem_target_x360_alloc()
        +void vigem_target_free(PVIGEM_TARGET target)
        +VIGEM_ERROR vigem_target_add(PVIGEM_CLIENT vigem, PVIGEM_TARGET target)
        +VIGEM_ERROR vigem_target_remove(PVIGEM_CLIENT vigem, PVIGEM_TARGET target)
        +VIGEM_ERROR vigem_target_x360_update(PVIGEM_CLIENT vigem, PVIGEM_TARGET target, XUSB_REPORT report)
    }

    class XUSB_REPORT {
        +USHORT wButtons
        +BYTE bLeftTrigger
        +BYTE bRightTrigger
        +SHORT sThumbLX
        +SHORT sThumbLY
        +SHORT sThumbRX
        +SHORT sThumbRY
    }

    InputBase <|-- GamepadInput
    GamepadInput ..> ViGEmClientDLL : dynamic_load
    GamepadInput --> XUSB_REPORT : uses
Loading

File-Level Changes

Change Details Files
Introduce a Gamepad-based Win32 input method and wire it into the Win32 control unit manager.
  • Add MaaWin32InputMethod_Gamepad bit flag to the Win32 input method definitions.
  • Update the Win32 control unit manager factory to construct a GamepadInput instance when the Gamepad method is selected.
  • Extend the CLI configuration parser to accept the string "Gamepad" and map it to the new input method flag.
include/MaaFramework/MaaDef.h
source/MaaWin32ControlUnit/Manager/Win32ControlUnitMgr.cpp
source/MaaPiCli/Impl/Configurator.cpp
Expose the new Gamepad input method through Node.js and Python bindings and update control-method documentation.
  • Extend the Node.js TypeScript constant definitions and native constant loader to include the Gamepad method.
  • Extend the Python MaaWin32InputMethodEnum with a Gamepad value.
  • Document the Gamepad control method in the English Win32 control-methods guide, including a note that it simulates an Xbox 360 controller and requires the ViGEmBus driver.
  • Update the Chinese control-method documentation and interface schema to reflect the new Gamepad method (schema and zh docs content not fully shown in diff).
source/binding/NodeJS/src/apis/constant.d.ts
source/binding/NodeJS/src/apis/constant.cpp
source/binding/Python/maa/define.py
docs/en_us/2.4-ControlMethods.md
docs/zh_cn/2.4-控制方法说明.md
tools/interface.schema.json
Implement GamepadInput using ViGEm to drive a virtual Xbox 360 controller, with dynamic loading of ViGEmClient.
  • Add a new GamepadInput class derived from InputBase that reports keyboard-style features and rejects unsupported pointer/touch/text/scroll operations with logging.
  • Dynamically load ViGEmClient.dll at runtime, resolve required ViGEm API function pointers, and log errors if loading or symbol resolution fails.
  • Create and connect a ViGEm client, allocate and add a virtual Xbox 360 target, initialize an XUSB_REPORT, and cleanly remove/disconnect/free all resources on destruction.
  • Implement button, stick, and trigger setters on GamepadInput that update the XUSB report and push the new state using vigem_target_x360_update, with initialization checks and error logging.
  • Add a vendored ViGEm Client.h header describing the public ViGEm API types, constants, and function pointer typedefs used by GamepadInput.
source/MaaWin32ControlUnit/Input/GamepadInput.h
source/MaaWin32ControlUnit/Input/GamepadInput.cpp
3rdparty/include/ViGEm/Client.h

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants