Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

547
vendor/gilrs/src/ev/filter.rs vendored Normal file
View File

@@ -0,0 +1,547 @@
// Copyright 2016-2018 Mateusz Sieczko and other GilRs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Alter events in various ways.
//!
//! This modules contains "event filters" that can change, drop or create new events. To use them,
//! import `Filter` trait and call `filter()` function on `Option<Event>`. Because `filter` also
//! returns `Option<Event>` you can combine multiple filters by using `filter()` function on
//! returned event.
//!
//! Filters in this modules have public fields that can be used to configure their behaviour. You
//! can also create them with default values using `new()` method. If filter is not configurable,
//! it is implemented as function (for example `deadzone()`).
//!
//! # Example
//!
//! ```
//! use gilrs::{GilrsBuilder, Filter};
//! use gilrs::ev::filter::{Jitter, Repeat, deadzone};
//!
//! let mut gilrs = GilrsBuilder::new().with_default_filters(false).build().unwrap();
//! let jitter = Jitter { threshold: 0.02 };
//! let repeat = Repeat::new();
//!
//! // Event loop
//! loop {
//! while let Some(event) = gilrs
//! .next_event()
//! .filter_ev(&jitter, &mut gilrs)
//! .filter_ev(&deadzone, &mut gilrs)
//! .filter_ev(&repeat, &mut gilrs)
//! {
//! gilrs.update(&event);
//! println!("{:?}", event);
//! }
//! # break;
//! }
//! ```
//! # Implementing custom filters
//!
//! If you want to implement your own filters, you will have to implement `FilterFn` trait.
//! **Do not return `None` if you got `Some(event)`**. If you want to discard an event, uses
//! `EventType::Dropped`. Returning `None` means that there are no more events to process and
//! will end `while let` loop.
//!
//! ## Example
//!
//! Example implementations of filter that will drop all events with `Unknown` axis or button.
//!
//! ```
//! use gilrs::ev::filter::FilterFn;
//! use gilrs::{Gilrs, Event, EventType, Button, Axis, Filter};
//!
//! struct UnknownSlayer;
//!
//! impl FilterFn for UnknownSlayer {
//! fn filter(&self, ev: Option<Event>, _gilrs: &mut Gilrs) -> Option<Event> {
//! match ev {
//! Some(Event { event: EventType::ButtonPressed(Button::Unknown, ..), id, .. })
//! | Some(Event { event: EventType::ButtonReleased(Button::Unknown, ..), id, .. })
//! | Some(Event { event: EventType::AxisChanged(Axis::Unknown, ..), id, .. })
//! => Some(Event::new(id, EventType::Dropped)),
//! _ => ev,
//! }
//! }
//! }
//! ```
//!
//! `FilterFn` is also implemented for all `Fn(Option<Event>, &Gilrs) -> Option<Event>`, so above
//! example could be simplified to passing closure to `filter()` function.
use crate::ev::{Axis, AxisOrBtn, Button, Code, Event, EventType};
use crate::gamepad::{Gamepad, Gilrs};
use crate::utils;
use std::time::Duration;
/// Discard axis events that changed less than `threshold`.
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Jitter {
pub threshold: f32,
}
impl Jitter {
/// Creates new `Repeat` filter with threshold set to 0.01.
pub fn new() -> Self {
Jitter { threshold: 0.01 }
}
}
impl Default for Jitter {
fn default() -> Self {
Self::new()
}
}
impl FilterFn for Jitter {
fn filter(&self, ev: Option<Event>, gilrs: &mut Gilrs) -> Option<Event> {
match ev {
Some(Event {
event: EventType::AxisChanged(_, val, axis),
id,
..
}) => match gilrs.gamepad(id).state().axis_data(axis) {
Some(data) if val != 0.0 && (val - data.value()).abs() < self.threshold => {
Some(Event::new(id, EventType::Dropped))
}
_ => ev,
},
_ => ev,
}
}
}
fn apply_deadzone(x: f32, y: f32, threshold: f32) -> (f32, f32) {
let magnitude = utils::clamp((x * x + y * y).sqrt(), 0.0, 1.0);
if magnitude <= threshold {
(0.0, 0.0)
} else {
let norm = ((magnitude - threshold) / (1.0 - threshold)) / magnitude;
(x * norm, y * norm)
}
}
fn deadzone_nonzero_axis_idx(axis: Axis) -> Option<usize> {
Some(match axis {
Axis::DPadX => 0,
Axis::DPadY => 1,
Axis::LeftStickX => 2,
Axis::LeftStickY => 3,
Axis::RightStickX => 4,
Axis::RightStickY => 5,
_ => {
return None;
}
})
}
/// Drops events in dead zone and remaps value to keep it in standard range.
pub fn deadzone(ev: Option<Event>, gilrs: &mut Gilrs) -> Option<Event> {
match ev {
Some(Event {
event: EventType::AxisChanged(axis, val, nec),
id,
time,
}) => {
let threshold = match gilrs.gamepad(id).deadzone(nec) {
Some(t) => t,
None => return ev,
};
if let Some((other_axis, other_code)) = axis
.second_axis()
.and_then(|axis| gilrs.gamepad(id).axis_code(axis).map(|code| (axis, code)))
{
let other_val = gilrs.gamepad(id).state().value(other_code);
let val = apply_deadzone(val, other_val, threshold);
// Since this is the second axis, deadzone_nonzero_axis_idx() will always returns something.
let other_axis_idx = deadzone_nonzero_axis_idx(other_axis).unwrap();
if val.0 == 0.
&& val.1 == 0.
&& gilrs.gamepads_data[id.0].have_sent_nonzero_for_axis[other_axis_idx]
&& gilrs.gamepad(id).state().value(other_code) != 0.
{
// Clear other axis that is now within the dead zone threshold.
gilrs.insert_event(Event {
id,
time,
event: EventType::AxisChanged(other_axis, 0., other_code),
});
gilrs.gamepads_data[id.0].have_sent_nonzero_for_axis[other_axis_idx] = false;
}
Some(if gilrs.gamepad(id).state().value(nec) == val.0 {
Event::new(id, EventType::Dropped)
} else {
if let Some(axis_idx) = deadzone_nonzero_axis_idx(axis) {
gilrs.gamepads_data[id.0].have_sent_nonzero_for_axis[axis_idx] =
val.0 != 0.;
}
Event {
id,
time,
event: EventType::AxisChanged(axis, val.0, nec),
}
})
} else {
let val = apply_deadzone(val, 0.0, threshold).0;
Some(if gilrs.gamepad(id).state().value(nec) == val {
Event::new(id, EventType::Dropped)
} else {
if let Some(axis_idx) = deadzone_nonzero_axis_idx(axis) {
gilrs.gamepads_data[id.0].have_sent_nonzero_for_axis[axis_idx] = val != 0.;
}
Event {
id,
time,
event: EventType::AxisChanged(axis, val, nec),
}
})
}
}
Some(Event {
event: EventType::ButtonChanged(btn, val, nec),
id,
time,
}) => {
let gp = &gilrs.gamepad(id);
let threshold = match gp.deadzone(nec) {
Some(t) => t,
None => return ev,
};
let val = apply_deadzone(val, 0.0, threshold).0;
Some(if gp.state().value(nec) == val {
Event::new(id, EventType::Dropped)
} else {
Event {
id,
time,
event: EventType::ButtonChanged(btn, val, nec),
}
})
}
_ => ev,
}
}
/// Maps axis dpad events to button dpad events.
///
/// This filter will do nothing if gamepad has dpad buttons (to prevent double events for same
/// element) and if standard `NativeEvCode` for dpads is used by some other buttons. It will always
/// try to map if SDL mappings contains mappings for all four hats.
pub fn axis_dpad_to_button(ev: Option<Event>, gilrs: &mut Gilrs) -> Option<Event> {
use gilrs_core::native_ev_codes as necs;
fn can_map(gp: &Gamepad<'_>) -> bool {
let hats_mapped = gp.mapping().hats_mapped();
if hats_mapped == 0b0000_1111 {
true
} else if hats_mapped == 0 {
gp.axis_or_btn_name(Code(necs::BTN_DPAD_RIGHT)).is_none()
&& gp.axis_or_btn_name(Code(necs::BTN_DPAD_LEFT)).is_none()
&& gp.axis_or_btn_name(Code(necs::BTN_DPAD_DOWN)).is_none()
&& gp.axis_or_btn_name(Code(necs::BTN_DPAD_UP)).is_none()
&& gp.button_code(Button::DPadRight).is_none()
} else {
// Not all hats are mapped so let's ignore it for now.
false
}
}
let ev = ev?;
let gamepad = gilrs.gamepad(ev.id);
if !can_map(&gamepad) {
return Some(ev);
}
let mut out_event = ev.drop();
match ev.event {
EventType::AxisChanged(Axis::DPadX, val, _) => {
let mut release_left = false;
let mut release_right = false;
if val == 1.0 {
// The axis value might change from left (-1.0) to right (1.0) immediately without
// us getting an additional event for the release at the center position (0.0).
release_left = gamepad.state().is_pressed(Code(necs::BTN_DPAD_LEFT));
gilrs.insert_event(Event {
event: EventType::ButtonChanged(
Button::DPadRight,
1.0,
Code(necs::BTN_DPAD_RIGHT),
),
..ev
});
out_event = Event {
event: EventType::ButtonPressed(Button::DPadRight, Code(necs::BTN_DPAD_RIGHT)),
..ev
};
} else if val == -1.0 {
// The axis value might change from right (1.0) to left (-1.0) immediately without
// us getting an additional event for the release at the center position (0.0).
release_right = gamepad.state().is_pressed(Code(necs::BTN_DPAD_RIGHT));
gilrs.insert_event(Event {
event: EventType::ButtonChanged(
Button::DPadLeft,
1.0,
Code(necs::BTN_DPAD_LEFT),
),
..ev
});
out_event = Event {
event: EventType::ButtonPressed(Button::DPadLeft, Code(necs::BTN_DPAD_LEFT)),
..ev
};
} else {
release_left = gamepad.state().is_pressed(Code(necs::BTN_DPAD_LEFT));
release_right = gamepad.state().is_pressed(Code(necs::BTN_DPAD_RIGHT));
}
if release_right {
if !out_event.is_dropped() {
gilrs.insert_event(out_event);
}
gilrs.insert_event(Event {
event: EventType::ButtonChanged(
Button::DPadRight,
0.0,
Code(necs::BTN_DPAD_RIGHT),
),
..ev
});
out_event = Event {
event: EventType::ButtonReleased(Button::DPadRight, Code(necs::BTN_DPAD_RIGHT)),
..ev
};
}
if release_left {
if !out_event.is_dropped() {
gilrs.insert_event(out_event);
}
gilrs.insert_event(Event {
event: EventType::ButtonChanged(
Button::DPadLeft,
0.0,
Code(necs::BTN_DPAD_LEFT),
),
..ev
});
out_event = Event {
event: EventType::ButtonReleased(Button::DPadLeft, Code(necs::BTN_DPAD_LEFT)),
..ev
};
}
Some(out_event)
}
EventType::AxisChanged(Axis::DPadY, val, _) => {
let mut release_up = false;
let mut release_down = false;
if val == 1.0 {
// The axis value might change from down (-1.0) to up (1.0) immediately without us
// getting an additional event for the release at the center position (0.0).
release_down = gamepad.state().is_pressed(Code(necs::BTN_DPAD_DOWN));
gilrs.insert_event(Event {
event: EventType::ButtonChanged(Button::DPadUp, 1.0, Code(necs::BTN_DPAD_UP)),
..ev
});
out_event = Event {
event: EventType::ButtonPressed(Button::DPadUp, Code(necs::BTN_DPAD_UP)),
..ev
};
} else if val == -1.0 {
// The axis value might change from up (1.0) to down (-1.0) immediately without us
// getting an additional event for the release at the center position (0.0).
release_up = gamepad.state().is_pressed(Code(necs::BTN_DPAD_UP));
gilrs.insert_event(Event {
event: EventType::ButtonChanged(
Button::DPadDown,
1.0,
Code(necs::BTN_DPAD_DOWN),
),
..ev
});
out_event = Event {
event: EventType::ButtonPressed(Button::DPadDown, Code(necs::BTN_DPAD_DOWN)),
..ev
};
} else {
release_up = gamepad.state().is_pressed(Code(necs::BTN_DPAD_UP));
release_down = gamepad.state().is_pressed(Code(necs::BTN_DPAD_DOWN));
}
if release_up {
if !out_event.is_dropped() {
gilrs.insert_event(out_event);
}
gilrs.insert_event(Event {
event: EventType::ButtonChanged(Button::DPadUp, 0.0, Code(necs::BTN_DPAD_UP)),
..ev
});
out_event = Event {
event: EventType::ButtonReleased(Button::DPadUp, Code(necs::BTN_DPAD_UP)),
..ev
};
}
if release_down {
if !out_event.is_dropped() {
gilrs.insert_event(out_event);
}
gilrs.insert_event(Event {
event: EventType::ButtonChanged(
Button::DPadDown,
0.0,
Code(necs::BTN_DPAD_DOWN),
),
..ev
});
out_event = Event {
event: EventType::ButtonReleased(Button::DPadDown, Code(necs::BTN_DPAD_DOWN)),
..ev
};
}
Some(out_event)
}
_ => Some(ev),
}
}
/// Repeats pressed keys.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Repeat {
pub after: Duration,
pub every: Duration,
}
impl Repeat {
/// Creates new `Repeat` filter with `after` set to 500ms and `every` set to 30ms.
pub fn new() -> Self {
Repeat {
after: Duration::from_millis(500),
every: Duration::from_millis(30),
}
}
}
impl Default for Repeat {
fn default() -> Self {
Self::new()
}
}
impl FilterFn for Repeat {
fn filter(&self, ev: Option<Event>, gilrs: &mut Gilrs) -> Option<Event> {
match ev {
Some(ev) => Some(ev),
None => {
let now = utils::time_now();
for (id, gamepad) in gilrs.gamepads() {
for (nec, btn_data) in gamepad.state().buttons() {
match (
btn_data.is_pressed(),
btn_data.is_repeating(),
now.duration_since(btn_data.timestamp()),
) {
(true, false, Ok(dur)) if dur >= self.after => {
let btn_name = match gamepad.axis_or_btn_name(nec) {
Some(AxisOrBtn::Btn(b)) => b,
_ => Button::Unknown,
};
return Some(Event {
id,
event: EventType::ButtonRepeated(btn_name, nec),
time: btn_data.timestamp() + self.after,
});
}
(true, true, Ok(dur)) if dur >= self.every => {
let btn_name = match gamepad.axis_or_btn_name(nec) {
Some(AxisOrBtn::Btn(b)) => b,
_ => Button::Unknown,
};
return Some(Event {
id,
event: EventType::ButtonRepeated(btn_name, nec),
time: btn_data.timestamp() + self.every,
});
}
_ => (),
}
}
}
None
}
}
}
}
/// Allow filtering events.
///
/// See module level documentation for more info.
pub trait Filter {
fn filter_ev<F: FilterFn>(&self, filter: &F, gilrs: &mut Gilrs) -> Option<Event>;
}
/// Actual filter implementation.
///
/// See module level documentation for more info.
pub trait FilterFn {
fn filter(&self, ev: Option<Event>, gilrs: &mut Gilrs) -> Option<Event>;
}
impl<F> FilterFn for F
where
F: Fn(Option<Event>, &mut Gilrs) -> Option<Event>,
{
fn filter(&self, ev: Option<Event>, gilrs: &mut Gilrs) -> Option<Event> {
self(ev, gilrs)
}
}
impl Filter for Option<Event> {
fn filter_ev<F: FilterFn>(&self, filter: &F, gilrs: &mut Gilrs) -> Option<Event> {
let e = filter.filter(*self, gilrs);
debug_assert!(
!(self.is_some() && e.is_none()),
"Filter changed Some(event) into None. See ev::filter documentation for more info."
);
e
}
}
impl Filter for Event {
fn filter_ev<F: FilterFn>(&self, filter: &F, gilrs: &mut Gilrs) -> Option<Event> {
let e = filter.filter(Some(*self), gilrs);
debug_assert!(
e.is_some(),
"Filter changed Some(event) into None. See ev::filter documentation for more info."
);
e
}
}

