Skip to main content

Input

Struct Input 

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

Keyboard state for the current frame.

Implementations§

Source§

impl Input

Source

pub fn is_blocked(&self) -> bool

Whether game input is currently blocked by an open UI element.

Source

pub fn pressed(&self, key: Key) -> bool

true in the frame the key went down. OS key repeat is ignored.

Examples found in repository?
examples/hello.rs (line 15)
14    fn update(&mut self, ctx: &mut Context) {
15        if ctx.input.pressed(Key::Space) {
16            // A pitch that rises over time, so every beep sounds different.
17            let pitch = 300.0 + (ctx.time.elapsed() as f32 * 50.0) % 900.0;
18            ctx.audio.play_tone(pitch.round(), 0.15);
19        }
20        if ctx.input.pressed(Key::F1) {
21            ctx.speech.repeat_last();
22        }
23        if ctx.input.pressed(Key::Escape) {
24            ctx.quit();
25        }
26    }
Source

pub fn pressed_or_repeated(&self, key: Key) -> bool

true in the frame the key went down and whenever the operating system sends a key repeat while it is held. This is what text fields and menus use.

Source

pub fn held(&self, key: Key) -> bool

true as long as the key is held down.

Source

pub fn released(&self, key: Key) -> bool

true in the frame the key was let go.

Source

pub fn held_for(&self, key: Key) -> Option<f32>

How long the key has been held in seconds, or None if it is up.

Source

pub fn repeating(&self, key: Key, delay: f32, every: f32) -> bool

Game-controlled key repeat with your own timing, independent of OS settings.

Returns true when the key is pressed, then again after delay seconds and from then on every every seconds while it stays held. Perfect for walking on a grid:

if ctx.input.repeating(Key::Up, 0.3, 0.3) {
    // take one step forward
}
Examples found in repository?
examples/bell_catcher.rs (line 243)
228    fn update(&mut self, ctx: &mut Context) {
229        if self.over {
230            if ctx.ui.closed("over") {
231                ctx.switch_scene(Title);
232            }
233            return;
234        }
235        if ctx.pressed(Key::Escape) {
236            ctx.switch_scene(Title);
237            return;
238        }
239        if ctx.pressed(Key::S) {
240            ctx.speak(format!("{} bells, {} lives", self.score, self.lives));
241        }
242        for (key, step) in [(Key::Left, -1), (Key::Right, 1)] {
243            if ctx.input.repeating(key, 0.3, 0.15) {
244                let lane = (self.lane + step).clamp(-LANES, LANES);
245                if lane == self.lane {
246                    ctx.play("edge");
247                } else {
248                    self.lane = lane;
249                    ctx.audio.sound("step").at(vec3(step as f32 * 0.5, 0.0, 0.0)).random_pitch(0.9, 1.1).play();
250                }
251            }
252        }
253
254        let dt = ctx.time.delta();
255        if self.left < 0.0 {
256            self.left += dt;
257            if self.left >= 0.0 {
258                self.drop_bell();
259            }
260            return;
261        }
262        self.left -= dt;
263        self.next_ring -= dt;
264        if self.left <= 0.0 {
265            self.land(ctx);
266        } else if self.next_ring <= 0.0 {
267            self.ring(ctx);
268        }
269    }
More examples
Hide additional examples
examples/beacon.rs (line 68)
58    fn update(&mut self, ctx: &mut Context) {
59        if ctx.pressed(Key::Escape) {
60            ctx.push_scene(Pause);
61        }
62        if ctx.pressed(Key::Left) || ctx.pressed(Key::Right) {
63            let degrees = if ctx.pressed(Key::Left) { -45.0 } else { 45.0 };
64            let facing = ctx.physics.turn(self.player, degrees);
65            ctx.speak(math::direction_name(facing));
66        }
67
68        let forward = ctx.input.repeating(Key::Up, 0.35, 0.35);
69        let backward = ctx.input.repeating(Key::Down, 0.35, 0.35);
70        if forward || backward {
71            let step = if forward { 1.0 } else { -1.0 };
72            if ctx.physics.move_forward(self.player, step).blocked {
73                ctx.play("wall");
74            } else {
75                ctx.audio.sound("step").random_pitch(0.85, 1.15).play();
76            }
77        }
78
79        if ctx.pressed(Key::C) {
80            let position = ctx.physics.position(self.player);
81            match ctx.physics.nearest_with_tag(position, "beacon") {
82                Some(beacon) => {
83                    let text = ctx.physics.describe(self.player, beacon);
84                    ctx.speak(text);
85                }
86                None => ctx.speak("No beacons left"),
87            }
88        }
89        if ctx.pressed(Key::F) {
90            let facing = ctx.physics.facing(self.player);
91            ctx.speak(format!("Facing {}", math::direction_name(facing)));
92        }
93
94        if let Some(beacon) = ctx.physics.entered_tag(self.player, "beacon") {
95            ctx.physics.remove(beacon);
96            self.beacons.retain(|b| *b != beacon);
97            ctx.play("found");
98            if self.beacons.is_empty() {
99                self.finish(ctx);
100            } else {
101                ctx.speak(format!("Beacon found! {} left.", self.beacons.len()));
102            }
103        }
104        if ctx.ui.closed("done") {
105            ctx.quit();
106        }
107    }
Source

