Skip to content

fix: use correct VID/PID when emulate_elite is disabled#18

Merged
BANANASJIM merged 1 commit intomainfrom
fix/emulate-elite-disable
Mar 8, 2026
Merged

fix: use correct VID/PID when emulate_elite is disabled#18
BANANASJIM merged 1 commit intomainfrom
fix/emulate-elite-disable

Conversation

@BANANASJIM
Copy link
Copy Markdown
Owner

@BANANASJIM BANANASJIM commented Mar 8, 2026

Summary

  • Pass emulate_elite flag to Uinput::create() so the virtual gamepad uses standard VID/PID (0x37d7:0x2401) instead of Xbox Elite (0x045e:0x0b00) when emulate_elite = false
  • Previously, the virtual device always identified as Xbox Elite regardless of config

Changes

  • include/vader5/uinput.hpp: Add bool emulate_elite parameter to Uinput::create()
  • src/uinput.cpp: Select VID/PID based on emulate_elite flag
  • src/gamepad.cpp: Pass cfg.emulate_elite to Uinput::create()
  • src/tools/test_uinput_elite.cpp: Test suite for config parsing of emulate_elite
  • config/test-elite-{default,true,false}.toml: Test configs

Test plan

  • test-uinput-elite passes — verifies config parsing for all 3 cases (absent/true/false)
  • test-remap passes — no regressions
  • Manual: set emulate_elite = false, verify Steam no longer shows Xbox Elite

Closes #16

Summary by CodeRabbit

  • New Features

    • Added Elite mode emulation support for the virtual gamepad, enabling configuration of device identifiers. When enabled, the device reports as an Elite variant; when disabled, it reports as a standard gamepad.
  • Tests

    • Added comprehensive test coverage for Elite mode configuration, validating behavior across default, enabled, and disabled scenarios.

Pass emulate_elite flag to Uinput::create() so the virtual gamepad
uses standard VID/PID (0x37d7:0x2401) instead of Xbox Elite
(0x045e:0x0b00) when emulate_elite = false.

Closes #16
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 8, 2026

📝 Walkthrough

Walkthrough

This PR implements the ability to conditionally emulate the Xbox Elite Controller by adding an emulate_elite boolean parameter to the configuration and API. When disabled, the controller uses standard vendor/product IDs instead of Elite-specific ones, addressing the issue where disabling Elite emulation had no effect.

Changes

Cohort / File(s) Summary
Build Configuration
CMakeLists.txt
Added new test target test-uinput-elite with appropriate sources and dependencies, mirroring the existing test-remap target structure.
Test Configuration Files
config/test-elite-default.toml, config/test-elite-true.toml, config/test-elite-false.toml
Three new TOML configuration files testing emulate_elite parameter in default (absent), true, and false states.
Public API
include/vader5/uinput.hpp
Added emulate_elite boolean parameter (defaulted to true) to the Uinput::create static method signature, positioned before the name argument.
Uinput Implementation
src/uinput.cpp
Updated Uinput::create to accept emulate_elite parameter and conditionally set vendor/product IDs based on value: Elite IDs when true, standard IDs when false.
Gamepad Integration
src/gamepad.cpp
Updated call to Uinput::create to pass cfg.emulate_elite from loaded configuration.
Test Implementation
src/tools/test_uinput_elite.cpp
New test tool validating Config::load behavior for emulate_elite across three configuration file scenarios with assertion checks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

Review effort 3/5

Poem

🐰 A feature springs forth from the config file deep,
Elite or not—the choice is yours to keep!
Vendor IDs dance when the switch flips true,
With tests that check what's right and what's new,
No more ghosts of controllers in disguise! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: enabling correct VID/PID selection based on the emulate_elite flag.
Linked Issues check ✅ Passed Code changes correctly implement the fix for issue #16 by passing emulate_elite flag and conditionally setting VID/PID to standard values when disabled.
Out of Scope Changes check ✅ Passed All changes directly support the emulate_elite feature requirement; no unrelated modifications detected in code, config, or build files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/emulate-elite-disable

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/tools/test_uinput_elite.cpp (1)

17-44: This still doesn't exercise the bug-fixed path.

