winit_input_map/lib.rs
1#![cfg_attr(test, feature(test))]
2//! Define actions and their list of input binds. and then see if its `pressing`, `pressed` or
3//! `released`. This library handles variable pressure through the `value` function as well as
4//! multiple variable pressure inputs for things like 1d axis (through `axis`) and 2d vectors
5//! (through `dir` and `dir_max_len_1`). This makes it easy to have things like 3d camera controls
6//! applied for both mouse movement and the gamepads right stick.
7//!
8//! The binds are structured by a list of `(Action, bind, bind, ..)`. An action is pressed if any
9//! of its binds are pressed. Binds are described as either `[InputCode, InputCode, ..]` or
10//! InputCode. A bind is pressed if all its InputCodes are pressed.
11//!
12//! The input map also can get the `mouse_pos`, what was `recently_pressed` (used for rebinding
13//! things) and the `text_typed` (useful for typing) to make sure it is fully featured.
14//! For better user control there are the `mouse_scale` and `scroll_scale` variables to make
15//! sensitivity align with eveything else 0-1 range and a `press_sensitivity` to control when an
16//! action counts as being pressed. Finaly, theres an `input_map!` macro to reduce boilerplate and
17//! increase readability.
18//! ```no_run
19//! use winit::{
20//! window::*, application::*, keyboard::*,
21//! event_loop::*, event::*
22//! };
23//! use gilrs::Gilrs;
24//! use winit_input_map::*;
25//!
26//! #[derive(Hash, PartialEq, Eq, Clone, Copy)]
27//! enum Actions{ Foo }
28//! use Actions::*;
29//!
30//! let input = { use base_input_codes::*; input_map!(
31//! (Foo, KeyCode::Space, [GamepadInput::South, RightTrigger])
32//! ) };
33//! let ev = EventLoop::new().unwrap();
34//! let gilrs = Gilrs::new().unwrap();
35//! ev.run_app(&mut App { window: None, input, gilrs }).unwrap();
36//!
37//! struct App {
38//! window: Option<Window>,
39//! input: InputMap<Actions>,
40//! gilrs: Gilrs
41//! }
42//! impl ApplicationHandler for App {
43//! fn resumed(&mut self, event_loop: &ActiveEventLoop) {
44//! let window_settings = Window::default_attributes();
45//! let window = event_loop.create_window(window_settings);
46//! self.window = Some(window.unwrap());
47//! }
48//! fn window_event(
49//! &mut self, event_loop: &ActiveEventLoop, _: WindowId,
50//! event: WindowEvent
51//! ) {
52//! self.input.update_with_window_event(&event);
53//! if let WindowEvent::CloseRequested = &event
54//! { event_loop.exit() }
55//! }
56//! fn device_event(
57//! &mut self, _: &ActiveEventLoop, id: DeviceId,
58//! event: DeviceEvent
59//! ) {
60//! self.input.update_with_device_event(id, &event);
61//! }
62//! fn about_to_wait(&mut self, _: &ActiveEventLoop) {
63//! self.input.update_with_gilrs(&mut self.gilrs);
64//!
65//! // your code here!
66//! if self.input.pressed(Foo) { println!("bar") }
67//!
68//! self.input.init();
69//! }
70//! }
71//! ```
72mod input;
73mod input_code;
74pub use crate::input::*;
75pub use crate::input_code::*;
76
77/// Outputs an input with the inputed binds.
78///
79/// The input is structured by a list of `(Action, bind, bind, ..)`. An action is pressed if any of
80/// its binds are pressed.
81///
82/// Binds are described as either `[InputCode, InputCode, ..]` or InputCode. A bind is pressed if all
83/// its InputCodes are pressed.
84/// ```
85/// use winit_input_map::*;
86/// use Action::*;
87/// #[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
88/// enum Action {
89/// Select, Undo, Redo, Confirm
90/// }
91/// let input = { use base_input_codes::*; input_map!(
92/// (Select, MouseButton::Left, ShiftLeft, ShiftRight),
93/// (Action::Undo, [KeyZ, ControlLeft], [KeyZ, ControlRight]),
94/// (Redo, [KeyR, ControlLeft], [KeyR, ControlRight]),
95/// (Confirm, MouseButton::Left, Enter)
96/// ) };
97/// ```
98#[macro_export]
99macro_rules! input_map {
100 () => { $crate::InputMap::empty() };
101 ( $( $t: tt )* ) => {
102 $crate::InputMap::new(
103 &$crate::binds!($($t)*)
104 )
105 };
106}
107/// Outputs binds in the expected format for `add_binds`, `set_binds` and `InputMap::new` though in
108/// the latter case `input_map!` should be used to skip the middle man.
109///
110/// The input is structured by a list of `(Action, bind, bind, ..)`. An action is pressed if any of
111/// its binds are pressed.
112///
113/// Binds are described as either `[InputCode, InputCode, ..]` or InputCode. A bind is pressed if all
114/// its InputCodes are pressed.
115/// ```
116/// use winit_input_map::*;
117/// use Action::*;
118/// #[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
119/// enum Action {
120/// Select, Undo, Redo, Confirm
121/// }
122/// let mut input = input_map!((Select, base_input_codes::ShiftLeft));
123///
124/// let binds = { use base_input_codes::*; binds!(
125/// (Select, MouseButton::Left, ShiftRight),
126/// (Action::Undo, [KeyZ, ControlLeft], [KeyZ, ControlRight], KeyCode::Undo),
127/// (Redo, [KeyR, ControlLeft], [KeyR, ControlRight]),
128/// (Confirm, MouseButton::Left, Enter)
129/// ) };
130///
131/// input.add_binds(&binds);
132/// ```
133#[macro_export]
134macro_rules! binds {
135 ( $( ( $x: expr, $( $tail: tt )* ) ),* ) => { {
136 vec![ $(
137 ($x, $crate::binds_muncher!(vec![]; $( $tail )*))
138 ),* ]
139 } };
140}
141
142#[test]
143fn bind_muncher() {
144 use base_input_codes::*;
145 assert_eq!(
146 vec![vec![InputCode::from(KeyZ)], vec![MouseButton::Left.into(), ShiftLeft.into()], vec![KeyZ.into(), KeyI.into(), KeyF.into()]],
147 *binds_muncher!(vec![]; KeyZ, [MouseButton::Left, ShiftLeft], [KeyZ, KeyI, KeyF])
148 );
149}
150#[macro_export]
151macro_rules! binds_muncher {
152 ( @vec $v: expr; ) => { $v };
153 ( $v: expr; [ $( $x: expr ),* ] ) => { {
154 let mut v: Vec<Vec<InputCode>> = $v;
155 v.push(vec![$( InputCode::from($x) ),*]);
156 v
157 } };
158 ( $v: expr; $x: expr ) => { {
159 let mut v: Vec<Vec<InputCode>> = $v;
160 v.push(vec![InputCode::from($x)]);
161 v
162 } };
163 ( $v: expr; [ $( $x: expr ),* ], $( $tail: tt )* ) => { {
164 let mut v: Vec<Vec<InputCode>> = $v;
165 v.push(vec![$( InputCode::from($x) ),*]);
166 $crate::binds_muncher!(v; $($tail)*)
167 } };
168 ( $v: expr; $x: expr, $( $tail: tt )* ) => { {
169 let mut v: Vec<Vec<InputCode>> = $v;
170 v.push(vec![InputCode::from($x)]);
171 $crate::binds_muncher!(v; $($tail)*)
172 } };
173}