Split the keyboard onto its own translucent OpenXR quad
build / build (push) Successful in 1m52s

Expand the on-screen keyboard to a full US layout (letters, digits,
punctuation, Shift layer, Tab, arrows, F1-F12, one-shot Ctrl/Alt
modifiers), make it a persistent, movable, closeable panel via a
title-bar drag handle, and lower its opacity.

Previously the keyboard was just a second panel swapped into the same
quad as the menu launcher, which made the launcher translucent too and
made the keyboard and menu mutually exclusive. Extract the shared
swapchain/JNI/touch-dispatch plumbing into two generic, reusable
modules - xr_swapchain.c (swapchain + per-image FBO setup) and
xr_overlay.c (an off-screen Android View rendered into its own OpenXR
quad, hit-tested via a laser pointer) - and make the menu launcher and
keyboard two independent XrOverlay instances instead of one. The
controller's menu button now only opens/closes the launcher; the
launcher's "Keyboard" button only opens the keyboard - so the keyboard
can stay up while picking something from the menu, and only the
keyboard's own Close button hides it.

xr_menu.c/.h are gone, fully absorbed into xr_overlay.c. On the Java
side, OverlayPanel.java carries the shared off-screen-render/touch/
cursor plumbing that MenuOverlay and the new KeyboardOverlay both
subclass.
This commit is contained in:
ml
2026-08-14 06:43:44 +02:00
parent 2d8fb49bf5
commit 3be310ade6
16 changed files with 1897 additions and 1102 deletions
+44 -13
View File
@@ -144,17 +144,47 @@ the viewer, with a separate menu quad toggled by a controller button and
driven by a laser-pointer-style aim ray from each hand
(`android/app/src/main/cpp/xr_input.c`) - point and pull the trigger to
interact with it, same as the game's own Bluetooth mouse/keyboard input
otherwise works unchanged. The menu's "Keyboard" button swaps to a
hand-built on-screen key grid (`MenuOverlay.java` - there's no system IME
to borrow once immersive) that forwards each key press straight to the
game as real input - non-printable keys (Esc/Enter/Backspace) as a
`SDLActivity.onNativeKeyDown()`/`onNativeKeyUp()` pair, the same one a
physical Bluetooth keyboard's presses already go through, and printable
keys (letters, Space) via a synthesized `SDL_TEXTINPUT` event pushed
directly from native code (`questshock_native.c`) - meant as a general
stand-in for keyboard-driven functionality that isn't (yet, or ever)
mapped onto the controllers, not just a future config screen's text
entry. The laser
otherwise works unchanged.
The menu launcher (`MenuOverlay.java` - just a "Keyboard" button so far)
and the keyboard (`KeyboardOverlay.java`) are two fully independent quads,
each its own `XrOverlay` instance (`android/app/src/main/cpp/xr_overlay.c`
- a generic "off-screen Android View rendered into an OpenXR quad,
hit-tested via a laser pointer" module shared by both, and by whatever
similar panel comes next) with its own swapchain, visibility, and
position, so they can be shown/hidden/moved independently - a design
specifically meant to let the keyboard stay open while also picking
something from the (still-to-be-built-out) menu. The controller's menu
button only ever opens/closes the launcher; clicking its "Keyboard" button
only opens the keyboard (never touching the launcher's own visibility) -
the keyboard's own title bar holds the only way to close it again.
The keyboard is a hand-built, full US-layout key grid (there's no system
IME to borrow once immersive) that forwards each key press straight to the
game as real input - non-printable keys (Esc/Enter/Backspace/Tab/arrows/
F1-F12) as a `SDLActivity.onNativeKeyDown()`/`onNativeKeyUp()` pair, the
same one a physical Bluetooth keyboard's presses already go through, and
printable keys (letters, digits, punctuation, Space) via a synthesized
`SDL_TEXTINPUT` event pushed directly from native code
(`questshock_native.c`). A Shift key toggles the whole grid between
lowercase/numbers and uppercase/symbols (doubling as Caps Lock - it stays
toggled until pressed again), and Ctrl/Alt arm as one-shot modifiers,
consumed by whichever key is pressed next - meant as a general stand-in
for keyboard-driven functionality that isn't (yet, or ever) mapped onto
the controllers, not just a future config screen's text entry.
Once opened, the keyboard stays up as a standing input panel while
actually playing rather than a modal you open and close. Its title bar
doubles as a drag handle (grab-and-drag with the trigger, handled entirely
on the native side in `xr_input.c` before it ever reaches
`KeyboardOverlay`'s own touch dispatch) for repositioning it, and holds
the Close button that hides it. It's also rendered semi-transparent
(`XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT` in `xr_session.c`,
set only on the keyboard's layer - the menu launcher stays fully opaque)
so whatever's behind it - the game quad, mid-play - stays visible while
it's up.
The laser
pointer/cursor is currently only visible while
actually aiming at the game or menu quad respectively - there's no visual
feedback yet while aiming at empty space between them. (Only tested on
@@ -321,8 +351,9 @@ each one does:
#### 5.5.1. The menu quad rendering the game instead of itself
While building the OpenXR menu (`android/app/src/main/cpp/xr_menu.c`,
`MenuOverlay.java`), the menu's composition-layer quad consistently showed
While building the OpenXR menu (`android/app/src/main/cpp/xr_overlay.c` -
`xr_menu.c` at the time - and `MenuOverlay.java`), the menu's
composition-layer quad consistently showed
the game's own live rendering instead of the menu's content, even though
every diagnostic (FBO bindings, swapchain/layer submission, texture
upload, viewport/scissor state) checked out correct in isolation.