These checks stop at Config::load(), so a regression in src/gamepad.cpp Line 219 or src/uinput.cpp Lines 135-136 would still pass. Consider extracting VID/PID selection into a small pure helper and asserting that helper for default/true/false.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/tools/test_uinput_elite.cpp` around lines 17 - 44, The tests currently
only call Config::load() and don't exercise the VID/PID selection logic in the
gamepad/uinput code; extract the selection logic into a pure helper (e.g.,
select_elite_vid_pid or choose_elite_device) that takes the Config or the
emulate_elite flag and returns the VID/PID tuple, update gamepad.cpp/uinput.cpp
to call that helper, and modify the tests in test_uinput_elite.cpp to call the
new helper directly and assert the returned VID/PID for the default, true, and
false cases so the bug-fixed path is exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CMakeLists.txt`:
- Around line 70-77: The test binary test-uinput-elite fails when run from the
build dir because src/tools/test_uinput_elite.cpp expects fixtures at a
source-path; define a compile-time macro pointing to the repository fixture
directory and expose it to that target so the test can build paths from
VADER5_TEST_CONFIG_DIR. Add a CMake directive for the test target
(test-uinput-elite) that provides VADER5_TEST_CONFIG_DIR (e.g., via
target_compile_definitions or by configuring a header) set to the source fixture
directory containing config/test-elite-*.toml, so
src/tools/test_uinput_elite.cpp can reliably locate fixtures at runtime.

In `@include/vader5/uinput.hpp`:
- Around line 22-24: The public factory signature Uinput::create(std::span<const
std::optional<int>> ext_mappings, bool emulate_elite = true, const char* name =
"Vader 5 Pro Virtual Gamepad") is error-prone because callers like
Uinput::create(mappings, "Custom Name") will pass the string into the bool
parameter; change the API to keep the name argument before emulate_elite or add
an overload that takes (ext_mappings, const char* name) to preserve
backward-friendly usage. Update the declaration in include/vader5/uinput.hpp and
the implementation in src/uinput.cpp to use the new parameter order
(ext_mappings, const char* name, bool emulate_elite = true) or add the overload,
and then update all call sites to match the new ordering or overload to avoid
accidental boolean conversion of string literals.

---

Nitpick comments:
In `@src/tools/test_uinput_elite.cpp`:
- Around line 17-44: The tests currently only call Config::load() and don't
exercise the VID/PID selection logic in the gamepad/uinput code; extract the
selection logic into a pure helper (e.g., select_elite_vid_pid or
choose_elite_device) that takes the Config or the emulate_elite flag and returns
the VID/PID tuple, update gamepad.cpp/uinput.cpp to call that helper, and modify
the tests in test_uinput_elite.cpp to call the new helper directly and assert
the returned VID/PID for the default, true, and false cases so the bug-fixed
path is exercised.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2c867c85-5c39-4a3d-b9e3-e40206a8cd9d

📥 Commits

Reviewing files that changed from the base of the PR and between f8649eb and d5cb552.

📒 Files selected for processing (8)
  • CMakeLists.txt
  • config/test-elite-default.toml
  • config/test-elite-false.toml
  • config/test-elite-true.toml
  • include/vader5/uinput.hpp
  • src/gamepad.cpp
  • src/tools/test_uinput_elite.cpp
  • src/uinput.cpp

Comment thread CMakeLists.txt
Comment on lines +70 to +77
add_executable(test-uinput-elite
src/tools/test_uinput_elite.cpp
src/config.cpp
src/keycodes.cpp
)
set_target_properties(test-uinput-elite PROPERTIES CXX_CLANG_TIDY "")
target_include_directories(test-uinput-elite PRIVATE include)
target_link_libraries(test-uinput-elite PRIVATE tomlplusplus::tomlplusplus)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make the fixture directory explicit for test-uinput-elite.

src/tools/test_uinput_elite.cpp loads config/test-elite-*.toml with relative paths, but this target doesn't copy those files or pass the source config dir. Running the binary from the build directory will fail before any assertions.

🧪 One way to keep fixture lookup stable
 add_executable(test-uinput-elite
     src/tools/test_uinput_elite.cpp
     src/config.cpp
     src/keycodes.cpp
 )
 set_target_properties(test-uinput-elite PROPERTIES CXX_CLANG_TIDY "")
 target_include_directories(test-uinput-elite PRIVATE include)
+target_compile_definitions(test-uinput-elite PRIVATE
+    VADER5_TEST_CONFIG_DIR="${CMAKE_SOURCE_DIR}/config"
+)
 target_link_libraries(test-uinput-elite PRIVATE tomlplusplus::tomlplusplus)

