c24b7f15cb
build / build (push) Successful in 2m14s
Add a player_controls config group that maps game actions to controller inputs, and a Controller Options menu tab to rebind them in-headset. - 45 actions: movement, click/double-click, jump, fire, and the engine's own keyboard hotkeys (posture, save/load, weapon/MFD select, etc.), sent to the engine as synthetic key events. Cheat and dead hotkeys are not exposed. - Press-to-capture rebinding with per-input exclusivity, Reset to Defaults (built-in defaults, then questshock.config.default.json), and new defaults: left stick moves/strafes, right stick turns. - Controller profiles for Touch, Vive and generic OpenXR (res/controller_profiles/), matched to the active interaction profile at runtime, with a fatal dialog if a profile's bindings are rejected at startup. - The menu's thumbstick locomotion is disabled while the Controller Options tab is open or a capture is active. A scrollable list with a tap-to-jump scroll bar handles the long action list. - Opening the menu pauses a running game and resumes it on close. - Reset Position now keeps the player's facing instead of turning the screen to the current gaze. - Play the intro video in the game's language (engine patch 23), falling back to English. - Watchdog and shared-key handling for stuck movement keys, plus key-edge logging.
155 lines
8.1 KiB
C
155 lines
8.1 KiB
C
// Controller input for questshock's immersive Quest build: one OpenXR
|
|
// action set (aim pose + trigger click per hand, a menu-toggle button on
|
|
// the left controller) plus ray/quad hit-testing. Each hand's ray is
|
|
// tried against the keyboard overlay, then the menu overlay (see
|
|
// xr_overlay.h, xr_session.c), then - only if neither actually claims it
|
|
// this frame (landing on it now, or continuing a touch/drag begun on a
|
|
// previous frame - not merely because that overlay happens to be visible)
|
|
// - the game quad xr_session.c submits, forwarding trigger edges to
|
|
// whichever overlay claims the ray as synthetic touches. The game quad
|
|
// itself acts as a plain desktop-style mouse pointer into the engine's
|
|
// own UI (see xr_mouse.h) - absolute cursor position while the ray hits
|
|
// it, plus a left click on the trigger edge; a pending click there
|
|
// likewise keeps claiming the ray ahead of the keyboard/menu until
|
|
// released, so the eventual mouse-up isn't lost if the ray strays. Since
|
|
// none of the three targets' own feedback (the overlays' on-quad cursor,
|
|
// drawn by their Java views; the engine's own mouse cursor sprite for the
|
|
// game quad) gives any indication while the ray is short of actually
|
|
// landing on something, every claimed target also builds a thin,
|
|
// billboarded laser-beam quad per hand from the controller to wherever
|
|
// the ray currently crosses that target's plane (see
|
|
// xr_input_get_beam_layer()) - so aiming looks and behaves the same
|
|
// whether the target is an overlay or the game quad itself.
|
|
#ifndef QUESTSHOCK_XR_INPUT_H
|
|
#define QUESTSHOCK_XR_INPUT_H
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
|
|
#define XR_USE_PLATFORM_ANDROID 1
|
|
#define XR_USE_GRAPHICS_API_OPENGL_ES 1
|
|
#include <openxr/openxr.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
// Call once, right after the session is created (see xr_session.c's
|
|
// xr_create_instance_and_session()) - creates the action set/actions,
|
|
// suggests Touch controller bindings, creates the per-hand aim action
|
|
// spaces and a view-space reference (for the laser-beam billboard math),
|
|
// creates the two per-hand beam swapchains (swapchain_format - the same
|
|
// format shared by the game swapchain and both overlays), and attaches
|
|
// the action set to the session. Returns false (logged, non-fatal - the
|
|
// caller keeps rendering without input) if any of that fails.
|
|
bool xr_input_init(XrInstance instance, XrSession session, int64_t swapchain_format);
|
|
|
|
// Call once per frame from xr_frame_end(), before releasing the acquired
|
|
// swapchain image - syncs this frame's action states (always, so edge
|
|
// detection stays correct even on frames with nothing to draw), handles
|
|
// the menu_toggle button's edge, and hit-tests/dispatches each hand's ray
|
|
// against keyboard/menu/game quad in that priority order (see the file
|
|
// comment above). draw gates only the laser-beam visuals (and the
|
|
// head-pose locate that feeds them) - if false (nothing to draw into this
|
|
// frame, e.g. no swapchain image was acquired), hit-testing and
|
|
// touch-forwarding still run. baseSpace/time must match whatever
|
|
// xr_frame_begin() used to predict this frame.
|
|
void xr_input_sync_and_draw(XrSpace baseSpace, XrTime time, bool draw);
|
|
|
|
// Call once per hand (hand: 0=left, 1=right) after xr_input_sync_and_draw()
|
|
// in the same frame - if that hand's ray claimed the keyboard, menu, or
|
|
// game quad this frame (see the file comment above), fills *out_quad's
|
|
// subImage/pose/size for its laser-beam ribbon and returns true.
|
|
// space/eyeVisibility/layerFlags are left for the caller to set, same
|
|
// convention as xr_overlay_render_and_build_layer(). Returns false
|
|
// (out_quad untouched) if no beam should be shown for that hand this
|
|
// frame.
|
|
bool xr_input_get_beam_layer(int hand, XrCompositionLayerQuad *out_quad);
|
|
|
|
// Recenters the player so the game quad ("virtual screen") appears directly
|
|
// ahead of wherever they are standing and facing, from their current real head
|
|
// pose. Never reads or writes questshock.config.json. Called automatically
|
|
// once, from xr_input_sync_and_draw(), on the first frame with a valid head
|
|
// pose after startup, unless a complete saved player_position was loaded (see
|
|
// xr_input_skip_startup_recenter()): a saved position is relative to a
|
|
// previous session's real-space origin, which is not stable across launches.
|
|
// Returns false (no-op) if no valid head pose is available yet.
|
|
bool xr_input_recenter_player_to_screen(void);
|
|
|
|
// The Main Menu tab's "Reset Position" button (via qs_config.c). Like
|
|
// xr_input_recenter_player_to_screen(), but re-anchors only the player's
|
|
// position to the centre in front of the game quad; the current facing (yaw)
|
|
// is kept, so the screen does not rotate to follow the gaze. Returns false
|
|
// (no-op) if no valid head pose is available yet.
|
|
bool xr_input_reset_player_position(void);
|
|
|
|
// Called once, from qs_config_load_startup() (qs_config.c), when a
|
|
// complete saved player_position was actually loaded from
|
|
// questshock.config.json - cancels the pending automatic startup recenter
|
|
// above so it doesn't immediately override the value that was just
|
|
// applied. Safe to call regardless of whether xr_input_init() has even run
|
|
// yet (this only touches the plain file-local flag, no XR calls).
|
|
void xr_input_skip_startup_recenter(void);
|
|
|
|
// ===========================================================================
|
|
// Remappable controls ("player_controls" config group; see qs_config.c and
|
|
// CONFIG.md). menu_toggle is not among them and has no getter/setter: it is
|
|
// fixed (see xr_input_sync_and_draw()).
|
|
// ===========================================================================
|
|
|
|
// Number of remappable actions and each one's index<->name mapping, which
|
|
// qs_config.c uses to parse/write the player_controls group without its own
|
|
// copy of the list. The names are the keys used in questshock.config.json;
|
|
// index_from_name() returns false for an unrecognized name.
|
|
int xr_input_action_count(void);
|
|
const char *xr_input_action_name(int action_index);
|
|
bool xr_input_action_index_from_name(const char *name, int *out_index);
|
|
|
|
// Current binding for one action, as an opaque int and as its string form
|
|
// (e.g. "right_b", "trigger", "none" for unbound), the same strings used in
|
|
// questshock.config.json and reported by capture.
|
|
int xr_input_get_action_binding(int action_index);
|
|
const char *xr_input_get_action_binding_name(int action_index);
|
|
|
|
// Sets one action's binding from a config-file string. Returns false (binding
|
|
// unchanged) for an unrecognized name, or for the symmetric "trigger"/
|
|
// "squeeze" on an action other than mouse_click/mouse_double_click. Does not
|
|
// enforce one-action-per-input the way capture does: a hand-edited file that
|
|
// binds two actions to one input is accepted as-is.
|
|
bool xr_input_set_action_binding(int action_index, const char *raw_name);
|
|
|
|
// Restores every action to its built-in default (the table xr_input_init()
|
|
// starts from). qs_config.c calls this first for "Reset to Defaults", then
|
|
// applies questshock.config.default.json's player_controls group on top if it
|
|
// has one.
|
|
void xr_input_reset_player_controls(void);
|
|
|
|
// Begins/cancels rebind capture for one action (an index into
|
|
// xr_input_action_name()'s list): the next fresh button or thumbstick-direction
|
|
// edge on any hand becomes that action's binding and is reported via
|
|
// qs_config_notify_control_capture_result(); with no press, capture cancels
|
|
// after 8 seconds. Called via qs_config.c's cross-thread request functions.
|
|
// The menu button is never captured.
|
|
void xr_input_capture_begin(int action_index);
|
|
void xr_input_capture_cancel(void);
|
|
|
|
// The OpenXR interaction profile currently bound (e.g.
|
|
// "/interaction_profiles/oculus/touch_controller"), refreshed once per frame.
|
|
// MenuOverlay.java's Controller Options tab uses it to pick a file from
|
|
// controller_profiles/ (see CONFIG.md). Empty until the first successful
|
|
// query.
|
|
const char *xr_input_get_active_interaction_profile_path(void);
|
|
|
|
// Set by MenuOverlay.java when the Controller Options tab becomes or stops
|
|
// being the menu's current tab. While it is open, the menu's thumbstick
|
|
// locomotion (snap turn/smooth move) is disabled.
|
|
void xr_input_set_controller_options_tab_open(bool open);
|
|
|
|
void xr_input_shutdown(void);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|