266
vendor/gilrs/src/ev/mod.rs vendored Normal file
View File

@@ -0,0 +1,266 @@
// Copyright 2016-2018 Mateusz Sieczko and other GilRs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! Gamepad state and other event related functionality.
pub mod filter;
pub mod state;
use std::{
fmt::{Display, Formatter, Result as FmtResult},
time::SystemTime,
};
use crate::{constants::*, gamepad::GamepadId, utils};
#[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Serialize};
/// Platform specific event code.
///
/// This type represents single gamepads's element like specific axis or button.
/// It can't be directly created, but you can get it from events or using
/// `Gamepad`'s methods [`button_code`](crate::Gamepad::button_code) and
/// [`axis_code`](crate::Gamepad::axis_code). If `serde-serialize` feature is
/// enabled, `Code` can be serialized and deserialized, but keep in mind that
/// layout **is** platform-specific. So it's not possible to serialize `Code` on
/// Linux and deserialize it on Windows. This also apply to `Display` implementation.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct Code(pub(crate) gilrs_core::EvCode);
impl Display for Code {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
self.0.fmt(f)
}
}
impl Code {
pub fn into_u32(&self) -> u32 {
self.0.into_u32()
}
}
/// Holds information about gamepad event.
#[derive(Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[non_exhaustive]
pub struct Event {
/// Id of gamepad.
pub id: GamepadId,
/// Event's data.
pub event: EventType,
/// Time when event was emitted.
pub time: SystemTime,
}
impl Event {
/// Creates new event with current time.
pub fn new(id: GamepadId, event: EventType) -> Self {
Event {
id,
event,
time: utils::time_now(),
}
}
/// Returns `Event` with `EventType::Dropped`.
pub fn drop(mut self) -> Event {
self.event = EventType::Dropped;
self
}
/// Returns true if event is `Dropped` and should be ignored.
pub fn is_dropped(&self) -> bool {
self.event == EventType::Dropped
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[non_exhaustive]
/// Gamepad event.
pub enum EventType {
/// Some button on gamepad has been pressed.
ButtonPressed(Button, Code),
/// This event can be generated by [`ev::Repeat`](filter/struct.Repeat.html) event filter.
ButtonRepeated(Button, Code),
/// Previously pressed button has been released.
ButtonReleased(Button, Code),
/// Value of button has changed. Value can be in range [0.0, 1.0].
ButtonChanged(Button, f32, Code),
/// Value of axis has changed. Value can be in range [-1.0, 1.0].
AxisChanged(Axis, f32, Code),
/// Gamepad has been connected. If gamepad's UUID doesn't match one of disconnected gamepads,
/// newly connected gamepad will get new ID.
Connected,
/// Gamepad has been disconnected. Disconnected gamepad will not generate any new events.
Disconnected,
/// There was an `Event`, but it was dropped by one of filters. You should ignore it.
Dropped,
/// A force feedback effect has ran for its duration and stopped.
ForceFeedbackEffectCompleted,
}
#[repr(u16)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// Gamepad's elements which state can be represented by value from 0.0 to 1.0.
///
/// ![Controller layout](https://gilrs-project.gitlab.io/gilrs/img/controller.svg)
pub enum Button {
// Action Pad
South = BTN_SOUTH,
East = BTN_EAST,
North = BTN_NORTH,
West = BTN_WEST,
C = BTN_C,
Z = BTN_Z,
// Triggers
LeftTrigger = BTN_LT,
LeftTrigger2 = BTN_LT2,
RightTrigger = BTN_RT,
RightTrigger2 = BTN_RT2,
// Menu Pad
Select = BTN_SELECT,
Start = BTN_START,
Mode = BTN_MODE,
// Sticks
LeftThumb = BTN_LTHUMB,
RightThumb = BTN_RTHUMB,
// D-Pad
DPadUp = BTN_DPAD_UP,
DPadDown = BTN_DPAD_DOWN,
DPadLeft = BTN_DPAD_LEFT,
DPadRight = BTN_DPAD_RIGHT,
#[default]
Unknown = BTN_UNKNOWN,
}
impl Button {
pub fn is_action(self) -> bool {
use crate::Button::*;
matches!(self, South | East | North | West | C | Z)
}
pub fn is_trigger(self) -> bool {
use crate::Button::*;
matches!(
self,
LeftTrigger | LeftTrigger2 | RightTrigger | RightTrigger2
)
}
pub fn is_menu(self) -> bool {
use crate::Button::*;
matches!(self, Select | Start | Mode)
}
pub fn is_stick(self) -> bool {
use crate::Button::*;
matches!(self, LeftThumb | RightThumb)
}
pub fn is_dpad(self) -> bool {
use crate::Button::*;
matches!(self, DPadUp | DPadDown | DPadLeft | DPadRight)
}
pub fn to_nec(self) -> Option<Code> {
use gilrs_core::native_ev_codes as necs;
match self {
Button::South => Some(necs::BTN_SOUTH),
Button::East => Some(necs::BTN_EAST),
Button::North => Some(necs::BTN_NORTH),
Button::West => Some(necs::BTN_WEST),
Button::C => Some(necs::BTN_C),
Button::Z => Some(necs::BTN_Z),
Button::LeftTrigger => Some(necs::BTN_LT),
Button::LeftTrigger2 => Some(necs::BTN_LT2),
Button::RightTrigger => Some(necs::BTN_RT),
Button::RightTrigger2 => Some(necs::BTN_RT2),
Button::Select => Some(necs::BTN_SELECT),
Button::Start => Some(necs::BTN_START),
Button::Mode => Some(necs::BTN_MODE),
Button::LeftThumb => Some(necs::BTN_LTHUMB),
Button::RightThumb => Some(necs::BTN_RTHUMB),
Button::DPadUp => Some(necs::BTN_DPAD_UP),
Button::DPadDown => Some(necs::BTN_DPAD_DOWN),
Button::DPadLeft => Some(necs::BTN_DPAD_LEFT),
Button::DPadRight => Some(necs::BTN_DPAD_RIGHT),
_ => None,
}
.map(Code)
}
}
#[repr(u16)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
/// Gamepad's elements which state can be represented by value from -1.0 to 1.0.
///
/// ![Controller layout](https://gilrs-project.gitlab.io/gilrs/img/controller.svg)
pub enum Axis {
LeftStickX = AXIS_LSTICKX,
LeftStickY = AXIS_LSTICKY,
LeftZ = AXIS_LEFTZ,
RightStickX = AXIS_RSTICKX,
RightStickY = AXIS_RSTICKY,
RightZ = AXIS_RIGHTZ,
DPadX = AXIS_DPADX,
DPadY = AXIS_DPADY,
Unknown = AXIS_UNKNOWN,
}
impl Axis {
/// Returns true if axis is `LeftStickX`, `LeftStickY`, `RightStickX` or `RightStickY`.
pub fn is_stick(self) -> bool {
use crate::Axis::*;
matches!(self, LeftStickX | LeftStickY | RightStickX | RightStickY)
}
/// Returns the other axis from same element of gamepad, if any.
///
/// | input | output |
/// |-------------|-------------------|
/// |`LeftStickX` |`Some(LeftStickY)` |
/// |`LeftStickY` |`Some(LeftStickX)` |
/// |`RightStickX`|`Some(RightStickY)`|
/// |`RightStickY`|`Some(RightStickX)`|
/// |`DpadX` |`Some(DpadY)` |
/// |`DpadY` |`Some(DpadX)` |
/// | … |`None` |
pub fn second_axis(self) -> Option<Self> {
use crate::Axis::*;
match self {
LeftStickX => Some(LeftStickY),
LeftStickY => Some(LeftStickX),
RightStickX => Some(RightStickY),
RightStickY => Some(RightStickX),
DPadX => Some(DPadY),
DPadY => Some(DPadX),
_ => None,
}
}
}
/// Represents `Axis` or `Button`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub enum AxisOrBtn {
Axis(Axis),
Btn(Button),
}
impl AxisOrBtn {
pub(crate) fn is_button(&self) -> bool {
matches!(self, AxisOrBtn::Btn(_))
}
}

230
vendor/gilrs/src/ev/state.rs vendored Normal file
View File

@@ -0,0 +1,230 @@
// Copyright 2016-2018 Mateusz Sieczko and other GilRs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use crate::ev::Code;
use fnv::FnvHashMap;
use std::collections::hash_map;
use std::iter::Iterator;
use std::time::SystemTime;
/// Cached gamepad state.
#[derive(Clone, Debug)]
pub struct GamepadState {
// Indexed by EvCode (nec)
buttons: FnvHashMap<Code, ButtonData>,
// Indexed by EvCode (nec)
axes: FnvHashMap<Code, AxisData>,
}
impl GamepadState {
pub(crate) fn new() -> Self {
GamepadState {
buttons: FnvHashMap::default(),
axes: FnvHashMap::default(),
}
}
/// Returns `true` if given button is pressed. Returns `false` if there is no information about
/// `btn` or it is not pressed.
pub fn is_pressed(&self, btn: Code) -> bool {
self.buttons
.get(&btn)
.map(|s| s.is_pressed())
.unwrap_or(false)
}
/// Returns value of `el` or 0.0 when there is no information about it. `el` can be either axis
/// or button.
pub fn value(&self, el: Code) -> f32 {
self.axes
.get(&el)
.map(|s| s.value())
.or_else(|| self.buttons.get(&el).map(|s| s.value()))
.unwrap_or(0.0)
}
/// Iterate over buttons data.
pub fn buttons(&self) -> ButtonDataIter<'_> {
ButtonDataIter(self.buttons.iter())
}
/// Iterate over axes data.
pub fn axes(&self) -> AxisDataIter<'_> {
AxisDataIter(self.axes.iter())
}
/// Returns button state and when it changed.
pub fn button_data(&self, btn: Code) -> Option<&ButtonData> {
self.buttons.get(&btn)
}
/// Returns axis state and when it changed.
pub fn axis_data(&self, axis: Code) -> Option<&AxisData> {
self.axes.get(&axis)
}
pub(crate) fn set_btn_pressed(
&mut self,
btn: Code,
pressed: bool,
counter: u64,
timestamp: SystemTime,
) {
let data = self.buttons.entry(btn).or_insert_with(|| {
ButtonData::new(
if pressed { 1.0 } else { 0.0 },
pressed,
false,
counter,
timestamp,
)
});
data.is_pressed = pressed;
data.is_repeating = false;
data.counter = counter;
data.last_event_ts = timestamp;
}
pub(crate) fn set_btn_repeating(&mut self, btn: Code, counter: u64, timestamp: SystemTime) {
let data = self
.buttons
.entry(btn)
.or_insert_with(|| ButtonData::new(1.0, true, true, counter, timestamp));
data.is_repeating = true;
data.counter = counter;
data.last_event_ts = timestamp;
}
pub(crate) fn set_btn_value(
&mut self,
btn: Code,
value: f32,
counter: u64,
timestamp: SystemTime,
) {
let data = self
.buttons
.entry(btn)
.or_insert_with(|| ButtonData::new(value, false, false, counter, timestamp));
data.value = value;
data.counter = counter;
data.last_event_ts = timestamp;
}
pub(crate) fn update_axis(&mut self, axis: Code, data: AxisData) {
self.axes.insert(axis, data);
}
}
/// Iterator over `ButtonData`.
pub struct ButtonDataIter<'a>(hash_map::Iter<'a, Code, ButtonData>);
/// Iterator over `AxisData`.
pub struct AxisDataIter<'a>(hash_map::Iter<'a, Code, AxisData>);
impl<'a> Iterator for ButtonDataIter<'a> {
type Item = (Code, &'a ButtonData);
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|(k, v)| (*k, v))
}
}
impl<'a> Iterator for AxisDataIter<'a> {
type Item = (Code, &'a AxisData);
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(|(k, v)| (*k, v))
}
}
/// Information about button stored in `State`.
#[derive(Clone, Copy, Debug)]
pub struct ButtonData {
last_event_ts: SystemTime,
counter: u64,
value: f32,
is_pressed: bool,
is_repeating: bool,
}
impl ButtonData {
pub(crate) fn new(
value: f32,
pressed: bool,
repeating: bool,
counter: u64,
time: SystemTime,
) -> Self {
ButtonData {
last_event_ts: time,
counter,
value,
is_pressed: pressed,
is_repeating: repeating,
}
}
/// Returns `true` if button is pressed.
pub fn is_pressed(&self) -> bool {
self.is_pressed
}
/// Returns value of button.
pub fn value(&self) -> f32 {
self.value
}
/// Returns `true` if button is repeating.
pub fn is_repeating(&self) -> bool {
self.is_repeating
}
/// Returns value of counter when button state last changed.
pub fn counter(&self) -> u64 {
self.counter
}
/// Returns when button state last changed.
pub fn timestamp(&self) -> SystemTime {
self.last_event_ts
}
}
/// Information about axis stored in `State`.
#[derive(Clone, Copy, Debug)]
pub struct AxisData {
last_event_ts: SystemTime,
last_event_c: u64,
value: f32,
}
impl AxisData {
pub(crate) fn new(value: f32, counter: u64, time: SystemTime) -> Self {
AxisData {
last_event_ts: time,
last_event_c: counter,
value,
}
}
/// Returns value of axis.
pub fn value(&self) -> f32 {
self.value
}
/// Returns value of counter when axis value last changed.
pub fn counter(&self) -> u64 {
self.last_event_c
}
/// Returns when axis value last changed.
pub fn timestamp(&self) -> SystemTime {
self.last_event_ts
}
}