Files
rust-engine/src/input.rs
2021-08-07 16:10:06 +02:00

771 lines
32 KiB
Rust

#![allow(deprecated)]
use std::collections::{HashMap, HashSet};
use std::fs;
use std::hash::Hash;
use std::iter::FromIterator;
use cgmath::{InnerSpace, Vector2, Zero, vec2};
use gilrs;
use gilrs::{EventType, Gilrs};
use serde_derive::{Deserialize, Serialize};
use toml;
use winit::event::{DeviceEvent, ElementState, Event, ModifiersState, MouseButton, MouseScrollDelta, ScanCode, Touch, TouchPhase, WindowEvent};
use crate::config::LogConfig;
#[derive(Debug, Clone)]
pub struct VirtualButton {
pub digital_inputs: Vec<DigitalInput>,
pub touch_count: Option<u8>,
}
#[derive(Debug)]
pub struct VirtualAxis {
pub axis_inputs: Vec<AxisInput>,
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum DigitalInputEvent {
Pressed(DigitalInput),
Released(DigitalInput),
}
#[derive(Debug, Serialize, Deserialize)]
struct InputConfig {
config: InputConfigConfig,
button: Vec<InputConfigButton>,
axis: Vec<InputConfigAxis>,
}
#[derive(Debug, Serialize, Deserialize)]
struct InputConfigConfig {
line_height_px: f32,
}
#[derive(Debug, Serialize, Deserialize)]
struct InputConfigButton {
name: String,
scan_code: Option<u32>,
mouse: Option<String>,
touch: Option<u8>,
controller_button: Option<String>,
ctrl: Option<bool>,
shift: Option<bool>,
alt: Option<bool>,
logo: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize)]
struct InputConfigAxis {
name: String,
positive_button: Option<String>,
negative_button: Option<String>,
mouse_axis: Option<String>,
controller_axis: Option<String>,
touch_axis: Option<String>,
ctrl: Option<bool>,
shift: Option<bool>,
alt: Option<bool>,
logo: Option<bool>,
}
#[derive(Debug)]
pub struct InputState {
pub virtual_buttons: HashMap<String, VirtualButton>,
pub virtual_axes: HashMap<String, VirtualAxis>,
pub mouse_delta_x: f64,
pub mouse_delta_y: f64,
pub mouse_position: Vector2<f64>,
input_events: HashSet<DigitalInputEvent>,
pressed_scan_codes: HashSet<ScanCode>,
pressed_mouse_buttons: HashSet<MouseButton>,
pressed_touch_positions: HashMap<u64, Vector2<f64>>,
analog_wheel_state: f32,
config: InputConfigConfig,
log_config: LogConfig,
controller_input: Gilrs,
touch_inputs: Vec<TouchInput>
}
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub struct KeyboardModifierState {
shift: bool,
ctrl: bool,
alt: bool,
logo: bool
}
impl KeyboardModifierState {
pub fn from_deprecated_state(old_state: &ModifiersState) -> KeyboardModifierState {
KeyboardModifierState {
shift: old_state.shift(),
ctrl: old_state.ctrl(),
alt: old_state.alt(),
logo: old_state.logo()
}
}
}
impl InputState {
pub fn new(toml_path: &str, log_config: LogConfig) -> InputState {
let config: InputConfig = toml::from_slice(&fs::read(toml_path).expect("Failed to read input config!")).expect("Failed to parse input config!");
let mut state = InputState { virtual_buttons: HashMap::new(), virtual_axes: HashMap::new(),
input_events: HashSet::new(), pressed_scan_codes: HashSet::new(),
pressed_mouse_buttons: HashSet::new(), pressed_touch_positions: HashMap::new(), touch_inputs: vec![], analog_wheel_state: 0.0,
config: config.config, mouse_delta_x: 0.0, mouse_delta_y: 0.0, mouse_position: Vector2::zero(), log_config,
controller_input: Gilrs::new().unwrap() };
// Create virtual buttons from config
config.button.iter().for_each(|bn| {
let modifiers = KeyboardModifierState {
shift: bn.shift.is_some(),
ctrl: bn.ctrl.is_some(),
alt: bn.alt.is_some(),
logo: bn.logo.is_some()
};
let mut inputs = vec![];
// Keyboard buttons
if let Some(scan_code) = bn.scan_code {
inputs.push(DigitalInput::Keyboard(KeyboardInput { scan_code, modifiers: modifiers.clone() }));
}
// Mouse buttons
if let Some(button_name) = &bn.mouse {
let button_name_lower = button_name.to_lowercase();
let button_input = match button_name_lower.as_str() {
"left" => DigitalInput::Mouse(MouseInput { button: MouseButton::Left, modifiers }),
"middle" => DigitalInput::Mouse(MouseInput { button: MouseButton::Middle, modifiers }),
"right" => DigitalInput::Mouse(MouseInput { button: MouseButton::Right, modifiers }),
"wheelup" => DigitalInput::Wheel(WheelInput { direction: WheelInputDirection::Up, modifiers }),
"wheeldown" => DigitalInput::Wheel(WheelInput { direction: WheelInputDirection::Down, modifiers }),
other => DigitalInput::Mouse(MouseInput { button: MouseButton::Other(other.parse().expect(&format!("Unknown button: {:?}", other))), modifiers }),
};
inputs.push(button_input);
}
// Controller buttons
if let Some(controller_button) = &bn.controller_button {
inputs.push(DigitalInput::Controller(ControllerInput {
button: string_to_button(controller_button.as_str()).expect(&format!("Unknown controller button: {}", controller_button.as_str()))
}));
}
// Touch clicks
if let Some(_) = bn.touch {
if let Some(virtual_button) = state.virtual_buttons.get_mut(&bn.name) {
virtual_button.touch_count = bn.touch;
} else {
state.virtual_buttons.insert(bn.name.clone(), VirtualButton { digital_inputs: vec![], touch_count: bn.touch });
}
}
// Insert digital inputs
for input in inputs {
if let Some(virtual_button) = state.virtual_buttons.get_mut(&bn.name) {
virtual_button.digital_inputs.push(input);
} else {
state.virtual_buttons.insert(bn.name.clone(), VirtualButton { digital_inputs: vec![input], touch_count: bn.touch });
}
}
});
// Create virtual axes from config
config.axis.iter().for_each(|axis| {
let axis_input = match axis {
InputConfigAxis { positive_button: Some(pos_button_name), negative_button: Some(neg_button_name), .. } => {
let positive_button = state.virtual_buttons.get(pos_button_name)
.expect(&format!("Button {:?} of axis {:?} not found!", axis.positive_button, axis.name))
.clone();
let negative_button = state.virtual_buttons.get(neg_button_name)
.expect(&format!("Button {:?} of axis {:?} not found!", axis.positive_button, axis.name))
.clone();
AxisInput::Digital(positive_button, negative_button)
},
InputConfigAxis { mouse_axis: Some(axis_name), .. } => {
let modifiers = KeyboardModifierState {
shift: axis.shift.is_some(),
ctrl: axis.ctrl.is_some(),
alt: axis.alt.is_some(),
logo: axis.logo.is_some(),
};
match axis_name.to_lowercase().as_str() {
"wheel" => AxisInput::Wheel(modifiers),
"x" => AxisInput::MouseMove(MouseMoveDirection::X, modifiers),
"y" => AxisInput::MouseMove(MouseMoveDirection::Y, modifiers),
other => panic!("Axis {:?} has unknown mouse axis name {:?}!", axis_name, other),
}
},
InputConfigAxis { controller_axis: Some(controller_axis_name), .. } => {
AxisInput::Controller(AnalogControllerInput { axis: string_to_axis(controller_axis_name).expect(&format!("Unknown controller axis: {}", controller_axis_name)) })
},
InputConfigAxis { touch_axis: Some(touch_axis_name), .. } => {
if let Some(axis) = string_to_touch_axis(touch_axis_name) {
AxisInput::Touch(axis)
} else {
panic!("Unknown touch axis {:?}", touch_axis_name);
}
},
other => panic!("Axis {:?} needs either (positive_button and negative_button) or (touch_axis) or (mouse_wheel) or (controller_axis must be set to true)", other.name)
};
if let Some(virtual_axis) = state.virtual_axes.get_mut(&axis.name) {
virtual_axis.axis_inputs.push(axis_input);
} else {
state.virtual_axes.insert(axis.name.clone(), VirtualAxis { axis_inputs: vec![axis_input] });
}
});
return state;
}
pub fn on_window_event(self: &mut Self, event: &Event<()>) {
match event {
Event::WindowEvent { event: WindowEvent::KeyboardInput { device_id, input, .. }, .. } => {
if self.log_config.input.buttons {
let mods = mods_to_string(&KeyboardModifierState::from_deprecated_state(&input.modifiers));
if mods.len() > 0 {
println!("Keyboard {:?} {:?} {:?} + {:?} {:?}", device_id, input.state, &mods, input.virtual_keycode, input.scancode)
} else {
println!("Keyboard {:?} {:?} {:?} {:?}", device_id, input.state, input.virtual_keycode, input.scancode)
}
}
self.on_keyboard_event(input.state, input.scancode, KeyboardModifierState::from_deprecated_state(&input.modifiers));
},
Event::WindowEvent { event: WindowEvent::MouseInput { device_id, state, button, modifiers }, .. } => {
if self.log_config.input.buttons {
let mods = mods_to_string(&KeyboardModifierState::from_deprecated_state(&modifiers));
if mods.len() > 0 {
println!("Mouse {:?} {:?} {:?} + {:?}", device_id, state, &mods, button)
} else {
println!("Mouse {:?} {:?} {:?}", device_id, state, button)
}
}
self.on_mouse_event(state, button, &KeyboardModifierState::from_deprecated_state(&modifiers));
},
Event::WindowEvent { event: WindowEvent::MouseWheel { device_id, delta, phase, modifiers }, .. } => {
if self.log_config.input.buttons {
let mods = mods_to_string(&KeyboardModifierState::from_deprecated_state(&modifiers));
if mods.len() > 0 {
println!("Scroll {:?} {:?} {:?} + {:?}", device_id, phase, &mods, delta)
} else {
println!("Scroll {:?} {:?} {:?}", device_id, phase, delta)
}
}
self.on_mouse_wheel_event(delta, &KeyboardModifierState::from_deprecated_state(&modifiers));
},
Event::DeviceEvent { device_id, event: DeviceEvent::MouseMotion { delta: (delta_x, delta_y) } } => {
if self.log_config.input.mouse_motion {
println!("MouseMotion {:?}, ({:?},{:?})", device_id, delta_x, delta_y);
}
self.mouse_delta_x += *delta_x;
self.mouse_delta_y += *delta_y;
},
Event::WindowEvent { event: WindowEvent::CursorMoved { position, .. }, .. } => {
self.mouse_position = vec2(position.x, position.y);
},
Event::WindowEvent { event: WindowEvent::Touch(touch), .. } => {
if self.log_config.input.touch {
println!("Touch {:?}, at {:?}, id: {:?}, force: {:?}", touch.phase, touch.location, touch.id, touch.force);
}
self.on_touch_event(touch);
},
_ => {}
}
}
pub fn button_down(self: &Self, button_code: &str) -> bool {
match self.virtual_buttons.get(button_code) {
Some(virtual_button) => {
if let Some(count) = virtual_button.touch_count {
if self.pressed_touch_positions.len() == count as usize {
return true;
}
}
virtual_button.digital_inputs.iter().any(|vi| self.digital_input_pressed(vi))
}
None => {
if self.log_config.input.buttons {
println!("Button {:?} not found!", button_code);
}
false
}
}
}
pub fn button_just_pressed(self: &Self, button_code: &str) -> bool {
match self.virtual_buttons.get(button_code) {
Some(virtual_button) => {
if let Some(count) = virtual_button.touch_count {
if self.pressed_touch_positions.len() == count as usize
&& self.touch_inputs.iter().any(|ti| ti.phase == TouchPhase::Started) {
return true;
}
}
self.input_events.iter().any(|input_event| {
if let DigitalInputEvent::Pressed(digital_input) = input_event {
virtual_button.digital_inputs.iter().any(|virtual_button_input| virtual_button_input == digital_input)
} else {
false
}
})
}
None => {
if self.log_config.input.missing_bindings {
println!("Button {:?} not found!", button_code);
}
false
}
}
}
pub fn button_just_released(self: &Self, button_code: &str) -> bool {
match self.virtual_buttons.get(button_code) {
Some(virtual_button) => {
if let Some(count) = virtual_button.touch_count {
if self.pressed_touch_positions.len() < count as usize
&& self.touch_inputs.iter().any(|ti| ti.phase == TouchPhase::Ended) {
return true;
}
}
self.input_events.iter().any(|input_event| {
if let DigitalInputEvent::Released(digital_input) = input_event {
virtual_button.digital_inputs.iter().any(|virtual_button_input| virtual_button_input == digital_input)
} else {
false
}
})
}
None => {
if self.log_config.input.missing_bindings {
println!("Button {:?} not found!", button_code);
}
false
}
}
}
fn get_touch_drag_distance(&self) -> Vector2<f64> {
if let Some(old_pos) = self.pressed_touch_positions.values().next() {
if let Some(newest_input) = self.touch_inputs.iter().filter(|ti| ti.phase == TouchPhase::Started || ti.phase == TouchPhase::Moved).last() {
newest_input.touch_location - old_pos
} else {
vec2(0.0, 0.0)
}
} else {
vec2(0.0, 0.0)
}
}
pub fn get_axis(self: &Self, axis_code: &str) -> f32 {
if let Some(axis) = self.virtual_axes.get(axis_code) {
axis.axis_inputs.iter().map(|item| {
match &item {
AxisInput::Wheel(modifiers) => {
if self.modifiers_are_pressed(modifiers) { self.analog_wheel_state } else { 0.0 }
},
AxisInput::MouseMove(direction, modifiers) => {
if self.modifiers_are_pressed(modifiers) {
match direction {
MouseMoveDirection::X => self.mouse_delta_x as f32,
MouseMoveDirection::Y => self.mouse_delta_y as f32,
}
} else {
0.0
}
},
AxisInput::Digital(positive_button, negative_button) => {
self.virtual_button_to_float(positive_button) - self.virtual_button_to_float(negative_button)
},
AxisInput::Controller(controller_input) => {
self.controller_input.gamepads()
.map(|(_id, gamepad)| gamepad.value(controller_input.axis))
.fold(0.0, fold_axis_value)
},
&AxisInput::Touch(touch_axis) => {
match touch_axis {
TouchAxis::Horizontal => {
if self.pressed_touch_positions.len() == 1 {
self.get_touch_drag_distance().x as f32
} else {
0.0
}
},
TouchAxis::Vertical => {
if self.pressed_touch_positions.len() == 1 {
self.get_touch_drag_distance().y as f32
} else {
0.0
}
},
TouchAxis::Rotate => {
if self.pressed_touch_positions.len() == 2 {
let mut positions = self.pressed_touch_positions.iter();
let (id_1, pos_1) = positions.next().unwrap();
let (id_2, pos_2) = positions.next().unwrap();
let mut touch_loc_1 = vec2(0., 0.);
let mut touch_loc_2 = vec2(0., 0.);
let mut touch_1 = None;
let mut touch_2 = None;
fn filtered_vector_sub(a: Vector2<f64>, b: &Vector2<f64>) -> Option<Vector2<f64>> {
Some(a - b).filter(|v| v.magnitude() > 0.01)
}
for input in &self.touch_inputs {
if input.id == *id_1 {
touch_1 = filtered_vector_sub(input.touch_location, &pos_1);
touch_loc_1 = input.touch_location;
}
if input.id == *id_2 {
touch_2 = filtered_vector_sub(input.touch_location, &pos_2);
touch_loc_2 = input.touch_location;
}
}
let diff = touch_loc_2 - touch_loc_1;
let norm_n = vec2(-diff.y, diff.x).normalize();
match (touch_1, touch_2) {
(Some(v1), Some(v2)) => {
let v1_n = v1.normalize();
let v2_n = v2.normalize();
let direction = v1_n.dot(norm_n) - v2_n.dot(norm_n);
let distance = (v1.magnitude() + v2.magnitude()) / 2.;
(direction * distance) as f32
},
(Some(v1), None) => {
let direction = v1.normalize().dot(norm_n);
(direction * v1.magnitude()) as f32
},
(None, Some(v2)) => {
let direction = v2.normalize().dot(norm_n);
(-direction * v2.magnitude()) as f32
},
(None, None) => { 0.0 }
}
} else {
0.0
}
},
}
},
}
}).fold(0.0, fold_axis_value)
} else {
if self.log_config.input.missing_bindings {
println!("Axis {:?} not found!", axis_code);
}
0.0
}
}
pub fn digital_input_pressed(self: &Self, digital_input: &DigitalInput) -> bool {
match digital_input {
DigitalInput::Keyboard(keyboard_input) => {
self.pressed_scan_codes.contains(&keyboard_input.scan_code)
&& self.modifiers_are_pressed(&keyboard_input.modifiers)
},
DigitalInput::Mouse(mouse_input) => {
self.pressed_mouse_buttons.contains(&mouse_input.button)
&& self.modifiers_are_pressed(&mouse_input.modifiers)
},
DigitalInput::Wheel(wheel_input) => {
self.input_events.contains(&DigitalInputEvent::Pressed(DigitalInput::Wheel(wheel_input.clone())))
},
DigitalInput::Controller(controller_input) => {
self.controller_input.gamepads().any(|(_id, gamepad)| gamepad.is_pressed(controller_input.button))
}
}
}
fn modifiers_are_pressed(self: &Self, modifiers: &KeyboardModifierState) -> bool {
(!modifiers.ctrl || self.pressed_scan_codes.contains(&29))
&& (!modifiers.shift || self.pressed_scan_codes.contains(&42) || self.pressed_scan_codes.contains(&54))
&& (!modifiers.alt || self.pressed_scan_codes.contains(&56))
&& (!modifiers.logo || self.pressed_scan_codes.contains(&91) || self.pressed_scan_codes.contains(&92))
}
fn virtual_button_to_float(self: &Self, input: &VirtualButton) -> f32 {
if input.digital_inputs.iter().any(|di| self.digital_input_pressed(di)) { 1.0 } else { 0.0 }
}
pub fn on_keyboard_event(self: &mut Self, state: ElementState, scan_code: ScanCode, modifiers: KeyboardModifierState) {
let input = DigitalInput::Keyboard(KeyboardInput { scan_code, modifiers });
match state {
ElementState::Pressed => {
if self.pressed_scan_codes.contains(&scan_code) { return; }
self.input_events.insert(DigitalInputEvent::Pressed(input));
self.pressed_scan_codes.insert(scan_code);
},
ElementState::Released => {
self.input_events.insert(DigitalInputEvent::Released(input));
self.pressed_scan_codes.remove(&scan_code);
},
}
}
pub fn on_mouse_event(self: &mut Self, state: &ElementState, button: &MouseButton, modifiers: &KeyboardModifierState) {
let input = DigitalInput::Mouse(MouseInput { button: button.clone(), modifiers: modifiers.clone() });
match state {
ElementState::Pressed => {
self.input_events.insert(DigitalInputEvent::Pressed(input));
self.pressed_mouse_buttons.insert(button.clone());
},
ElementState::Released => {
self.input_events.insert(DigitalInputEvent::Released(input));
self.pressed_mouse_buttons.remove(button);
},
}
}
pub fn on_mouse_wheel_event(self: &mut Self, delta: &MouseScrollDelta, modifiers: &KeyboardModifierState) {
let vertical_direction = match delta {
MouseScrollDelta::LineDelta(_x, y) => {
if *y > 0.0 { Some(WheelInputDirection::Up) }
else if *y < 0.0 { Some(WheelInputDirection::Down) }
else { None }
},
MouseScrollDelta::PixelDelta(pixels) => {
if pixels.y > 0.0 { Some(WheelInputDirection::Up) }
else if pixels.y < 0.0 { Some(WheelInputDirection::Down) }
else { None }
}
};
if let Some(direction) = vertical_direction {
let input = DigitalInput::Wheel(WheelInput { direction, modifiers: modifiers.clone() });
self.input_events.insert(DigitalInputEvent::Pressed(input.clone()));
self.input_events.insert(DigitalInputEvent::Released(input));
}
self.analog_wheel_state = match delta {
MouseScrollDelta::LineDelta(_x, y) => *y * self.config.line_height_px,
MouseScrollDelta::PixelDelta(pixels) => pixels.y as f32,
};
}
pub fn on_touch_event(&mut self, event: &Touch) {
self.mouse_position = vec2(event.location.x, event.location.y);
match event.phase {
winit::event::TouchPhase::Started => {
self.pressed_touch_positions.insert(event.id, self.mouse_position);
self.touch_inputs.push(TouchInput { id: event.id, touch_location: self.mouse_position, phase: event.phase });
},
winit::event::TouchPhase::Moved => {
self.touch_inputs.push(TouchInput { id: event.id, touch_location: self.mouse_position, phase: event.phase });
},
winit::event::TouchPhase::Ended => {
self.pressed_touch_positions.remove(&event.id);
self.touch_inputs.push(TouchInput { id: event.id, touch_location: self.mouse_position, phase: event.phase });
},
winit::event::TouchPhase::Cancelled => {
self.pressed_touch_positions.remove(&event.id);
},
}
}
pub fn frame_start(self: &mut Self) {
// Read out all controller events
while let Some(event) = self.controller_input.next_event() {
match event.event {
EventType::ButtonPressed(button, _) => {
if self.log_config.input.buttons { println!("ControllerButton Pressed {:?} {:?}", event.id, button); }
self.input_events.insert(DigitalInputEvent::Pressed(DigitalInput::Controller(ControllerInput { button })));
},
EventType::ButtonRepeated(_, _) => {},
EventType::ButtonReleased(button, _) => {
if self.log_config.input.buttons { println!("ControllerButton Released {:?} {:?}", event.id, button); }
self.input_events.insert(DigitalInputEvent::Released(DigitalInput::Controller(ControllerInput { button })));
},
EventType::ButtonChanged(_, _, _) => {},
EventType::AxisChanged(axis, value, _) => {
if self.log_config.input.buttons { println!("ControllerAxis {:?} {:?} {:?}", event.id, axis, value); }
},
EventType::Connected => {},
EventType::Disconnected => {},
EventType::Dropped => {},
}
}
}
pub fn frame_end(self: &mut Self) {
self.analog_wheel_state = 0.0;
self.mouse_delta_x = 0.0;
self.mouse_delta_y = 0.0;
self.input_events.clear();
// Store final touch positions as base for next frame
for touch_input in &mut self.touch_inputs {
self.pressed_touch_positions.get_mut(&touch_input.id).map(|pos| *pos = touch_input.touch_location);
}
self.touch_inputs.clear();
}
}
fn mods_to_string(modifiers: &KeyboardModifierState) -> String {
String::from_iter(
vec!["shift", "ctrl", "alt", "logo"].iter()
.zip(vec![modifiers.shift, modifiers.ctrl, modifiers.alt, modifiers.logo])
.filter(|(&_name, state)| *state)
.map(|(&name, _state)| name))
}
#[derive(Debug)]
pub enum AxisInput {
Wheel(KeyboardModifierState),
MouseMove(MouseMoveDirection, KeyboardModifierState),
Digital(VirtualButton, VirtualButton),
Controller(AnalogControllerInput),
Touch(TouchAxis)
}
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub enum DigitalInput {
Keyboard(KeyboardInput),
Wheel(WheelInput),
Mouse(MouseInput),
Controller(ControllerInput),
}
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub struct KeyboardInput {
scan_code: ScanCode,
modifiers: KeyboardModifierState,
}
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub struct MouseInput {
button: MouseButton,
modifiers: KeyboardModifierState,
}
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub struct WheelInput {
direction: WheelInputDirection,
modifiers: KeyboardModifierState,
}
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub struct ControllerInput {
button: gilrs::Button,
}
#[derive(Debug, Clone)]
pub struct TouchInput {
id: u64,
touch_location: Vector2<f64>,
phase: TouchPhase
}
impl Eq for TouchInput {}
impl PartialEq for TouchInput {
fn eq(&self, other: &Self) -> bool {
self.id.eq(&other.id) && self.phase.eq(&other.phase)
}
}
impl Hash for TouchInput {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
state.write_u64(self.id);
self.phase.hash(state)
}
}
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub enum TouchAxis {
Horizontal,
Vertical,
Rotate
}
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub enum WheelInputDirection {
Up,
Down,
}
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub enum MouseMoveDirection {
X,
Y,
}
#[derive(Debug, PartialEq, Clone)]
pub struct AnalogWheelInput {
value: f32,
modifiers: KeyboardModifierState,
}
#[derive(Debug, PartialEq, Clone)]
pub struct AnalogControllerInput {
axis: gilrs::Axis,
}
fn fold_axis_value(fold: f32, it: f32) -> f32 {
if f32::abs(it) > f32::abs(fold) { it } else { fold }
}
fn string_to_button(button_name: &str) -> Option<gilrs::Button> {
match button_name {
"South" => Some(gilrs::Button::South),
"East" => Some(gilrs::Button::East),
"North" => Some(gilrs::Button::North),
"West" => Some(gilrs::Button::West),
"C" => Some(gilrs::Button::C),
"Z" => Some(gilrs::Button::Z),
// Triggers
"LeftTrigger" => Some(gilrs::Button::LeftTrigger),
"LeftTrigger2" => Some(gilrs::Button::LeftTrigger2),
"RightTrigger" => Some(gilrs::Button::RightTrigger),
"RightTrigger2" => Some(gilrs::Button::RightTrigger2),
// Menu Pad
"Select" => Some(gilrs::Button::Select),
"Start" => Some(gilrs::Button::Start),
"Mode" => Some(gilrs::Button::Mode),
// Sticks
"LeftThumb" => Some(gilrs::Button::LeftThumb),
"RightThumb" => Some(gilrs::Button::RightThumb),
// D-Pad
"DPadUp" => Some(gilrs::Button::DPadUp),
"DPadDown" => Some(gilrs::Button::DPadDown),
"DPadLeft" => Some(gilrs::Button::DPadLeft),
"DPadRight" => Some(gilrs::Button::DPadRight),
_ => None,
}
}
fn string_to_axis(axis_name: &str) -> Option<gilrs::Axis> {
match axis_name {
"LeftStickX" => Some(gilrs::Axis::LeftStickX),
"LeftStickY" => Some(gilrs::Axis::LeftStickY),
"LeftZ" => Some(gilrs::Axis::LeftZ),
"RightStickX" => Some(gilrs::Axis::RightStickX),
"RightStickY" => Some(gilrs::Axis::RightStickY),
"RightZ" => Some(gilrs::Axis::RightZ),
"DPadX" => Some(gilrs::Axis::DPadX),
"DPadY" => Some(gilrs::Axis::DPadY),
_ => None,
}
}
fn string_to_touch_axis(touch_axis_name: &str) -> Option<TouchAxis> {
match touch_axis_name {
"horizontal" => Some(TouchAxis::Horizontal),
"vertical" => Some(TouchAxis::Vertical),
"rotate" => Some(TouchAxis::Rotate),
_ => None,
}
}