Skip to main content

ActionMap

Struct ActionMap 

Source
pub struct ActionMap { /* private fields */ }
Expand description

Resolves raw input events to action values.

Bindings are declared once via ActionMap::declare and then driven by feeding raw events (key_event, mouse_button, mouse_motion, mouse_scroll). Per-tick bookkeeping is done with ActionMap::begin_tick.

Implementations§

Source§

impl ActionMap

Source

pub fn from_ron(text: &str) -> Result<Self, BindingAssetError>

A map declaring every action a binding asset lists, in file order, with its patterns attached — see the module docs for the schema.

§Errors

BindingAssetError for text that is not RON, RON that is not the schema (an unknown field or kind, a missing action), or a schema that is not a usable map; AssetRefusal names each.

Source

pub fn to_ron(&self) -> Result<String, AssetWriteError>

Every action’s declaration as a binding asset, in declaration order, in the canonical form: fields in the schema’s order, empty lists left out, four-space indent, \n newlines on every platform, and a final newline. Reading a canonical file and writing it back gives the same bytes.

Writes each action’s defaults, not what a player rebound them to — see the module docs. An emitted action named on a pattern that is not attached is not written, since it does nothing.

§Errors

AssetWriteError for a map the schema cannot say: one whose reading back would differ from it.

§Panics

Never, in practice: a record is strings, integers, enums and sequences, and ron’s serializer has no failing path over those.

Source§

impl ActionMap

Source

pub fn push_context(&mut self, context: &str) -> Result<(), ActionMapError>

Push a declared context on top of the stack.

Every held input the context takes from a context beneath is withheld until released — see the module docs — and every action re-resolves, so what the context beneath lost reads as released on this tick.

§Errors

ActionMapError::UnknownContext if no action was ever declared in it, ActionMapError::ContextAlreadyActive if it is already on the stack.

Source

pub fn push_context_modal( &mut self, context: &str, ) -> Result<(), ActionMapError>

Push a declared context on top of the stack as modal: every key, pointer button, on-screen control, wheel and pad input it does not bind reaches nothing beneath it, where ActionMap::push_context lets it fall through. The pointer’s position and motion still route beneath, and GLOBAL_CONTEXT stays above it.

Everything else is ActionMap::push_context’s: an input held when it opens loses its owner and is withheld until released, so a walk held into an inventory stops, and does not resume when it closes until the key is pressed again.

§Errors

As ActionMap::push_context.

Source

pub fn pop_context(&mut self, context: &str) -> Result<(), ActionMapError>

Pop the topmost pushed context, which must be context.

Its actions go idle without a release edge, as a disabled action does, and inputs it held fall through to the contexts beneath only once they have been released.

§Errors

ActionMapError::UnknownContext if it was never declared, ActionMapError::ContextNotOnTop if it is not the topmost pushed context — including GAMEPLAY_CONTEXT, which is never pushed.

Source

pub fn active_contexts(&self) -> impl Iterator<Item = &str>

The stack’s contexts’ names, bottom first: GAMEPLAY_CONTEXT, then each pushed context in the order it was pushed. GLOBAL_CONTEXT is active too, above them all, and is not listed.

Source

pub fn is_context_active(&self, context: &str) -> bool

Whether context is on the stack. false for one never declared.

Source

pub fn is_context_modal(&self, context: &str) -> bool

Whether context was pushed with ActionMap::push_context_modal. false for one not on the stack, or never declared.

Source

pub fn context_of(&self, name: &str) -> Option<&str>

The context an action was declared in, or None if it is not declared.

Source

pub fn set_pad_chords_outrank( &mut self, name: &str, outrank: bool, ) -> Result<(), ActionMapError>

Let an action’s Binding::PadChords take their button from the contexts above it while their modifier is held, or put them back under the ordinary precedence — see the module docs.