pub fn axis(&self, negative: Key, positive: Key) -> f32

-1.0, 0.0 or 1.0 depending on which of two held keys is down, e.g. ctx.input.axis(Key::Left, Key::Right) for running in a side scroller.

Examples found in repository?
examples/platformer.rs (line 67)
58    fn update(&mut self, ctx: &mut Context) {
59        if ctx.pressed(Key::Escape) {
60            ctx.quit();
61        }
62
63        // The lift goes up for 4 seconds and down for 4 seconds.
64        let lift_up = (ctx.time.elapsed() % 8.0) < 4.0;
65        ctx.physics.set_velocity(self.lift, vec3(0.0, 0.0, if lift_up { 2.0 } else { -2.0 }));
66
67        let run = ctx.input.axis(Key::Left, Key::Right);
68        let mut velocity = ctx.physics.velocity(self.player);
69        velocity.x = run * 6.0;
70        ctx.physics.set_velocity(self.player, velocity);
71        if ctx.pressed(Key::Space) && ctx.physics.jump(self.player, 2.5) {
72            ctx.play("jump");
73        }
74        let running = ctx.physics.on_ground(self.player) && run != 0.0;
75        self.run_sound.set_volume(if running { 0.6 } else { 0.0 });
76
77        if let Some(speed) = ctx.physics.landed(self.player) {
78            ctx.audio.sound("land").volume((speed / 12.0).clamp(0.2, 1.0)).play();
79            if speed > 15.0 {
80                ctx.speak("Ouch!");
81            }
82        }
83        if let Some((other, _)) = ctx.physics.collided(self.player)
84            && ctx.physics.tag(other) == "crate"
85        {
86            ctx.play_on(other, "push");
87        }
88        if let Some(coin) = ctx.physics.entered_tag(self.player, "coin") {
89            ctx.physics.remove(coin); // its looping sound stops by itself
90            self.score += 1;
91            ctx.audio.sound("coin").pitch(1.5).play();
92            ctx.speak(format!("{} of {COINS} coins", self.score));
93            if self.score == COINS {
94                ctx.ui.message("won", "You collected every coin! Press enter to quit.");
95            }
96        }
97        if ctx.ui.closed("won") {
98            ctx.quit();
99        }
100
101        if ctx.pressed(Key::S) {
102            let x = ctx.physics.position(self.player).x;
103            ctx.speak(format!("Score {}, position {x:.0}", self.score));
104        }
105    }
More examples
Hide additional examples
examples/flight.rs (line 90)
75    fn update(&mut self, ctx: &mut Context) {
76        if ctx.pressed(Key::Escape) {
77            ctx.quit();
78        }
79        if ctx.pressed(Key::Left) || ctx.pressed(Key::Right) {
80            let facing = ctx.physics.turn(self.drone, if ctx.pressed(Key::Left) { -30.0 } else { 30.0 });
81            ctx.speak(math::direction_name(facing));
82        }
83        if ctx.pressed(Key::PageUp) || ctx.pressed(Key::PageDown) {
84            let pitch = ctx.physics.tilt(self.drone, if ctx.pressed(Key::PageUp) { 30.0 } else { -30.0 });
85            ctx.speak(describe_pitch(pitch));
86        }
87
88        // Smooth flight: 4 meters per second while a key is held.
89        let speed = 4.0 * ctx.time.delta();
90        let forward = ctx.input.axis(Key::Down, Key::Up);
91        if forward != 0.0 {
92            let result = ctx.physics.move_forward(self.drone, forward * speed);
93            self.fly(ctx, result);
94        }
95        let rise = ctx.input.axis(Key::Q, Key::E);
96        if rise != 0.0 {
97            let result = ctx.physics.move_up(self.drone, rise * speed);
98            self.fly(ctx, result);
99        }
100
101        if ctx.pressed(Key::C) {
102            let position = ctx.physics.position(self.drone);
103            match ctx.physics.nearest_with_tag(position, "bird") {
104                Some(bird) => {
105                    let text = ctx.physics.describe(self.drone, bird); // e.g. "2 o'clock, 9 meters, 6 meters above"
106                    ctx.speak(text);
107                }
108                None => ctx.speak("No birds left"),
109            }
110        }
111        if ctx.pressed(Key::F) {
112            let (facing, pitch) = (ctx.physics.facing(self.drone), ctx.physics.pitch(self.drone));
113            ctx.speak(format!("Facing {}, {}", math::direction_name(facing), describe_pitch(pitch)));
114        }
115        if ctx.pressed(Key::H) {
116            let height = ctx.physics.position(self.drone).z;
117            ctx.speak(format!("{height:.0} meters high"));
118        }
119
120        if let Some(bird) = ctx.physics.entered_tag(self.drone, "bird") {
121            ctx.physics.remove(bird);
122            self.birds -= 1;
123            ctx.play("found");
124            if self.birds == 0 {
125                ctx.ui.message("done", "You found every bird!");
126            } else {
127                ctx.speak(format!("Bird found! {} left.", self.birds));
128            }
129        }
130        if ctx.ui.closed("done") {
131            ctx.quit();
132        }
133    }
Source

