Skip to main content

Binding

Enum Binding 

Source
pub enum Binding {
Show 16 variants Key(KeyCode), MouseButton(PointerButton), MouseMotion, MouseScroll, PointerPosition { axis: PointerAxis, }, KeyAxis { negative: KeyCode, positive: KeyCode, }, Chord { modifier: Modifier, key: KeyCode, }, ButtonChord { modifier: Modifier, button: PointerButton, }, ScrollChord { held: KeyCode, }, Virtual(String), Wasd { up: KeyCode, down: KeyCode, left: KeyCode, right: KeyCode, }, PadButton(PadButton), PadDpad, PadStick { stick: Stick, deadzone: f32, }, PadChord { modifier: PadButton, button: PadButton, }, PadTrigger { trigger: Trigger, threshold: f32, },
}
Expand description

A binding source: what raw input triggers this action.

Keyboard, mouse, gamepad and on-screen controls. A game played with one finger needs nothing touch-specific — the platforms deliver the primary contact as an ordinary pointer, so Binding::MouseButton and Binding::PointerPosition are what a phone plays it through. Binding::Virtual is what a game needs when one finger is not enough.

PartialEq and not Eq: a pad binding’s dead zone is an f32.

Its Display and FromStr are a stable text form, KeyR or Pad:South, for a player’s saved rebinds; binding_text has the spelling of each.

Variants§

§

Key(KeyCode)

A single key.

§

MouseButton(PointerButton)

A mouse button.

§

MouseMotion

Mouse motion (delta in pixels).

§

MouseScroll

Mouse scroll wheel.

§

PointerPosition

Where the pointer is, normalised to the surface it is over: −1.0 at one edge, +1.0 at the other, with +X right and +Y up.

Drives an ActionKind::Axis1, whose −1…1 range is already exactly a normalised coordinate. Feeding an Axis2 instead would put a place in the same value as Binding::Wasd’s direction, and a consumer handed (0.5, 0.0) could not tell “half way to the right edge” from “moving right at half speed”; a fourth ActionKind for one binding would be a whole value shape for a case Axis1 already covers. Any other kind ignores this binding, as Binding::MouseMotion does on a button.

Normalised, not pixels, because pixels are the surface’s business: a device-pixel coordinate makes every consumer redo the DPI arithmetic the windowing layer already did, and get it wrong on exactly the displays nobody develops on. What the consumer still owns is the step from the surface to its own world — a camera’s half width is not the map’s to know.

A pointer that leaves keeps its last position. Leaving is not a command: the platform reports it with no coordinate at all, so there is nothing to resolve, and an axis that recentred itself would walk a paddle to the middle of the field every time a finger lifted.

On an axis that also has a relative source — a Binding::KeyAxis, a Binding::MouseScroll — this one wins whenever the pointer has a position, because summing them would add a place to a rate and produce neither. That is a resolution, not an arbitration: a consumer whose keyboard means something genuinely different from its pointer (a paddle driven left at a speed, versus a paddle put at a coordinate) declares two actions and picks between them with Axis1Action::pointer_moved.

Fields

§axis: PointerAxis

Which coordinate this action reads.

§

KeyAxis

Two keys driving one 1-D axis: negative contributes −1.0, positive +1.0, and both at once cancel.

A single Binding::Key on an Axis1 can only ever push the axis positive, so a keyboard-driven throttle or zoom needs this.

Fields

§negative: KeyCode

Key for the −1.0 direction.

§positive: KeyCode

Key for the +1.0 direction.

§

Chord

A key that counts only while a Modifier is held — Shift+Tab.

The more specific binding takes the key. While the modifier is held, every plain Binding::Key, Binding::KeyAxis and Binding::Wasd on the same key, in the context that owns the key, reads it as up — so ui_next on Tab and ui_prev on Shift+Tab never both fire. Holding Tab and then pressing Shift therefore releases the one and presses the other.

The modifier is read, not consumed: a chord owns its key and nothing else, so a Shift+Tab in a pushed context leaves a sprint bound to Shift in the context beneath it alone.

