feat(profiles): add solo Joy-Con layouts and digital stick mappings
Add per-profile native solo routing, stick/click swapping, SL/SR output mappings, and digital left-stick directions with analog priority. Extend both codecs to schema 11 while preserving legacy profiles, expose the controls and preview in Studio, and carry rail outputs through Pro emulation. Verified with 541 tests, firmware builds, editor checks, and saved-profile preservation during native 0.89 deployment.
This commit is contained in:
parent
d424fe0f4a
commit
d15b0ec711
31 changed files with 2803 additions and 183 deletions
|
|
@ -1,6 +1,9 @@
|
|||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from dataclasses import replace
|
||||
|
||||
from switch_pico_bridge import config_manager
|
||||
|
||||
|
||||
def test_controller_profile_native(tmp_path: Path) -> None:
|
||||
|
|
@ -28,3 +31,83 @@ def test_controller_profile_native(tmp_path: Path) -> None:
|
|||
cwd=root,
|
||||
)
|
||||
subprocess.run([str(executable)], check=True, cwd=root)
|
||||
|
||||
legacy = subprocess.run(
|
||||
[str(executable), "--legacy9"], check=True, cwd=root, capture_output=True
|
||||
).stdout
|
||||
migrated = config_manager.ControllerProfile.from_bytes(legacy)
|
||||
assert migrated.to_bytes()[2:] == legacy[2:]
|
||||
assert migrated.native_joycon_layout == 0
|
||||
assert migrated.swap_sticks is False
|
||||
assert migrated.swing.macro == 0
|
||||
assert migrated.nunchuk_swing.button == 15
|
||||
assert migrated.combined_swing.macro == 3
|
||||
upgraded = subprocess.run(
|
||||
[str(executable), "--codec"],
|
||||
input=legacy, check=True, cwd=root, capture_output=True,
|
||||
).stdout
|
||||
assert upgraded == migrated.to_bytes()
|
||||
|
||||
legacy10 = subprocess.run(
|
||||
[str(executable), "--legacy10"], check=True, cwd=root, capture_output=True
|
||||
).stdout
|
||||
migrated10 = config_manager.ControllerProfile.from_bytes(legacy10)
|
||||
assert legacy10[:4] == bytes((10, 0, 128, 1))
|
||||
assert migrated10.native_joycon_layout == 2
|
||||
assert migrated10.swap_sticks is True
|
||||
assert migrated10.button_map[0] == 18
|
||||
assert migrated10.extra_button_map[0] == 19
|
||||
assert migrated10.shift.button_map[0] == 20
|
||||
assert migrated10.shift.extra_button_map[0] == 21
|
||||
assert migrated10.left_trigger.output == migrated10.right_trigger.output == 21
|
||||
assert migrated10.to_bytes()[2:] == legacy10[2:]
|
||||
upgraded10 = subprocess.run(
|
||||
[str(executable), "--codec"],
|
||||
input=legacy10, check=True, cwd=root, capture_output=True,
|
||||
).stdout
|
||||
assert upgraded10 == migrated10.to_bytes()
|
||||
|
||||
directions = replace(
|
||||
migrated10,
|
||||
button_map=(*migrated10.button_map[:12], 22, 23, 24, 25),
|
||||
extra_button_map=(24, *migrated10.extra_button_map[1:]),
|
||||
shift=replace(
|
||||
migrated10.shift,
|
||||
button_map=(23, *migrated10.shift.button_map[1:]),
|
||||
extra_button_map=(25, *migrated10.shift.extra_button_map[1:]),
|
||||
),
|
||||
left_trigger=replace(migrated10.left_trigger, output=22),
|
||||
right_trigger=replace(migrated10.right_trigger, output=22),
|
||||
)
|
||||
direction_wire = directions.to_bytes()
|
||||
native_directions = subprocess.run(
|
||||
[str(executable), "--codec"],
|
||||
input=direction_wire, check=True, cwd=root, capture_output=True,
|
||||
).stdout
|
||||
assert native_directions == direction_wire
|
||||
assert config_manager.ControllerProfile.from_bytes(native_directions) == directions
|
||||
assert config_manager.ControllerProfile.from_json(directions.to_json()) == directions
|
||||
|
||||
for layout in range(len(config_manager.NATIVE_JOYCON_LAYOUTS)):
|
||||
for swap in (False, True):
|
||||
profile = replace(
|
||||
migrated,
|
||||
native_joycon_layout=layout,
|
||||
swap_sticks=swap,
|
||||
button_map=(18, *migrated.button_map[1:]),
|
||||
extra_button_map=(19, *migrated.extra_button_map[1:]),
|
||||
shift=replace(
|
||||
migrated.shift,
|
||||
button_map=(20, *migrated.shift.button_map[1:]),
|
||||
extra_button_map=(21, *migrated.shift.extra_button_map[1:]),
|
||||
),
|
||||
left_trigger=replace(migrated.left_trigger, output=21),
|
||||
right_trigger=replace(migrated.right_trigger, output=21),
|
||||
)
|
||||
encoded = profile.to_bytes()
|
||||
native = subprocess.run(
|
||||
[str(executable), "--codec"],
|
||||
input=encoded, check=True, cwd=root, capture_output=True,
|
||||
).stdout
|
||||
assert native == encoded
|
||||
assert config_manager.ControllerProfile.from_bytes(native) == profile
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue