Files
BT411/docs/MOUSELOOK_PLAN.md
T
CydandClaude Opus 5 9d536294e4 Mouse buttons are bindable; mouse LOOK scoped (not built)
BUTTONS (shipped).  Win32 hands mouse buttons out as virtual keys, and the
binding path already stores VKs and polls GetAsyncKeyState -- so this needed no
verb, no parser change and no new machinery, just names:

    key MOUSE4 button 0x40        # side buttons
    key MOUSE5 button 0x46
    key MOUSEMIDDLE button 0x41

MOUSELEFT/MOUSERIGHT are named too, with a warning in the file header and the
docs: they are how the player presses cockpit buttons (left = press, right =
latch), and the poll is focus-guarded but not click-aware, so binding either
ALSO fires on every panel click.  The side and middle buttons are the free
ones.  Axes work as well (`key MOUSE4 axis Throttle slew + 0.7`).

One guard: the RGB lamp mirror skips mouse VKs when building its map -- a
keyboard lamp array has no mouse buttons to paint (BTPadBindingIsMouseKey).

Verified live: a bindings.txt carrying two mouse rows loads 76 keys (74 + 2),
and a real injected XBUTTON1 press produced `[emitter] FIRED #1`.  Clean A/B --
the earlier run whose SendInput failed the struct-size check logged no fire at
all.  Shipped commented-out examples in the default profile so the capability
is discoverable.

LOOK (scoped only).  docs/MOUSELOOK_PLAN.md.  Mouse MOVEMENT is a real feature,
not a table entry, and the hard part is not reading the device:

 - The cursor is already spoken for.  The glass cockpit's premise is that all
   72 buttons are mouse targets; mouse-look wants a captured, hidden, recentred
   cursor.  Both cannot be true, so this is a MODE question first -- four
   models compared, recommending hold-to-look (costs nothing when unbound,
   cannot strand a player, behaves the same in surround and exploded layouts).
 - The channels are POSITIONAL (JoystickX/Y are -1..1 deflections the mapper
   reads per control mode); a mouse gives deltas.  Accumulate-into-a-virtual-
   stick reuses every existing rule; a rate model would need new mapper
   semantics.
 - Control mode changes what it MEANS: BASIC steers with the stick, MID/ADV
   twist the torso -- so mouse-look steers in one and aims in the other.

Proposed grammar (new row type, so old builds skip it with a warning),
where the code goes, ~250 lines, and a verification plan whose load-bearing
item is "panel clicks still work when a mouselook binding exists but is not
engaged".  Also flagged: the pod had NO mouse, so nothing here is
reconstruction -- every choice is design, judged on feel, and it must stay out
of the pod build's path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 09:06:58 -05:00

131 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MOUSELOOK_PLAN — scope: mouse movement as a cockpit axis
**Status: SCOPED, NOT IMPLEMENTED.** Written 2026-07-26 at the author's request, alongside the
mouse-BUTTON support that did ship (4.11.565). Read §2 before agreeing to build it — the hard
part is not reading the mouse.
---
## 1. What shipped, and what this is instead
**Shipped:** mouse *buttons*, as key names (`MOUSE4`, `MOUSE5`, `MOUSEMIDDLE`, `MOUSELEFT`,
`MOUSERIGHT`). Zero new machinery — Win32 hands mouse buttons out as virtual keys and the binding
path already stores VKs and polls `GetAsyncKeyState`, so five table entries were the whole change.
**This document:** mouse *movement* driving `JoystickX`/`JoystickY` (torso twist and aim) — the
thing a modern player means by "mouse look". That is a real feature, not a table entry, for three
reasons that have nothing to do with reading the device.
## 2. The three real problems
### 2.1 The cursor is already spoken for ⚠ (the blocking one)
The glass cockpit's whole premise is that **every one of the 72 pod buttons is a mouse target**
left-click presses, right-click latches, and under the exploded layout there are seven separate
windows to click in. Mouse-look wants the opposite: a captured, hidden, recentred cursor that
never touches a button.
These cannot both be true at once, so the feature is really a **mode question**, and the answer
decides the whole design:
| Model | Feel | Cost |
|---|---|---|
| **A. Hold-to-look** (`key MOUSE5 mouselook` or a modifier) | Cursor stays free; press to steer, release to click buttons | No mode confusion, discoverable, but you cannot look and hold a trigger comfortably |
| **B. Toggle** (a key flips captured/free) | Full mouse-look while engaged | Needs a visible on-screen indicator or players get stuck "unable to click anything" |
| **C. Region** (look while the pointer is over the 3D view, click when over a display) | No mode at all | Fails in the exploded layout (displays are separate windows) and near the surround's corner MFDs, which overlap the view by design |
| **D. Always captured**, panel clicks via a "release" key | Cleanest for a shooter | Throws away the cockpit's defining interaction; **not recommended** |
**Recommendation: A, with B as an option.** A costs nothing when unbound and cannot strand a
player. It is also the only one that behaves identically in the surround and exploded layouts.
### 2.2 The pod's channels are POSITIONAL; a mouse is not
`JoystickX`/`JoystickY` are absolute stick deflections in 1..1 that `MechControlsMapper`
interprets per control mode. A mouse produces *deltas*. Bridging that is a design choice, not a
conversion:
- **Accumulate** (recommended): integrate deltas into the channel, clamp to ±1 — a "virtual
stick". Reuses every existing rule (composition, the #36 release edge, the gait detent).
- **Rate**: treat the delta as a velocity of torso angle. Feels better for aiming, but the mapper
has no rate input — it would mean a new channel semantic and a new path through the mapper.
Bigger and less authentic.
With Accumulate, the stick does not spring back (a mouse has no centre). Options, all cheap:
a `spring <rate>` trailing option that decays toward 0, and/or a recentre key (0x42 torso centre
is already bound to the Up arrow).
### 2.3 Control mode changes what it means
BASIC steers with the stick; MID/ADV twist the torso with it and steer with the pedals
([[experience-levels]], [[pod-hardware]]). So mouse-look **steers the mech in BASIC and aims the
torso in MID/ADV** — authentic, but it will read as a bug to anyone who hasn't been told. The
docs must say so, and the feature is most useful in MID/ADV.
## 3. Proposed shape (if we build it)
New row type — the sanctioned way to extend the grammar (old builds skip unknown rows with a
logged warning, so a player's file stays forward-compatible):
```
mouseaxis <X|Y> axis <channel> [invert] [sensitivity <n>] [spring <rate>] [deadzone <f>]
key <KEY> mouselook # hold-to-look (model A)
```
Example default (shipped commented out):
```
#mouseaxis X axis JoystickX sensitivity 1.0 spring 0
#mouseaxis Y axis JoystickY sensitivity 1.0 spring 0 invert
#key MOUSE5 mouselook
```
### Where the code goes
| Piece | Where | Notes |
|---|---|---|
| Raw delta capture | `L4PADRIO` (new), fed from the window proc | **`WM_INPUT` (RawInput)**, not `WM_MOUSEMOVE`: relative motion, no cursor clamping at screen edges, no pointer acceleration. Register `HID_USAGE_GENERIC_MOUSE` with `RIDEV_INPUTSINK` off (foreground only). |
| Capture/hide | same | `SetCapture` + `ShowCursor(FALSE)` + recentre per frame while engaged; release on focus loss |
| Bindings | `L4PADBINDINGS` | `mouseAxisBindings[]` + the `mouselook` action, parallel to `padAxisBindings` |
| Channel write | `PadRIO::Poll` | Beside the pad/joy axis writes, with the SAME per-binding previous-value array so it inherits the #36 release edge and the #24 disconnect rule |
| Docs | `bindings.txt` header, `docs/CONTROLS.md`, `docs/CONTROLS.html` | including the control-mode caveat |
Estimated size: ~250 lines plus docs. No engine or reconstruction changes — this is entirely in
the glass desktop layer, like PadRIO itself.
## 4. Authenticity note
**The pod had no mouse.** There is nothing to reconstruct here and no binary behaviour to be
faithful to — this is a desktop-convenience layer, exactly like PadRIO and the glass cockpit
itself. That is fine (the layer exists precisely so developers and players can fly without a
cabinet), but it means every decision above is a *design* decision and should be judged on feel,
not fidelity. It also means it must stay out of the pod build's path: gate it the way PadRIO is
gated, so `BT_PLATFORM=pod` never sees it.
## 5. Verification plan
1. `mouseaxis` rows parse; unknown-option rows warn and skip (grammar-compatibility rule).
2. Hold-to-look engages/releases; cursor visible again on release AND on focus loss (the #24
disconnect rule, mouse edition).
3. Channel values track motion, clamp at ±1, and release cleanly to 0 (the #36 latch bug is
exactly the hazard here).
4. **Panel clicks still work** while a mouselook binding exists but is not engaged — in BOTH the
surround and exploded layouts. This is the regression that matters.
5. Control-mode sweep: BASIC steers, MID/ADV twists — confirmed against `[mppr]` trace.
6. Pod + dev profiles: no mouse path constructed at all.
## 6. Open questions
1. Model A or B (§2.1)? Everything else follows from it.
2. Should mouse-look imply a crosshair/reticle change, so the player can see it is engaged?
3. Does the exploded layout need its own answer, given the seven windows each have their own
client area and the main window may not have focus?
4. Is this wanted for the tester builds at all, or only for the operator/dev seat? It is not
pod-authentic, and the cockpit's mouse-click identity is a feature people have praised.
## Key Relationships
- Extends: [[glass-cockpit]] (PadRIO, the desktop input layer) · Constrained by: [[pod-hardware]]
(the RIO channel model), [[experience-levels]] (control modes)
- Prior art in-tree: `L4JOY` (DirectInput layer + the wizard) is the closest analogue for adding
a whole new input device cleanly.