Then build the paths from VADER5_TEST_CONFIG_DIR inside src/tools/test_uinput_elite.cpp.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CMakeLists.txt` around lines 70 - 77, The test binary test-uinput-elite fails
when run from the build dir because src/tools/test_uinput_elite.cpp expects
fixtures at a source-path; define a compile-time macro pointing to the
repository fixture directory and expose it to that target so the test can build
paths from VADER5_TEST_CONFIG_DIR. Add a CMake directive for the test target
(test-uinput-elite) that provides VADER5_TEST_CONFIG_DIR (e.g., via
target_compile_definitions or by configuring a header) set to the source fixture
directory containing config/test-elite-*.toml, so
src/tools/test_uinput_elite.cpp can reliably locate fixtures at runtime.

Comment thread include/vader5/uinput.hpp
Comment on lines 22 to 24
static auto create(std::span<const std::optional<int>> ext_mappings,
bool emulate_elite = true,
const char* name = "Vader 5 Pro Virtual Gamepad") -> Result<Uinput>;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# List every Uinput::create call site for manual inspection.
rg -n -C2 'Uinput::create\s*\('

Repository: BANANASJIM/flydigi-vader5

Length of output: 622


🏁 Script executed:

# Search more broadly for Uinput::create references and the implementation details
rg -n 'Uinput::create' --type cpp --type hpp

Repository: BANANASJIM/flydigi-vader5

Length of output: 96


🏁 Script executed:

# Show lines around the implementation in uinput.cpp
sed -n '60,70p' src/uinput.cpp

Repository: BANANASJIM/flydigi-vader5

Length of output: 470


🏁 Script executed:

# Search more broadly without file type specification
rg 'Uinput::create' -n

Repository: BANANASJIM/flydigi-vader5

Length of output: 247


🏁 Script executed:

# Check for any other references to Uinput in headers
rg 'Uinput' include/vader5/uinput.hpp -n | head -20

Repository: BANANASJIM/flydigi-vader5

Length of output: 486


🏁 Script executed:

# Verify no other build/test files reference Uinput::create
find . -name "*.cpp" -o -name "*.hpp" -o -name "*.h" | xargs rg -l 'Uinput' 2>/dev/null | head -20

Repository: BANANASJIM/flydigi-vader5

Length of output: 160


🏁 Script executed:

# Verify the call site in gamepad.cpp and nearby context to ensure compatibility
sed -n '215,225p' src/gamepad.cpp

Repository: BANANASJIM/flydigi-vader5

Length of output: 435


Keep the existing name slot ahead of emulate_elite or add an overload.

Line 23 makes Uinput::create(mappings, "Custom Name") silently wrong: the string converts to true, and name falls back to the default. That's an easy API trap for any future caller.

♻️ Safer signature
-    static auto create(std::span<const std::optional<int>> ext_mappings,
-                       bool emulate_elite = true,
-                       const char* name = "Vader 5 Pro Virtual Gamepad") -> Result<Uinput>;
+    static auto create(std::span<const std::optional<int>> ext_mappings,
+                       const char* name = "Vader 5 Pro Virtual Gamepad",
+                       bool emulate_elite = true) -> Result<Uinput>;

Update src/uinput.cpp and any call sites to match.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/vader5/uinput.hpp` around lines 22 - 24, The public factory signature
Uinput::create(std::span<const std::optional<int>> ext_mappings, bool
emulate_elite = true, const char* name = "Vader 5 Pro Virtual Gamepad") is
error-prone because callers like Uinput::create(mappings, "Custom Name") will
pass the string into the bool parameter; change the API to keep the name
argument before emulate_elite or add an overload that takes (ext_mappings, const
char* name) to preserve backward-friendly usage. Update the declaration in
include/vader5/uinput.hpp and the implementation in src/uinput.cpp to use the
new parameter order (ext_mappings, const char* name, bool emulate_elite = true)
or add the overload, and then update all call sites to match the new ordering or
overload to avoid accidental boolean conversion of string literals.

@BANANASJIM BANANASJIM merged commit b14dce6 into main Mar 8, 2026
5 checks passed
@BANANASJIM BANANASJIM deleted the fix/emulate-elite-disable branch March 13, 2026 21:13
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.

Disabling Emulate Elite doesn't do anything

1 participant