USBJoystick - mouse-pointer and keyboard synthesis
======================================================

How USBJoystick makes a joystick drive the RISC OS keyboard and mouse
pointer: binding a physical button or an axis direction to a keypress, and
binding axes/buttons to mouse-pointer movement and mouse buttons.

Design principle: **additive, alongside the real devices.** Synthesised
keys sit next to a real keyboard, and synthesised mouse movement nudges the
*same* desktop pointer the real mouse controls, both live at once. We do NOT
become a separate selectable pointer device (the one-device-at-a-time model
USBDriver uses via OS_Pointer) - see "Mouse movement" for why that's both
possible and preferable here.



Keyboard synthesis (c.keys)
------------------------------
Keys are injected via KeyV, the same vector a real USB keyboard drives:

    OS_CallAVector  R0 = KeyV_KeyDown (2) / KeyV_KeyUp (1)
                    R1 = RISC OS internal KeyNo (Global/Keyboard.h)
                    R9 = KEYV (&13)

To *inject* keys you only call the vector - you do NOT claim KeyV (claiming
is for being a keyboard: receiving LED/enable reasons and getting kernel
auto-repeat). A held KeyDown reads as down via the kernel's key-state table
(OS_Byte 121/129), which is what games poll, so no auto-repeat handling is
needed for held directions.

The configured codes (key_up/down/left/right, key_buttons[]) are KeyNo
values used directly as R1 - no HID-usage translation (unlike USBDriver,
whose USB keyboard must map HID usage -> KeyNo).

c.keys tracks, per slot, the actual KeyNo currently held for each source
(4 axis directions + each physical button), so it emits KeyV events only on
a change, releases the right key if a mapping changes mid-press, and can
release everything on detach/finalise (so keys never stick). Axis-direction
"pressed" uses the 8-bit mapped stick with the same digital dead-zone
thresholds as encode_stick_serial_port (c.joyswis).


Mouse buttons (c.mouse)
--------------------------
Mouse buttons are injected via KeyV as pseudo-keys (Global/Keyboard.h):
KeyNo_LeftMouse &70 (Select), KeyNo_CentreMouse &71 (Menu), KeyNo_RightMouse
&72 (Adjust) - same OS_CallAVector KEYV convention as keyboard, edge-detected
against previous state. This is the same mechanism USBDriver's mouse uses.


Mouse movement (c.mouse) 
---------------------------
The canonical way to add RELATIVE movement to the shared pointer, coexisting
with the real mouse, is PointerV reason 3 (Report), pushed via OS_CallAVector.
This is similar to USBDriver.

There is no PointerV Claim and no PointerReason_Request handler: this is a
pure push model, not a claimed selectable pointer device.

The kernel does mouse-step scaling and bounds-clamping; there is no kernel
acceleration (flat multiply only).

Joystick feel (acceleration/sensitivity) ***IDEA***:
  A joystick reports a *sustained deflection*, not discrete deltas like a
  mouse, so movement should be time-based, not per-USB-packet. Drive it from
  a steady ticker (OS_CallEvery, ~2cs) that runs while mouse control is on:
  each tick read the mapped mouse axes' deflection and compute a small signed
  dx,dy = (deflection beyond a dead zone) * sensitivity, optionally through a
  squared curve for fine control near centre and speed at the edges, then push
  one Report. A per-axis sensitivity factor (to be added) would scale this; the
  kernel's mouse-step then applies on top. This decouples pointer speed from
  USB report rate.


Persistence
--------------
Key and mouse mappings persist via the config store (doc.Config: keyaxes,
keybuttons, mouse) - no extra work needed as these are extended. The runtime
behaviour above is independent of whether a mapping came from auto-map,
a *command/SWI, or the saved config.
