Commit Graph

3 Commits

Author SHA1 Message Date
c4c9dd7e50 forza-trigger: patch dualsense-controller for vibration freq propagation
All checks were successful
Build and Deploy / mreow (push) Successful in 1m6s
Build and Deploy / yarn (push) Successful in 1m7s
Build and Deploy / muffin (push) Successful in 1m6s
Live strace on yarn during gameplay revealed the daemon was correctly
calling effect.vibration(freq=35) on slip events, but the OUT report
on the wire showed mode=0x26 (VIBRATION) with byte 31 (param9 =
frequency) = 0. The controller firmware treats freq=0 as "no
oscillation" — trigger sits silent in vibration mode. That's why the
user reported "doesn't react to slipping or anything" even after the
pedal-off early-return fix.

Root cause is in dualsense-controller 0.3.1 itself:
  - WriteStates.__init__ registers individual write-states for trigger
    effect params 1-7 only. params 8/9/10 are not registered.
  - update_out_report copies from per-state values to the OutReport,
    again only params 1-7.
  - The OutReport dataclass DEFINES params 1-10 (with defaults of 0)
    and Usb01OutReport.to_bytes writes all 10 to the wire.
  - effect.vibration() puts frequency in param9 — silently dropped.
  - Same hits effect.machine() (params 8,9,10) and effect.galloping()
    (param10). effect.feedback/weapon/bow only use params 1-7 so
    they happen to work.

Fix is a small upstream-style patch added under patches/dualsense-
controller/ and wired into the dualsense-controller derivation in
hosts/yarn/forza-trigger/python-packages.nix via the patches attr:
in update_out_report, after the param7 assignments, read param8/9/10
directly from the parent TriggerEffect state value (which already
carries them correctly from the call site through _set_value).

Verified post-patch by source-reading the installed library:
  out_report.left_trigger_effect_param9 = self.left_trigger_effect.value.param9
  out_report.right_trigger_effect_param9 = self.right_trigger_effect.value.param9
  (and 4 more for left/right param8/10)

Build-sandbox tests (54/54) pass via the forza-trigger-tests build
gate; full yarn NixOS closure builds clean.

Filing upstream against yesbotics/dualsense-controller-python is the
follow-up; until then this is a local patch.
2026-05-07 14:38:12 -04:00
6501fe2ddb forza-trigger: rewrite 2026-05-04 14:47:00 -04:00
2404792b61 game-mods: drop in-house launchOptions writer, hardcode FH5 ini
Replaces three handfuls of custom code with upstream / static data:

- Per-app Steam launch options now declared via different-name/steam-
  config-nix's `programs.steam.config.apps.<n>` instead of a custom
  ~70-line `apply_launch_options` Python function. The dropped writer
  was racy: it edited localconfig.vdf without checking for a running
  Steam, so any timer firing while Steam was open would lose its
  changes on the next Steam shutdown. steam-config-nix's `closeSteam`
  flag closes that race.

  Also moves the GE-Proton compat-tool pin to declarative config —
  one fewer manual click in Steam UI to remember.

- `mods.<>.launchOptions` option, the `launchOptionsData` aggregation,
  and `LAUNCH_OPTIONS_DATA` are removed from desktop-game-mods.nix.
  The module now does file-drops only; Steam config lives in its own
  `programs.steam.config` namespace, where it belongs.

  fh5-vkd3d-no-hvv (which existed only to set VKD3D_CONFIG) collapses
  into the FH5 launchOptions block in hosts/yarn/default.nix.

- `unitConfig.X-ConfigHash` on game-mods.service is replaced with
  `restartTriggers`. NixOS already emits `X-Restart-Triggers=<hash>`
  on the unit; the workaround was redundant. The Type=oneshot,
  RemainAfterExit=no semantics make `systemctl restart` re-run
  ExecStart cleanly on hash change.

- The awk pipeline that patched OptiScaler's stock OptiScaler.ini at
  build time is replaced with a hand-written hosts/yarn/optiscaler-
  fh5-rdna3.ini containing only the keys we override (5 of them).
  OptiScaler's Config::readString defaults missing keys to "auto"
  (Config.cpp:1568), so a minimal file is sufficient. Side benefits:
  one upstream-source dependency removed, a key-rename in upstream
  becomes a behavior change rather than a silent awk-no-match.

  Override values + sources:
    Fsr4Update=true              FH5 wiki, FSR4 Linux Setup
    DlssReactiveMaskBias=0.65    FH5 wiki, "Known Issues"
    FsrNonLinearColorSpace=true  FSR4 wiki, "Image Quality"
    EnableFsr2Inputs=false       FH5 wiki, "Known Issues"
    Dxgi=false                   FH5 wiki

- forza-trigger's three custom Python derivations (pydualsense,
  hidapi-usb, fdp) factored out of default.nix into a sibling
  python-packages.nix. Same logic, single-purpose file. Bumping a
  version is now a one-place hash roll.

- pkgs.dualsensectl removed from the daemon's environment.system-
  Packages. Single-shot writes from the CLI get clobbered by the BG
  sendReport thread within ~4ms anyway, so the tool is only useful
  with the daemon stopped — not worth the unconditional install.
  Bring it in ad-hoc with `nix-shell -p dualsensectl`.
2026-05-03 22:44:14 -04:00