pub struct Gilrs {
inner: Gilrs,
next_id: usize,
tx: Sender<Message>,
rx: Receiver<FfMessage>,
counter: u64,
mappings: MappingDb,
default_filters: bool,
events: VecDeque<Event>,
axis_to_btn_pressed: f32,
axis_to_btn_released: f32,
pub(crate) update_state: bool,
pub(crate) gamepads_data: Vec<GamepadData>,
}
Expand description
Main object responsible of managing gamepads.
In order to get gamepad handle, use gamepad()
, or connected_gamepad()
. The main difference
between these two is that gamepad()
will also return handle to gamepad that is currently
disconnected. However, both functions will return None
if gamepad with given id has never
existed.
§Event loop
All interesting actions like button was pressed or new controller was connected are represented
by struct Event
. Use next_event()
function to retrieve event from
queue.
use gilrs::{Gilrs, Event, EventType, Button};
let mut gilrs = Gilrs::new().unwrap();
// Event loop
loop {
while let Some(event) = gilrs.next_event() {
match event {
Event { id, event: EventType::ButtonPressed(Button::South, _), .. } => {
println!("Player {}: jump!", id)
}
Event { id, event: EventType::Disconnected, .. } => {
println!("We lost player {}", id)
}
_ => (),
};
}
}
§Cached gamepad state
Gilrs
also menage cached gamepad state. Updating state is done automatically, unless it’s
disabled by GilrsBuilder::set_update_state(false)
. However, if you are using custom filters,
you still have to update state manually – to do this call update()
method.
To access state you can use Gamepad::state()
function. Gamepad also implement some state
related functions directly, see Gamepad
for more.
§Counter
Gilrs
has additional functionality, referred here as counter. The idea behind it is simple,
each time you end iteration of update loop, you call Gilrs::inc()
which will increase
internal counter by one. When state of one if elements changes, value of counter is saved. When
checking state of one of elements you can tell exactly when this event happened. Timestamps are
not good solution here because they can tell you when system observed event, not when you
processed it. On the other hand, they are good when you want to implement key repeat or software
debouncing.
use gilrs::{Gilrs, Button};
let mut gilrs = Gilrs::new().unwrap();
let mut player_one = None;
loop {
while let Some(ev) = gilrs.next_event() {
if player_one.is_none() {
player_one = Some(ev.id);
}
// Do other things with event
}
if let Some(id) = player_one {
let gamepad = gilrs.gamepad(id);
if gamepad.is_pressed(Button::DPadLeft) {
// go left
}
match gamepad.button_data(Button::South) {
Some(d) if d.is_pressed() && d.counter() == gilrs.counter() => {
// jump only if button was observed to be pressed in this iteration
}
_ => ()
}
}
// Increase counter
gilrs.inc();
}
Fields§
§inner: Gilrs
§next_id: usize
§tx: Sender<Message>
§rx: Receiver<FfMessage>
§counter: u64
§mappings: MappingDb
§default_filters: bool
§events: VecDeque<Event>
§axis_to_btn_pressed: f32
§axis_to_btn_released: f32
§update_state: bool
§gamepads_data: Vec<GamepadData>
Implementations§
source§impl Gilrs
impl Gilrs
sourcepub fn new() -> Result<Self, Error>
pub fn new() -> Result<Self, Error>
Creates new Gilrs
with default settings. See GilrsBuilder
for more details.
sourcepub fn next_event(&mut self) -> Option<Event>
pub fn next_event(&mut self) -> Option<Event>
Returns next pending event. If there is no pending event, None
is
returned. This function will not block current thread and should be safe
to call in async context. Doesn’t block the thread it is run in
sourcepub fn next_event_blocking(
&mut self,
timeout: Option<Duration>,
) -> Option<Event>
pub fn next_event_blocking( &mut self, timeout: Option<Duration>, ) -> Option<Event>
Same as Gilrs::next_event, but blocks the thread it is run in. Useful for apps that aren’t run inside a loop and just react to the user’s input, like GUI apps.
§Platform support
This function is not supported on web and will always panic.
fn next_event_inner( &mut self, is_blocking: bool, blocking_timeout: Option<Duration>, ) -> Option<Event>
sourcefn next_event_priv(
&mut self,
is_blocking: bool,
blocking_timeout: Option<Duration>,
) -> Option<Event>
fn next_event_priv( &mut self, is_blocking: bool, blocking_timeout: Option<Duration>, ) -> Option<Event>
Returns next pending event.
sourcepub fn update(&mut self, event: &Event)
pub fn update(&mut self, event: &Event)
Updates internal state according to event
.
Please note, that it’s not necessary to call this function unless you modify events by using
additional filters and disabled automatic updates when creating Gilrs
.
sourcepub fn inc(&mut self)
pub fn inc(&mut self)
Increases internal counter by one. Counter data is stored with state and can be used to determine when last event happened. You probably want to use this function in your update loop after processing events.
sourcepub fn counter(&self) -> u64
pub fn counter(&self) -> u64
Returns counter. Counter data is stored with state and can be used to determine when last event happened.
sourcepub fn reset_counter(&mut self)
pub fn reset_counter(&mut self)
Sets counter to 0.
fn finish_gamepads_creation(&mut self)
sourcepub fn gamepad(&self, id: GamepadId) -> Gamepad<'_>
pub fn gamepad(&self, id: GamepadId) -> Gamepad<'_>
Returns handle to gamepad with given ID. Unlike connected_gamepad()
, this function will
also return handle to gamepad that is currently disconnected.
use gilrs::{Button, EventType};
loop {
while let Some(ev) = gilrs.next_event() {
// unwrap() should never panic because we use id from event
let is_up_pressed = gilrs.gamepad(ev.id).is_pressed(Button::DPadUp);
match ev.event {
EventType::ButtonPressed(Button::South, _) if is_up_pressed => {
// do something…
}
_ => (),
}
}
}
sourcepub fn connected_gamepad(&self, id: GamepadId) -> Option<Gamepad<'_>>
pub fn connected_gamepad(&self, id: GamepadId) -> Option<Gamepad<'_>>
Returns a reference to connected gamepad or None
.
sourcepub fn gamepads(&self) -> ConnectedGamepadsIterator<'_> ⓘ
pub fn gamepads(&self) -> ConnectedGamepadsIterator<'_> ⓘ
Returns iterator over all connected gamepads and their ids.
for (id, gamepad) in gilrs.gamepads() {
assert!(gamepad.is_connected());
println!("Gamepad with id {} and name {} is connected",
id, gamepad.name());
}
sourcepub fn insert_event(&mut self, ev: Event)
pub fn insert_event(&mut self, ev: Event)
Adds ev
at the end of internal event queue. It can later be retrieved with next_event()
.
pub(crate) fn ff_sender(&self) -> &Sender<Message>
sourcepub fn set_mapping<'b, O: Into<Option<&'b str>>>(
&mut self,
gamepad_id: usize,
mapping: &MappingData,
name: O,
) -> Result<String, MappingError>
pub fn set_mapping<'b, O: Into<Option<&'b str>>>( &mut self, gamepad_id: usize, mapping: &MappingData, name: O, ) -> Result<String, MappingError>
Sets gamepad’s mapping and returns SDL2 representation of them. Returned mappings may not be
compatible with SDL2 - if it is important, use
set_mapping_strict()
.
The name
argument can be a string slice with custom gamepad name or None
. If None
,
gamepad name reported by driver will be used.
§Errors
This function return error if name
contains comma, mapping
have axis and button entry
for same element (for example Axis::LetfTrigger
and Button::LeftTrigger
) or gamepad does
not have any element with EvCode
used in mapping. Button::Unknown
and
Axis::Unknown
are not allowd as keys to mapping
– in this case,
MappingError::UnknownElement
is returned.
Error is also returned if this function is not implemented or gamepad is not connected.
§Example
use gilrs::{Mapping, Button};
let mut data = Mapping::new();
// …
// or `match gilrs.set_mapping(0, &data, None) {`
match gilrs.set_mapping(0, &data, "Custom name") {
Ok(sdl) => println!("SDL2 mapping: {}", sdl),
Err(e) => println!("Failed to set mapping: {}", e),
};
See also examples/mapping.rs
.
sourcepub fn set_mapping_strict<'b, O: Into<Option<&'b str>>>(
&mut self,
gamepad_id: usize,
mapping: &MappingData,
name: O,
) -> Result<String, MappingError>
pub fn set_mapping_strict<'b, O: Into<Option<&'b str>>>( &mut self, gamepad_id: usize, mapping: &MappingData, name: O, ) -> Result<String, MappingError>
Similar to set_mapping()
but returned string should be compatible
with SDL2.
§Errors
Returns MappingError::NotSdl2Compatible
if mapping
have an entry for Button::{C, Z}
or Axis::{LeftZ, RightZ}
.