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}