For a pad chord a player can give a gameplay action when the plain button is a global one: LB+Select rebound from a global free look to a gameplay reload reloads, and Select alone still opens the global map. The mark is the action’s, not a binding’s, so it holds whatever the action is rebound to — ActionMap::rebind and ActionMap::apply_overrides leave it alone, restoring the defaults included — and a binding asset declares it with pad_chords_outrank: true (binding_asset.rs). Off for every action until set.

Every action re-resolves, as after a rebind, and nothing is withheld.

§Errors

ActionMapError::UnknownAction if nothing with that name is declared.

Source

pub fn pad_chords_outrank(&self, name: &str) -> Option<bool>

Whether an action’s pad chords outrank the contexts above it — see ActionMap::set_pad_chords_outrank. None if it is not declared.

Source

pub fn suppress_held(&mut self)

Withhold every input held right now, whoever owns it, until it is released — or for a level, until it rests — and cancel every pattern in flight. See the module docs for what lifts each input.

For a state change that is not a context: movement keys held when a revival starts or a menu opens stop moving the player, and move it again only once pressed again. Every action re-resolves, so one that was down reads as released on this tick.

Source

pub fn suppress_held_action(&mut self, name: &str) -> Result<(), ActionMapError>

Withhold every input held right now that one action’s bindings read, as ActionMap::suppress_held does for all of them, and cancel the patterns in flight on that action and on every action reading one of those inputs.

The input is withheld, not the action: another action bound to the same key reads it as up too — see the module docs. A Binding::Chord withholds its key and not its modifier, and a Binding::ScrollChord its held key.

§Errors

ActionMapError::UnknownAction if nothing with that name is declared.

Source§

impl ActionMap

Source

pub fn last_device(&self) -> Option<Device>

The kind of device that last spoke, or None before any did.

Source

pub const fn last_device_changed(&self) -> bool

Whether ActionMap::last_device changed since the last ActionMap::begin_tick — the edge a game swapping its control prompts reads, as it reads ActionMap::just_pressed for a button.

Set only when a different device takes the front: the keyboard speaking again while it is already the last device changes nothing, and neither does a device moving up behind it. What counts as speaking is device.rs’s rule, so a pad stick drifting inside PAD_ACTIVITY_THRESHOLD never raises it.

Source

pub fn last_pad_kind(&self) -> Option<PadKind>

The family of the pad that last spoke, by the same rule, or None before any pad did — what ActionMap::hint names a pad button after.

Kept apart from ActionMap::last_device because it outlives it: a player who put the pad down for the keyboard and picks it up again is still holding the pad they were.

Source§

impl ActionMap

Source

pub fn set_emits( &mut self, source: &str, pattern: Pattern, target: Option<&str>, ) -> Result<(), ActionMapError>

Make an action’s pattern press target whenever it fires, or stop it with None — see the module docs for what the press looks like.

Names the emitted action whether or not the pattern is attached yet: ActionMap::set_hold and the rest leave it alone, and a pattern that is not attached never fires. Nothing in flight is cancelled, since the pattern’s timing does not change.

§Errors

ActionMapError::UnknownAction if source or target is not declared, ActionMapError::EmitsItself if they are the same action, ActionMapError::NotAButton if target is not an ActionKind::Button — a press is the only thing a pattern can give.

Source

pub fn emits(&self, source: &str, pattern: Pattern) -> Option<&str>

The action an action’s pattern emits, if it names one.

Source§

impl ActionMap

Source

pub fn gamepad_event(&mut self, event: &GamepadEvent)

Feed a pad event from any backend — the one way pads reach a map.

Optional: the events mean the same to a game that reads them directly and never calls this (see the module docs).

Activity makes Device::Gamepad the last device, and the pad’s PadKind the ActionMap::last_pad_kind, by the rule device.rs states for the others: a button going down, or a stick or trigger moving out past PAD_ACTIVITY_THRESHOLD. A release does not, a stick returning to centre does not, and neither does a stick held where it already was — holding it over is like holding a key down, and the pad spoke when it went over. A connection or disconnection is not the player speaking either.

