fix(input): Phase K live-test fixes pt3 — fly→chase round-trip, Shift coexists, run-speed for backward + strafe
Four issues from the K-fix2 launch (2026-04-26 user report): 1. Can't return from free-fly to player view. CameraController.ToggleFly only swaps Fly↔Orbit, so a user who flew out of player mode landed in orbit (Holtburg) on toggle-back instead of the chase camera. Added ToggleFlyOrChase() helper that prefers Fly→Chase / Chase→Fly when _playerMode is true and a chase camera is available; falls back to the original Fly↔Orbit toggle for offline / pre-login flows. Wired into all three free-fly entry points: keyboard shortcut (Ctrl+Shift+F), Camera menu item, and DebugPanel button. 2. Shift while moving STOPS instead of dropping to walk. Root cause: InputDispatcher.IsChordHeld required _keyboard.CurrentModifiers to match chord.Modifiers EXACTLY. So with W bound as (W, None), holding W and then pressing Shift made CurrentModifiers=Shift mismatch chord (None) → IsActionHeld(MovementForward) returned false → Forward flag dropped → player stopped. Fixed by relaxing IsChordHeld: when chord.Modifiers is None, Shift is allowed to coexist (it's the retail walk-modifier). Other modifiers (Ctrl, Alt, Win) still mismatch strictly so Ctrl+W stays a distinct chord from W. +2 tests pinning the new permissive-Shift / strict-Ctrl semantics. 3. Backwards too slow when running. forwardCmdSpeed for the WalkBackward branch was hardcoded to 1.0; localY was hardcoded to -(WalkAnimSpeed * 0.65). Neither honored input.Run. With Run=true (default), backward now scales by runRate (~2.4×) so X = "run backwards" matches the forward run pace × the 0.65 backward animation cycle ratio. 4. Strafe too slow when running. localX for SideStepLeft / SideStepRight was hardcoded to ±SidestepAnimSpeed regardless of Run. Same fix: when Run is held, scale by runRate so strafe at default speed matches the run-forward pace. Tests: 1220 → 1222 (the two new IsChordHeld tests). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6481169cb9
commit
785dd92378
4 changed files with 130 additions and 28 deletions
|
|
@ -142,8 +142,18 @@ public sealed class InputDispatcher
|
|||
|
||||
/// <summary>True iff the given chord's primary key is currently down on
|
||||
/// the appropriate device AND the keyboard's current modifier mask
|
||||
/// equals the chord's required modifier mask exactly. Modifiers must
|
||||
/// match precisely — Ctrl+A held does NOT count Shift+Ctrl+A as held.</summary>
|
||||
/// matches the chord's required modifier mask. Match semantics:
|
||||
/// <list type="bullet">
|
||||
/// <item>If <see cref="KeyChord.Modifiers"/> is <see cref="ModifierMask.None"/>,
|
||||
/// any Shift state is allowed — Shift is the retail walk-modifier and
|
||||
/// must coexist with movement chords (W held + Shift pressed = run
|
||||
/// gracefully drops to walk, not "stop"). Other modifiers
|
||||
/// (Ctrl, Alt, Win) still mismatch strictly so Ctrl+W stays a
|
||||
/// distinct chord.</item>
|
||||
/// <item>If <see cref="KeyChord.Modifiers"/> includes any non-Shift
|
||||
/// modifier (or includes Shift explicitly), the match is exact —
|
||||
/// Ctrl+A held does NOT count Shift+Ctrl+A as held.</item>
|
||||
/// </list></summary>
|
||||
private bool IsChordHeld(KeyChord chord)
|
||||
{
|
||||
if (chord.Device == 0)
|
||||
|
|
@ -160,7 +170,14 @@ public sealed class InputDispatcher
|
|||
// Unknown device — never held.
|
||||
return false;
|
||||
}
|
||||
return _keyboard.CurrentModifiers == chord.Modifiers;
|
||||
var current = _keyboard.CurrentModifiers;
|
||||
if (chord.Modifiers == ModifierMask.None)
|
||||
{
|
||||
// K-fix3 (2026-04-26): permissive Shift handling for bare-key
|
||||
// chords. See the XML doc above for rationale.
|
||||
current &= ~ModifierMask.Shift;
|
||||
}
|
||||
return current == chord.Modifiers;
|
||||
}
|
||||
|
||||
/// <summary>Inverse of <see cref="MouseButtonToKey"/>: decode a chord
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue