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>
131 lines
7.1 KiB
Markdown
131 lines
7.1 KiB
Markdown
# 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.
|