A GamepadEvent::State with a non-finite axis is dropped, and the pad keeps its previous state. One for a pad never announced as GamepadEvent::Connected connects it.

Source

pub fn release_gamepads(&mut self)

Drop every pad to neutral — what focus loss owes the pads, called beside crcbl::engine::lose_focus.

Each pad stays connected at rest until its next snapshot. A button held through this is withheld until it is released, so a pad still holding A when the window comes back does not press A again; sticks and triggers are levels and come back with the next snapshot. The engine loop calls this on the map a game hands it through Game::actions; a game that feeds pads into a map it keeps to itself calls it on focus loss too.

Source

pub fn gamepads(&self) -> impl Iterator<Item = (GamepadId, &GamepadSnapshot)>

The pads currently connected, and what each last reported.

Source§

impl ActionMap

Source

pub fn hint(&self, action: &str) -> Option<Hint>

How the named action’s binding is shown to the player now, in the engine’s own DefaultLabels — see the module docs for which binding is picked. None if no such action is declared or it has no bindings.

use crcbl_core::input::KeyCode;
use crcbl_input::{ActionMap, GamepadEvent, GamepadId, GamepadSnapshot, PadButton, PadKind};

let mut map = ActionMap::from_ron(
    r#"[(action: "jump", kind: Button, keyboard: ["Space"], gamepad: ["Pad:South"])]"#,
)?;
map.key_event(KeyCode::KeyQ, true);
assert_eq!(map.hint("jump").map(|hint| hint.label).as_deref(), Some("Space"));

let mut snapshot = GamepadSnapshot::neutral(PadKind::PlayStation);
snapshot.buttons.insert(PadButton::South);
map.gamepad_event(&GamepadEvent::State { id: GamepadId(1), snapshot });
assert_eq!(map.hint("jump").map(|hint| hint.label).as_deref(), Some("Cross"));
Source

pub fn hint_with( &self, action: &str, labels: &(impl HintLabels + ?Sized), ) -> Option<Hint>

ActionMap::hint, with every label taken from labels — a game’s own table, which overrides the engine’s entry by entry.

Source§

impl ActionMap

Source

pub fn overrides(&self) -> Vec<ActionOverride>

Every action whose bindings differ from the ones it was declared with, in declaration order, with its current bindings.

An action rebound and then rebound back to its declaration is not listed: the diff is by value, not by history.

Source

pub fn apply_overrides( &mut self, overrides: &[ActionOverride], ) -> Vec<ActionMapError>

Sets the map to its declared defaults with overrides on top, through ActionMap::rebind: each listed action gets its listed bindings and every action not listed goes back to its declaration, so applying what ActionMap::overrides returned reproduces the map it came from.

An action whose bindings already match is left alone, so its value and hold state survive. An override that cannot be applied is skipped and its error returned, and the rest still apply: a settings file naming an action the game no longer declares costs that one entry, not the load. The returned list is empty when every override applied.

Source

pub fn override_text(&self) -> Vec<(String, Vec<String>)>

ActionMap::overrides in the bindings’ text form: each rebound action’s name and its bindings’ texts, in declaration order.

Source

pub fn apply_override_text<'a>( &mut self, entries: impl IntoIterator<Item = (&'a str, &'a [String])>, ) -> Vec<OverrideRefusal>

ActionMap::apply_overrides over a list in the bindings’ text form, with every entry that could not apply refused by name: an action this map does not declare is skipped, and an entry with a binding text that does not parse is refused whole — see OverrideRefusal.

Like apply_overrides, every action not listed goes back to its declaration, and so does every action whose entry was refused.

Source

pub fn bound_elsewhere(&self, action: &str, binding: &Binding) -> Option<&str>

The action other than action, in the same context, that binding is already one of the bindings of — what a rebind screen shows as a conflict before it takes the input away from that action.