Fields

§modifier: Modifier

The modifier that must be held.

§key: KeyCode

The key the chord owns.

§

ButtonChord

A mouse button that counts only while a Modifier is held — Alt+right click beside a plain right click. The mouse’s Binding::Chord, on the same two rules, and read as Binding::MouseButton is: down on an ActionKind::Button, inert on the other kinds.

The more specific binding takes the button. While the modifier is held, every plain Binding::MouseButton on the same button, in the context that owns the button, reads it as up — so an aim on the right button and a zoom on Alt+right never both fire. Holding the button and then pressing the modifier releases the one and presses the other; letting the modifier go first hands the button back.

The modifier is read, not consumed: a button chord owns its button and nothing else, so a lean bound to Alt still sees every press of Alt, chorded or not.

Fields

§modifier: Modifier

The modifier that must be held.

§button: PointerButton

The mouse button the chord owns.

§

ScrollChord

The mouse wheel, read only while held is down — Z+wheel, Ctrl+wheel.

Read as Binding::MouseScroll is: the vertical delta on an ActionKind::Axis1, inert on the other kinds. It reads the wheel as one, too, so it takes the wheel for its context as a MouseScroll would.

The more specific binding takes the wheel, as it takes the key for a Binding::Chord: while the held key of any scroll chord in the context that owns the wheel is down, every plain MouseScroll in that context reads zero. With several of those keys down, the most recently pressed one takes the wheel and the chords on the others read zero, so letting go of it hands the wheel back to the one pressed before. An OS auto-repeat of a key already down is not a press and takes nothing.

The held key is read, not consumed, as a chord’s modifier is: a scroll chord owns the wheel and nothing else, so a Binding::Key on Z still sees Z — a game that also taps Z cancels that tap with ActionMap::cancel_patterns when the wheel turns. A held key withheld from its owner (see context.rs) is up for this read too.

Only an enabled action’s scroll chord competes. A key whose action is disabled (ActionMap::set_enabled) takes the wheel from nothing and silences no plain MouseScroll, however recently it was pressed: Ctrl held for one chord keeps the wheel when Alt goes down for a chord that cannot act right now. Enabling it again restores its place by when its key went down, not by when it was enabled.

Fields

§held: KeyCode

The key that must be down; any key, modifiers included.

§

Virtual(String)

An on-screen control, by the id the widget drawing it was given.

The touch row of a binding table, and the one binding whose device is a piece of the game’s own UI: a crcbl-ui control hit-tests the raw contacts, decides what its geometry makes of them, and reports the result here through ActionMap::virtual_button or ActionMap::virtual_stick. From this side it is a device like any other — the same action can carry a key, a mouse button and one of these, and nothing downstream can tell which of them spoke.

That split is deliberate and it is why there is no binding on a raw contact. A finger reports a place on the glass; what it means is a question only the thing drawn under it can answer, and an ActionMap that hit-tested widgets would have to be told where every control was drawn this frame.

A control is a button or a stick, and an action reads whichever matches its own kind: an ActionKind::Button is down while the named control is held, an ActionKind::Axis2 takes the named control’s deflection, and an ActionKind::Axis1 takes nothing — reducing a stick to one axis is a choice the control would have to make and none of them makes it. A binding whose kind does not match is inert, the way Binding::MouseMotion is on a button.

The vector arrives already inside the unit disc, and is clamped to it again here: a control with a longer throw than its own radius is a broken control, not a player asking to run faster.

§

Wasd

WASD composite: four keys mapped to a 2-D axis.

The composite is normalized, so a diagonal is a unit vector rather than (1, 1) — otherwise diagonal movement is 41% faster than cardinal.

Fields

§up: KeyCode

Key for the +Y direction (forward / up).

§down: KeyCode

Key for the −Y direction (back / down).

§left: KeyCode

Key for the −X direction (left).

§right: KeyCode

Key for the +X direction (right).

§

PadButton(PadButton)

A pad button, by position — see PadButton.

