ui_input_state/lib.rs
1// Copyright 2025 the UI Events Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4//! Frame-oriented input state built on `ui-events`.
5//!
6//! This crate provides simple state containers to make input handling easier in
7//! immediate-mode or frame-based UIs. Instead of reacting to each event
8//! individually, you feed pointer and keyboard events into the state, query the
9//! current and per-frame information during your update, and then call
10//! [`InputState::clear_frame`] at the end of the frame.
11//!
12//! ## What it provides:
13//!
14//! - [`PrimaryPointerState`]: current pointer state, coalesced and predicted motion,
15//! per-frame button transitions, and helpers for motion in physical/logical units.
16//! - [`KeyboardState`]: current modifiers, keys down, and per-frame key transitions.
17//! - [`InputState`]: a convenience container bundling both states and a per-frame clear.
18//!
19//! ## Typical lifecycle per frame:
20//!
21//! 1. Receive backend events and convert them to `ui-events` types.
22//! 2. Update `PrimaryPointerState` and `KeyboardState` with the events.
23//! 3. Read state during your UI update (e.g. check just pressed, motion, etc.).
24//! 4. Call [`InputState::clear_frame`] before the next frame.
25//!
26//! ## Example (sketch):
27//!
28//! ```no_run
29//! use ui_input_state::{InputState, PrimaryPointerState, KeyboardState};
30//! use ui_events::pointer::PointerEvent;
31//! use ui_events::keyboard::KeyboardEvent;
32//!
33//! let mut input = InputState::default();
34//!
35//! // 1-2) In your event loop, feed events into state
36//! fn on_pointer_event(input: &mut InputState, e: PointerEvent) {
37//! input.primary_pointer.process_pointer_event(e);
38//! }
39//! fn on_keyboard_event(input: &mut InputState, e: KeyboardEvent) {
40//! input.keyboard.process_keyboard_event(e);
41//! }
42//!
43//! // 3) During your update pass, read state
44//! fn update(input: &InputState) {
45//! if input.primary_pointer.is_primary_just_pressed() {
46//! // Begin a drag, for example
47//! }
48//! if input.keyboard.key_str_just_pressed("z") && input.keyboard.modifiers.ctrl() {
49//! // Ctrl+Z
50//! }
51//! }
52//!
53//! // 4) At the end of the frame, clear per-frame transitions
54//! fn end_frame(input: &mut InputState) { input.clear_frame(); }
55//! ```
56//!
57//! ## Coordinates and units
58//!
59//! Pointer positions are stored in physical pixels with a Y-down axis, as in
60//! `ui-events`. Use [`PrimaryPointerState::current_logical_position`] and
61//! [`PrimaryPointerState::logical_motion`] to work in logical units.
62//!
63//! ## Features
64//!
65//! - `std` (enabled by default): Use the Rust standard library.
66//! - `libm`: Enable `ui-events/libm` transitively for `no_std` environments.
67// LINEBENDER LINT SET - lib.rs - v3
68// See https://linebender.org/wiki/canonical-lints/
69// These lints shouldn't apply to examples or tests.
70#![cfg_attr(not(test), warn(unused_crate_dependencies))]
71// These lints shouldn't apply to examples.
72#![warn(clippy::print_stdout, clippy::print_stderr)]
73// Targeting e.g. 32-bit means structs containing usize can give false positives for 64-bit.
74#![cfg_attr(target_pointer_width = "64", warn(clippy::trivially_copy_pass_by_ref))]
75// END LINEBENDER LINT SET
76#![no_std]
77
78extern crate alloc;
79
80mod input_state;
81mod keyboard_state;
82mod primary_pointer_state;
83
84pub use crate::input_state::InputState;
85pub use crate::keyboard_state::KeyboardState;
86pub use crate::primary_pointer_state::PrimaryPointerState;