concinnity_core/components/frame_input.rs
1// src/components/frame_input.rs
2
3/// Per-frame keyboard and mouse input state.
4///
5/// One `FrameInput` is updated each frame from the window's keyboard and mouse
6/// state and read by camera and UI behavior. It is maintained automatically and
7/// is never saved with the world.
8#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
9pub struct FrameInput {
10 /// True while the move-forward key (W) is held.
11 pub forward: bool,
12 /// True while the move-backward key (S) is held.
13 pub backward: bool,
14 /// True while the strafe-left key (A) is held.
15 pub left: bool,
16 /// True while the strafe-right key (D) is held.
17 pub right: bool,
18 /// True while the sprint key (Shift) is held.
19 pub sprint: bool,
20 /// True for exactly one frame when the interact key (E) is pressed.
21 pub interact: bool,
22 /// True for exactly one frame when the jump key (Space) is pressed.
23 pub jump: bool,
24 /// True while the Control key is held. A modifier used by UI (e.g. a story
25 /// fast-forwards its dialogue while it is down). Like [escape](#structfield.escape)
26 /// and [captured_key](#structfield.captured_key) it is not frozen while a
27 /// menu is open.
28 pub ctrl: bool,
29 /// True while the Shift key is held. A modifier used by UI (e.g. additive
30 /// selection in the editor). Unlike [sprint](#structfield.sprint) it is
31 /// not frozen while a menu is open, matching [ctrl](#structfield.ctrl).
32 pub shift: bool,
33 /// True while the Alt (Option) key is held. A modifier used by UI (e.g.
34 /// the editor's orbit drag). Not frozen while a menu is open, matching
35 /// [ctrl](#structfield.ctrl).
36 pub alt: bool,
37 /// True while the platform's command modifier is held: the Command key on
38 /// macOS, where application shortcuts are built on it. Windows and Linux
39 /// leave this false and use [ctrl](#structfield.ctrl) instead, since the
40 /// Super key there belongs to the desktop shell. UI that offers a shortcut
41 /// on both accepts either modifier. Not frozen while a menu is open,
42 /// matching [ctrl](#structfield.ctrl).
43 pub cmd: bool,
44 /// Gamepad left-stick movement vector `[x, y]`: `x` is rightward strafe,
45 /// `y` is forward. Radial deadzone applied, magnitude at most 1, so partial
46 /// deflection walks slower. `[0.0, 0.0]` with no gamepad; frozen (zeroed)
47 /// while a menu is open, like the movement keys.
48 pub move_axis: [f32; 2],
49 /// Gamepad right-stick look vector `[x, y]` in the mouse-delta sign
50 /// convention (positive `x` looks right, positive `y` looks down), with
51 /// deadzone and response curve applied, magnitude at most 1. Unlike the
52 /// pixel-based mouse deltas this is a deflection rate: consumers scale it
53 /// by their look speed and the frame time. Frozen while a menu is open.
54 pub look_axis: [f32; 2],
55 /// The gamepad button pressed this frame, for one frame, or `None`.
56 /// Surfaced regardless of menu state (like
57 /// [captured_key](#structfield.captured_key)) so the settings menu can
58 /// capture a button for rebinding.
59 pub captured_button: Option<crate::components::GamepadButton>,
60 /// The UI-navigation pulse this frame, or `None`. A one-frame
61 /// [NavDirection](#navdirection) produced from a d-pad press (repeating
62 /// while held) or a deliberate left-stick deflection. Surfaced regardless
63 /// of menu state (like [captured_key](#structfield.captured_key)); menu
64 /// focus movement consumes it only while a screen is active, so during
65 /// play the d-pad and stick keep their movement meaning.
66 pub nav: Option<crate::components::NavDirection>,
67 /// True for exactly one frame when the confirm button (South) is pressed.
68 /// Surfaced regardless of menu state; menus fire their focused control
69 /// from it while a screen is active.
70 pub confirm: bool,
71 /// True for exactly one frame when the back button (East) is pressed.
72 /// Surfaced regardless of menu state; menus treat it like Escape while a
73 /// screen is active.
74 pub back: bool,
75 /// Accumulated horizontal mouse movement since the last frame (pixels).
76 pub mouse_dx: f32,
77 /// Accumulated vertical mouse movement since the last frame (pixels).
78 pub mouse_dy: f32,
79 /// Accumulated vertical scroll-wheel movement since the last frame. Positive
80 /// scrolls the content up (a scrollable UI panel moves its rows up). Cleared
81 /// each frame like the mouse deltas.
82 pub scroll_delta: f32,
83 /// Absolute cursor X position in window pixels (origin top-left).
84 /// Only meaningful when the cursor is not captured.
85 pub mouse_x: f32,
86 /// Absolute cursor Y position in window pixels (origin top-left).
87 /// Only meaningful when the cursor is not captured.
88 pub mouse_y: f32,
89 /// True for exactly one frame when the left mouse button is pressed
90 /// while the cursor is not captured.
91 pub left_click: bool,
92 /// True while the left mouse button is held down (cursor not captured).
93 /// Unlike `left_click` this stays true across frames until release, so a
94 /// UI drag (e.g. a slider) can track the cursor for its whole duration.
95 pub left_button_down: bool,
96 /// True for exactly one frame when the right mouse button is pressed
97 /// while the cursor is not captured. Used for contextual UI (e.g. a
98 /// create-at-cursor menu); it never captures the cursor.
99 pub right_click: bool,
100 /// Live logical viewport size in pixels `[width, height]`. Used to map
101 /// overlay (Screen-owned) UI between its fixed reference resolution and the
102 /// window, so menus scale with the window and the cursor still hit-tests
103 /// against the scaled controls. `[0.0, 0.0]` before the backend is ready.
104 pub viewport: [f32; 2],
105 /// Height of the window chrome overlapping the top of the render surface,
106 /// in the same logical units as [viewport](#structfield.viewport). Non-zero
107 /// only where the window's content runs under a transparent title bar
108 /// (macOS), leaving the OS window buttons floating over the frame's
109 /// top-left corner: UI anchored to the top of the window starts below this
110 /// so it cannot land under them. `0.0` on a window whose content already
111 /// begins below its chrome.
112 pub top_inset: f32,
113 /// True for exactly one frame when the HUD-toggle key (F1) is pressed.
114 pub hud_toggle: bool,
115 /// True for exactly one frame when Escape is pressed while the cursor is
116 /// not captured (menu / UI worlds). Used to fire [KeyBinding](#keybinding)
117 /// actions. In worlds that capture the cursor, Escape instead releases the
118 /// cursor and this stays false.
119 pub escape: bool,
120 /// The canonical key pressed this frame, for one frame, or `None`. Surfaced
121 /// regardless of menu state (unlike the gameplay keys, which freeze while a
122 /// menu is open) so the settings menu can capture a key for rebinding and
123 /// scrollable menu lists can react to the arrow keys.
124 pub captured_key: Option<crate::components::InputKey>,
125 /// The printable character typed this frame (Unicode, with shift / layout
126 /// applied by the OS), for text-input fields, or `None`. A one-frame pulse
127 /// surfaced regardless of menu state, like
128 /// [captured_key](#structfield.captured_key). Editing keys (Backspace,
129 /// Delete, arrows) arrive via `captured_key`, not here.
130 pub typed_char: Option<char>,
131}