Exact bindings only: a chord that shares a key with binding is not a conflict here, because the chord rule already lets the two coexist. Actions in other contexts are not conflicts either; the context stack is what decides between them.

Source§

impl ActionMap

Source

pub fn set_tap( &mut self, name: &str, tap: Option<Tap>, ) -> Result<(), ActionMapError>

Attach a tap to an action, or detach it with None.

Attaching or detaching cancels whatever the action’s patterns had in flight, so a press already down when this is called fires nothing — see the module docs.

§Errors

ActionMapError::UnknownAction if nothing with that name is declared.

Source

pub fn set_hold( &mut self, name: &str, hold: Option<Hold>, ) -> Result<(), ActionMapError>

Attach a hold to an action, or detach it with None. Cancels what was in flight, as ActionMap::set_tap does.

§Errors

ActionMapError::UnknownAction if nothing with that name is declared.

Source

pub fn set_double_tap( &mut self, name: &str, double_tap: Option<DoubleTap>, ) -> Result<(), ActionMapError>

Attach a double tap to an action, or detach it with None. Cancels what was in flight, as ActionMap::set_tap does.

§Errors

ActionMapError::UnknownAction if nothing with that name is declared.

Source

pub fn cancel_patterns(&mut self, name: &str) -> Result<(), ActionMapError>

Cancel whatever an action’s patterns have in flight, exactly as a context push does: the press in progress is spent until it is released, and a first tap waiting for its second is dropped. The action’s value is untouched — a held button stays held — and with nothing in flight this changes nothing.

For a press the game decides was something else: a Z held while the wheel turns was a Z+wheel, not the first half of a Z double tap.

§Errors

ActionMapError::UnknownAction if nothing with that name is declared.

Source

pub fn tap(&self, name: &str) -> Option<Tap>

The tap attached to an action, if any.

Source

pub fn hold(&self, name: &str) -> Option<Hold>

The hold attached to an action, if any.

Source

pub fn double_tap(&self, name: &str) -> Option<DoubleTap>

The double tap attached to an action, if any.

Source

pub fn tapped(&self, name: &str) -> bool

Whether an action’s tap fired on this tick. false for an action with no tap, or none declared.

Source

pub fn hold_fired(&self, name: &str) -> bool

Whether an action’s hold fired on this tick. false for an action with no hold, or none declared.

Source

pub fn double_tapped(&self, name: &str) -> bool

Whether an action’s double tap fired on this tick. false for an action with no double tap, or none declared.

Source

pub fn hold_progress(&self, name: &str) -> f32

How far the press in progress is toward the action’s hold, from 0.0 at the press to 1.0 once it fired — the fill of a hold-to-interact ring. 0.0 while nothing is down, for a spent or cancelled press, for an action with no hold, or none declared.

Source§

impl ActionMap

Source

pub fn set_repeat( &mut self, name: &str, repeat: Option<Repeat>, ) -> Result<(), ActionMapError>

Attach a repeat schedule to an action, or detach it with None.

Attaching does not pulse: an action already held when its schedule is attached is treated as having gone down now, and first repeats a Repeat::delay later.

§Errors

ActionMapError::UnknownAction if nothing with that name is declared.

Source

pub fn repeat(&self, name: &str) -> Option<Repeat>

The repeat schedule attached to an action, if any.

Source

pub fn repeated(&self, name: &str) -> bool

Whether an action pulsed on this tick: it went down (or turned to a new direction), or a repeat fell due. false for an action with no schedule, or none declared.

Source

pub fn cardinal(&self, name: &str) -> Option<Cardinal>

The Cardinal a 2-D axis action points in, or None when it is at rest, absent or another kind.

Source§

impl ActionMap

Source

pub fn set_tracing(&mut self, on: bool)

Start or stop recording the resolution trace — see the module docs. Stopping drops what was recorded.

Source

pub const fn is_tracing(&self) -> bool

Whether the resolution trace is being recorded.

Source

pub fn trace(&self) -> impl DoubleEndedIterator<Item = &TraceEntry>