Read like a Binding::Key: down on an ActionKind::Button, +1.0 on an ActionKind::Axis1, nothing on an ActionKind::Axis2 — the d-pad’s Axis2 is Binding::PadDpad. Down while any connected pad holds it.

§

PadDpad

The d-pad as one 2-D axis: Binding::Wasd over PadButton::DpadUp, PadButton::DpadDown, PadButton::DpadLeft and PadButton::DpadRight, +Y up.

Resolved exactly as Wasd is: into the same unit disc as the keys and the sticks on the action, so a diagonal is a unit vector and opposite directions cancel; down on an ActionKind::Button while any of the four is held; inert on an ActionKind::Axis1. It owns the four buttons for routing, as Wasd owns its four keys.

§

PadStick

A pad stick’s deflection, +Y up, through a scaled radial dead zone: zero within deadzone of centre, rescaled so the zone’s edge reads 0 and full throw reads 1.

Drives an ActionKind::Axis2, into the same unit disc as a Binding::Wasd or a Binding::Virtual stick on the action, so a stick and a key pushed together ask for one direction. Inert on the other kinds, as a Binding::Virtual stick is on an Axis1.

Fields

§stick: Stick

Which stick.

§deadzone: f32

The dead zone’s radius, in 0.0..1.0; anything else is refused with ActionMapError::InvalidDeadzone.

§

PadChord

A pad button that counts only while another pad button is held — a held shoulder giving the face buttons a second layer. The pad’s Binding::Chord, on the same two rules:

The more specific binding takes the button. While modifier is held, every plain Binding::PadButton on button (and a Binding::PadDpad reading it), in the context that owns the button, reads it as up — so a jump on South and a vault on LB+South never both fire. Holding South and then pressing LB releases the one and presses the other. A chord in a context beneath the owner reads nothing, unless its action is marked with ActionMap::set_pad_chords_outrank: then it takes the button from the contexts above while modifier is held (context.rs).

The modifier is read, not consumed: a pad chord owns its button and nothing else, so modifier can still carry a plain binding of its own, which sees every press of it, chorded or not.

Fields

§modifier: PadButton

The pad button that must be held.

§button: PadButton

The pad button the chord owns.

§

PadTrigger

A pad trigger past a threshold.

On an ActionKind::Button, down while the pull is past threshold; on an ActionKind::Axis1, the pull rescaled so the threshold reads 0 and full pull reads 1. Inert on an ActionKind::Axis2.

Fields

§trigger: Trigger

Which trigger.

§threshold: f32

The threshold, in 0.0..1.0; anything else is refused with ActionMapError::InvalidDeadzone.

Implementations§

Source§

impl Binding

Source

pub const fn device(&self) -> Device

The kind of device this binding listens to — which list of a binding asset it is written in (binding_asset.rs), and what ActionMap::hint matches against ActionMap::last_device.

A binding that reads two devices belongs to the one its value comes from: a Binding::ScrollChord is the wheel with a key held, so it is Device::Pointer’s. Binding::PointerPosition is the pointer’s too, though a phone’s primary contact drives it — the platform hands that contact over as a pointer.

Source§

impl Binding

Source

pub fn visit_keys(&self, visit: impl FnMut(KeyCode))

Calls visit with every key this binding owns — the keys a context consumes by binding it. A Binding::Chord’s modifier is not one, and neither is a Binding::ScrollChord’s held key.

Source

pub const fn reads_gamepad(&self) -> bool

Whether this binding reads a gamepad.

Source

pub fn owns_key(&self, key: KeyCode) -> bool

Whether this binding owns key.

Trait Implementations§

Source§

impl Clone for Binding

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Binding

Source§

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

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

impl Display for Binding

Source§

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

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

impl FromStr for Binding

Source§

type Err = BindingParseError

The associated error which can be returned from parsing.
Source§

fn from_str(text: &str) -> Result<Self, Self::Err>

Parses a string s to return a value of this type. Read more
Source§

impl PartialEq for Binding

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Binding

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
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.