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    ( $( ( $x: expr, $( $k: expr ),* ) ),* ) => {
102        $crate::InputMap::new(
103            &$crate::binds!($(
104                ($x, $( $k ),* )
105            ),*)
106        )
107    };
108}
109/// Outputs binds in the expected format for `add_binds`, `set_binds` and `InputMap::new` though in
110/// the latter case `input_map!` should be used to skip the middle man.
111///
112/// The input is structured by a list of `(Action, bind, bind, ..)`. An action is pressed if any of
113/// its binds are pressed.
114///
115/// Binds are described as either `[InputCode, InputCode, ..]` or InputCode. A bind is pressed if all
116/// its InputCodes are pressed.
117/// ```
118/// use winit_input_map::*;
119/// use Action::*;
120/// #[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
121/// enum Action {
122///     Select, Undo, Redo, Confirm
123/// }
124/// let mut input = input_map!((Select, base_input_codes::ShiftLeft));
125///
126/// let binds = { use base_input_codes::*; binds!(
127///     (Select, MouseButton::Left, ShiftRight),
128///     (Action::Undo,  [KeyZ, ControlLeft], [KeyZ, ControlRight]),
129///     (Redo,  [KeyR, ControlLeft], [KeyR, ControlRight]),
130///     (Confirm, MouseButton::Left, Enter)
131/// ) };
132///
133/// input.add_binds(&binds);
134/// ```
135#[macro_export]
136macro_rules! binds {
137    ( $( ( $x: expr, $( $k: expr ),* ) ),* ) => { {
138        $crate::as_binds(&[ $(
139                ($x, &[ $( (&$k as &dyn $crate::AsBind) ),* ])
140        ),* ])
141    } };
142}
143/// Takes in more flexible deffinition of binds, the `binds!` macro is however, still prefered.
144pub fn as_binds<'a, F: std::hash::Hash + Copy>(binds: &'a [(F, &'a [&'a dyn AsBind])]) -> crate::Binds<F> {
145    let mut result = Vec::new();
146    for (action, binds) in binds {
147        let mut sub_result = Vec::new();
148        for bind in *binds {
149            sub_result.push(bind.as_bind());
150        }
151        result.push((*action, sub_result));
152    }
153    result
154}
155
156trait AsInputCode { fn as_code(&self) -> InputCode; }
157impl<T: Into<InputCode> + Copy> AsInputCode for T { fn as_code(&self) -> InputCode { (*self).into() } }
158
159/// Dictates what can be turned into binds for the purposes of the `as_binds()` method and the
160/// `binds!()` and `input_map!()` macros
161pub trait AsBind { fn as_bind(&self) -> Vec<InputCode>; }
162impl<T: AsInputCode> AsBind for T { fn as_bind(&self) -> Vec<InputCode> { vec![self.as_code()] } }
163impl<T: AsInputCode, const X: usize> AsBind for [T; X] { 
164    fn as_bind(&self) -> Vec<InputCode> {
165        let mut result = Vec::new();
166        for i in self {
167            let bind: InputCode = i.as_code();
168            result.push(bind);
169        }
170        result
171    }
172}
173impl<T: AsInputCode> AsBind for [T] { 
174    fn as_bind(&self) -> Vec<InputCode> {
175        let mut result = Vec::new();
176        for i in self {
177            let bind: InputCode = i.as_code();
178            result.push(bind);
179        }
180        result
181    }
182}
183impl<T: AsInputCode> AsBind for &[T] { 
184fn as_bind(&self) -> Vec<InputCode> {
185    let mut result = Vec::new();
186    for i in *self {
187        let bind: InputCode = i.as_code();
188        result.push(bind);
189    }
190    result
191}
192}
193impl AsBind for Vec<&dyn AsInputCode> {
194    fn as_bind(&self) -> Vec<InputCode> {
195        let mut result = Vec::new();
196        for i in self {
197            let bind: InputCode = i.as_code();
198            result.push(bind);
199        }
200        result
201    }
202}
203impl AsBind for &[&dyn AsInputCode] {
204    fn as_bind(&self) -> Vec<InputCode> {
205        let mut result = Vec::new();
206        for i in *self {
207            let bind: InputCode = i.as_code();
208            result.push(bind);
209        }
210        result
211    }
212}
213impl AsBind for [&dyn AsInputCode] {
214    fn as_bind(&self) -> Vec<InputCode> {
215        let mut result = Vec::new();
216        for i in self {
217            let bind: InputCode = i.as_code();
218            result.push(bind);
219        }
220        result
221    }
222}
223impl<const X: usize> AsBind for &[&dyn AsInputCode; X] {
224    fn as_bind(&self) -> Vec<InputCode> {
225        let mut result = Vec::new();
226        for i in *self {
227            let bind: InputCode = i.as_code();
228            result.push(bind);
229        }
230        result
231    }
232}
233impl<const X: usize> AsBind for [&dyn AsInputCode; X] {
234    fn as_bind(&self) -> Vec<InputCode> {
235        let mut result = Vec::new();
236        for i in self {
237            let bind: InputCode = i.as_code();
238            result.push(bind);
239        }
240        result
241    }
242}