The recorded trace, oldest first; empty while tracing is off.

Source

pub fn trace_claimed(&mut self, input: TracedInput, by: &str)

Records that by took input before it reached this map — the engine loop’s reserved keys, a menu drawn over the game — so the trace shows where an input that never arrived went. Nothing happens while tracing is off, and the map’s state is not touched either way.

Source§

impl ActionMap

Source

pub fn new() -> Self

Create an empty action map.

Source

pub fn declare(&mut self, decl: ActionDecl)

Register an action in GAMEPLAY_CONTEXT. Actions are enabled by default.

§Panics

Panics if an action with the same name has already been declared. Use ActionMap::try_declare when the declaration comes from a user config file, where a duplicate is a message rather than a crash.

Source

pub fn try_declare(&mut self, decl: ActionDecl) -> Result<(), ActionMapError>

Register an action, reporting a duplicate name rather than panicking.

§Errors

ActionMapError::DuplicateName if the name is already declared.

Source

pub fn declare_in(&mut self, context: &str, decl: ActionDecl)

Register an action in the named context, declaring the context on first use.

§Panics

Panics on a duplicate action name, as ActionMap::declare does.

Source

pub fn try_declare_in( &mut self, context: &str, decl: ActionDecl, ) -> Result<(), ActionMapError>

Register an action in the named context, reporting a duplicate name rather than panicking. Action names are unique across every context.

An action declared into an active context with its input already held reports it at once, as ActionMap::rebind does.

§Errors

ActionMapError::DuplicateName if the name is already declared, ActionMapError::InvalidDeadzone if a pad binding’s dead zone or threshold is unusable.

Source

pub fn rebind( &mut self, name: &str, bindings: Vec<Binding>, ) -> Result<(), ActionMapError>

Replace an action’s bindings in place — the rebind path.

Keeps the action’s registration order and enabled flag, and resets its value and hold state (the old bindings’ “is it down” answer says nothing about the new ones). Rebuilding the whole map instead, which was the only option before, lost both.

§Errors

ActionMapError::UnknownAction if nothing with that name is declared, ActionMapError::InvalidDeadzone if a pad binding’s dead zone or threshold is unusable — and then the old bindings stay.

Source

pub fn bindings(&self, name: &str) -> Option<&[Binding]>

The bindings currently driving an action, or None if it is not declared.

Source

pub fn is_enabled(&self, name: &str) -> Option<bool>

Whether an action is enabled. None if it is not declared.

Source

pub fn set_enabled(&mut self, name: &str, enabled: bool)

Enable or disable an action by name. Disabled actions always return their default (idle) value and do not react to input — including across ActionMap::begin_tick, which used to re-read the held-key set and re-press a disabled action on the very next tick.

An action with a Binding::ScrollChord also leaves or rejoins the wheel’s competition, and the wheel is re-read at once.

Has no effect if the named action does not exist.

Source

pub fn key_event(&mut self, key: KeyCode, pressed: bool)

Feed a key event. pressed → key-down, !pressed → key-up.

A press makes Device::Keyboard the last device; a release does not, since letting go of a key after reaching for the mouse is not the keyboard speaking.

Source

pub fn mouse_button(&mut self, button: PointerButton, pressed: bool)

Feed a mouse-button event.

Source

pub fn mouse_motion(&mut self, dx: f32, dy: f32)

Feed mouse motion (delta in pixels since the last event).

Non-finite deltas are dropped: a NaN from a driver or a divide-by-zero sensitivity would otherwise propagate straight into an action value and poison every comparison downstream.

Source

pub fn mouse_scroll(&mut self, dx: f32, dy: f32)

Feed scroll input (delta in detents or pixels — caller normalises).

Non-finite deltas are dropped, as for ActionMap::mouse_motion; f32::clamp returns NaN for a NaN input, so the clamp downstream is no defence.

Source

pub fn pointer_position(&mut self, x: f32, y: f32)

