Input
pebble::wgpu::window::Input (re-exported from pebble::wgpu::prelude) is the frame’s keyboard/mouse/window input state. WGPUPlugin inserts it automatically, so any system can fetch it directly:
use pebble::prelude::*;
use pebble::wgpu::prelude::*;
fn movement(input: Res<Input>, mut query: Query<&mut Transform>) {
for transform in query.iter() {
if input.key_held(KeyCode::KeyW) {
transform.position.z += 1.0;
}
if input.key_pressed(KeyCode::Space) {
// fires once, the step the key goes down
}
if input.mouse_held(MouseButton::Left) {
let (dx, dy) = input.mouse_diff();
// e.g. rotate a camera by (dx, dy)
}
}
}
Input is a plain resource — Res<Input>, no different from any other Res<T>. There’s no concrete backend type to name and no separate lookup step: unlike WindowResource<W> (which needs W, e.g. WindowResource<WinitWindow>, because it also carries the raw surface handle), Input doesn’t depend on which backend produced it, so WindowPlugin inserts it as its own top-level resource in addition to nesting it inside WindowResource<W>::exposed.
KeyCode and MouseButton are Pebble’s own types (mirroring winit’s exactly) — like every other value type in pebble::wgpu, no raw winit type crosses Input’s API, so nothing here requires depending on winit yourself.
Cheap to clone, no guard to hold
Every accessor (key_pressed, key_held, mouse_diff, …) locks internally and returns a plain value — there’s no MutexGuard or similar to keep alive across a match arm or loop body. Clone Input freely; it’s an Arc internally, so every clone reads the same underlying state.
What’s tracked
State refreshes once per step, before systems run, so every accessor below reflects that step:
- Keyboard:
key_pressed/key_released(edge-triggered — true only the step the state changes) andkey_held(true for as long as it’s down), plusheld_shift/held_control/held_altfor the common modifier check. All physical-key based (KeyCode), so bindings stay put across keyboard layouts — the right choice for game controls. - Mouse:
mouse_pressed/mouse_released/mouse_held(same edge/level distinction,MouseButton),cursor()(position in pixels,Nonewhen unfocused),cursor_diff()(frame-to-frame position delta),mouse_diff()(raw device motion — the one to use for a captured-mouse camera, since it isn’t clamped to the window likecursor_diff), andscroll_diff(). - Window:
close_requested(),resolution(),dropped_file(),delta_time(). - Touch:
touches()— every finger currently on the screen, as aVec<TouchPoint>(id,position,phase) — andtouch_count(). Scoped like raylib’s own touch API: current points only, not edge-triggered the way keys/mouse buttons are (no separate “just started” tracking).idis stable for one finger’s whole contact, fromStartedthroughEnded/Cancelled.
Text entry (IME-aware logical keys, typed characters) isn’t covered — Input is scoped to physical input suitable for game controls and simple UI toggles, not a text field implementation.
See Gamepad Input for controllers — a separate Gamepads resource, not part of Input.
Input::delta_time() is a side effect of how winit_input_helper times its own step cycle, not a general-purpose clock — it’s Option<Duration> (None on the first step), and only exists once a window backend has inserted Input at all. For frame delta/elapsed time/fps in any app, graphical or not, reach for Time instead.