pub fn movement(&self) -> Vec2

Movement direction from the arrow keys or WASD: x is right, y is forward. Diagonals are normalized, so moving diagonally is not faster.

Source

pub fn movement_3d(&self) -> Vec3

Like Input::movement, plus z for up (Page Up or E) and down (Page Down or Q), for flying, swimming or climbing. x is right, y is forward, z is up. Diagonals are normalized.

Source

pub fn any_pressed(&self) -> bool

true if any key went down this frame.

Source

pub fn keys_pressed(&self) -> &[Key]

Keys that went down this frame in the order they were pressed (including OS repeats).

Source

pub fn text(&self) -> &str

Text typed this frame, respecting keyboard layout and shift state.

Source

pub fn modifiers(&self) -> Modifiers

Current state of shift, control and alt.

Source

pub fn raw(&self) -> RawInput<'_>

Unblocked view of the input, even while a UI element is open.

Source

pub fn held_duration(&self, key: Key) -> Option<Duration>

Duration the key has been held, using a real Duration.

Trait Implementations§

Source§

impl Debug for Input

Source§

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

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

impl Default for Input

Source§

fn default() -> Self

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

Auto Trait Implementations§

§

impl Freeze for Input

§

impl RefUnwindSafe for Input

§

impl Send for Input

§

impl Sync for Input

§

impl Unpin for Input

§

impl UnsafeUnpin for Input

§

impl UnwindSafe for Input

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

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.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more