Feed the pointer’s position, normalised to the surface: −1.0 at one edge and +1.0 at the other, +X right and +Y up.

The caller does the conversion because the caller is the only thing that knows the surface — see Binding::PointerPosition, which also says why a pointer that leaves is not reported here at all.

A coordinate equal to the one already held is dropped, so Axis1Action::pointer_moved means the pointer moved rather than that an event arrived. Non-finite coordinates are dropped like ActionMap::mouse_motion’s deltas: a NaN would poison every comparison downstream of the axis.

Source

pub fn virtual_button(&mut self, control: &str, pressed: bool)

Feed an on-screen button: the control named by control is held, or it is not.

The widget decides what “held” means for its own geometry — which contact owns it, and whether a lift over it commits or cancels. What arrives here is the answer, and it drives every Binding::Virtual with this id on an ActionKind::Button exactly as a key event drives a Binding::Key, edges included.

Source

pub fn virtual_stick(&mut self, control: &str, x: f32, y: f32)

Feed an on-screen stick: where the control named by control is deflected to, with +X right and +Y up.

A level, not a delta — a stick held still reports the same value every frame, and a stick nobody is touching reports (0.0, 0.0). The magnitude belongs to the widget’s own radius, so a control at its edge reports 1.0 and the value is clamped to the unit disc when it is resolved.

Non-finite coordinates are dropped like ActionMap::mouse_motion’s deltas: a NaN would poison every comparison downstream of the axis.

Source

pub fn begin_tick(&mut self, dt: f32)

Called at the start of each server tick.

Source

pub fn action(&self, name: &str) -> Option<&ActionValue>

Get the current value of an action by name.

Returns None if no action with that name was declared.

Source

pub fn action_mut(&mut self, name: &str) -> Option<&mut ActionValue>

Get a mutable reference to the current value of an action.

The caller can use this to clear edge flags after consuming them (e.g. setting just_pressed = false after a jump was processed).

Source

pub fn action_names(&self) -> impl Iterator<Item = &str>

All declared action names, in registration order.

Source

pub fn button_held(&self, name: &str) -> bool

Whether a button action is down — pressed this tick or still held.

An action that was never declared, or that is not a button, is false rather than an error: a caller asking whether a button is down has no better answer to give, and every game was already collapsing both cases that way.

The state is matched positively rather than as “not Released”. The two agree while ButtonState has three variants, and would stop agreeing the day it gains a fourth — silently, and only for whoever wrote the negation.

Source

pub fn just_pressed(&self, name: &str) -> bool

Whether a button action went down on this tick.

The edge, not the level: true only for the tick of the transition, and cleared by ActionMap::begin_tick. This is what a jump or a flap reads, so that holding the key does not repeat it.

Source

pub fn just_released(&self, name: &str) -> bool

Whether a button action came up on this tick.

Source

pub fn axis1(&self, name: &str) -> f32

A 1-D axis action’s value, or 0.0 if it is absent or another kind.

Source

pub fn axis2(&self, name: &str) -> (f32, f32)

A 2-D axis action’s value, or (0.0, 0.0) if it is absent or another kind.

Key-driven composites arrive normalised to at most unit length, so a diagonal is not faster than a cardinal; mouse motion is a raw pixel delta and is not normalised.

Source

pub fn held_keys(&self) -> Vec<KeyCode>

Every key held down, in the order they were pressed — what an input inspector shows beside the actions they drive. Raw: a key no context binds, or one withheld, is listed as much as any other.

Source

pub fn held_mouse_buttons(&self) -> Vec<PointerButton>

Every pointer button held down, in PointerButton’s order. Raw, as ActionMap::held_keys is.

Source

pub const fn pointer(&self) -> Option<(f32, f32)>

Where the pointer last was, normalised to the surface as ActionMap::pointer_position takes it, or None before it reported a position.

Trait Implementations§

Source§

impl Debug for ActionMap

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ActionMap

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.