bevy_trackball/controller/
input.rs

1use bevy::prelude::*;
2use trackball::Fixed;
3
4/// Trackball controller input mappings and settings.
5#[derive(Component, Debug, Clone)]
6pub struct TrackballInput {
7	/// Trackball velocity for time-based input like pressed keys.
8	pub velocity: TrackballVelocity,
9	/// Wheel unit for coherent scaling. Default is 24 clicks per turn.
10	///
11	/// Device dependent setting as mouse wheel events usually lack a reference unit.
12	pub wheel_unit: TrackballWheelUnit,
13
14	/// Transmission ratio of movement to input for look around by key. Default is `1.0`.
15	///
16	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
17	pub first_key_transmission: f32,
18	/// Transmission ratio of movement to input for orbit by key. Default is `1.0`.
19	///
20	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
21	pub orbit_key_transmission: f32,
22	/// Transmission ratio of movement to input for screw/roll by key. Default is `1.0`.
23	///
24	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
25	pub screw_key_transmission: f32,
26	/// Transmission ratio of movement to input for slide by key. Default is `1.0`.
27	///
28	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
29	pub slide_key_transmission: f32,
30	/// Transmission ratio of movement to input for scale by key. Default is `1.0`.
31	///
32	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
33	pub scale_key_transmission: f32,
34
35	/// Transmission ratio of movement to input for look around by mouse. Default is `1.0`.
36	///
37	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
38	pub first_mouse_transmission: f32,
39	/// Transmission ratio of movement to input for orbit by mouse. Default is `1.0`.
40	///
41	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
42	pub orbit_mouse_transmission: f32,
43	/// Transmission ratio of movement to input for slide by mouse. Default is `1.0`.
44	///
45	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
46	pub slide_mouse_transmission: f32,
47	/// Transmission ratio of movement to input for scale by wheel. Default is `1.0`.
48	///
49	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
50	pub scale_wheel_transmission: f32,
51
52	/// Transmission ratio of movement to input for look around by touch. Default is `1.0`.
53	///
54	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
55	pub first_touch_transmission: f32,
56	/// Transmission ratio of movement to input for orbit by touch. Default is `1.0`.
57	///
58	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
59	pub orbit_touch_transmission: f32,
60	/// Transmission ratio of movement to input for screw/roll by touch. Default is `1.0`.
61	///
62	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
63	pub screw_touch_transmission: f32,
64	/// Transmission ratio of movement to input for slide by touch. Default is `1.0`.
65	///
66	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
67	pub slide_touch_transmission: f32,
68	/// Transmission ratio of movement to input for scale by touch. Default is `1.0`.
69	///
70	/// Values unequal the default deviate from coherence as in movement equals ratio times input.
71	pub scale_touch_transmission: f32,
72
73	/// Enables focus operation. Default is `true`.
74	///
75	/// Whether to slide towards mouse or single-finger touch position when [`Self::orbit_button`]
76	/// is just pressed and released again or single-finger gesture is just started and ended again.
77	/// Moving the cursor/finger slightly between pressed/started and released/ended events discards
78	/// the focus operation in favor of the orbit operation.
79	pub focus: bool,
80
81	/// Key used to toggle `esdf`/`wasd` mapping. Default is [`KeyCode::KeyM`].
82	pub gamer_key: Option<KeyCode>,
83	/// Key used to toggle projection mode. Default is [`KeyCode::KeyP`].
84	pub ortho_key: Option<KeyCode>,
85
86	/// Key used to reset frame. Default is [`KeyCode::Enter`].
87	pub reset_key: Option<KeyCode>,
88
89	/// Mouse button used to look around. Default is [`MouseButton::Middle`].
90	pub first_button: Option<MouseButton>,
91	/// Key used to look around with single-finger touch. Default is [`KeyCode::ShiftLeft`].
92	pub first_key: Option<KeyCode>,
93	/// Key used to look left. Default is [`KeyCode::ArrowLeft`].
94	pub first_left_key: Option<KeyCode>,
95	/// Key used to look right. Default is [`KeyCode::ArrowRight`].
96	pub first_right_key: Option<KeyCode>,
97	/// Key used to look up. Default is [`KeyCode::ArrowUp`].
98	pub first_up_key: Option<KeyCode>,
99	/// Key used to look down. Default is [`KeyCode::ArrowDown`].
100	pub first_down_key: Option<KeyCode>,
101
102	/// Mouse button used to orbit camera. Default is [`MouseButton::Left`].
103	pub orbit_button: Option<MouseButton>,
104	/// Key used to screw/roll left. Default is [`KeyCode::KeyU`].
105	pub screw_left_key: Option<KeyCode>,
106	/// Key used to screw/roll right. Default is [`KeyCode::KeyO`].
107	pub screw_right_key: Option<KeyCode>,
108	/// Key used to orbit left. Default is [`KeyCode::KeyJ`].
109	pub orbit_left_key: Option<KeyCode>,
110	/// Key used to orbit right. Default is [`KeyCode::KeyL`].
111	pub orbit_right_key: Option<KeyCode>,
112	/// Key used to orbit up. Default is [`KeyCode::KeyI`].
113	pub orbit_up_key: Option<KeyCode>,
114	/// Key used to orbit down. Default is [`KeyCode::KeyK`].
115	pub orbit_down_key: Option<KeyCode>,
116
117	/// Mouse button used to slide camera. Default is [`MouseButton::Right`].
118	pub slide_button: Option<MouseButton>,
119	/// Key used to slide left. Default is [`KeyCode::KeyS`].
120	pub slide_left_key: Option<KeyCode>,
121	/// Key used to slide right. Default is [`KeyCode::KeyF`].
122	pub slide_right_key: Option<KeyCode>,
123	/// Key used to slide up. Default is [`KeyCode::KeyE`].
124	pub slide_up_key: Option<KeyCode>,
125	/// Key used to slide up. Default is [`KeyCode::KeyD`].
126	pub slide_down_key: Option<KeyCode>,
127	/// Key used to slide far. Default is [`KeyCode::KeyG`].
128	pub slide_far_key: Option<KeyCode>,
129	/// Key used to slide near. Default is [`KeyCode::KeyV`].
130	pub slide_near_key: Option<KeyCode>,
131
132	/// Key used to scale/zoom in. Default is [`KeyCode::KeyH`].
133	pub scale_in_key: Option<KeyCode>,
134	/// Key used to scale/zoom out. Default is [`KeyCode::KeyN`].
135	pub scale_out_key: Option<KeyCode>,
136}
137
138impl TrackballInput {
139	/// Maps `esdf`/`gv` to slide operations.
140	///
141	/// Key | Operation
142	/// --- | ---------------------------
143	/// `e` | Slides up.
144	/// `s` | Slides left.
145	/// `d` | Slides down.
146	/// `f` | Slides right.
147	/// `g` | Slides far (in/forward).
148	/// `v` | Slides near (out/backward).
149	///
150	/// This mapping is symmetric to the `ijkl`/`hn` orbit mapping but less intuitive to gamers
151	/// compared with [`Self::map_wasd`].
152	pub const fn map_esdf(&mut self) {
153		self.slide_up_key = Some(KeyCode::KeyE);
154		self.slide_down_key = Some(KeyCode::KeyD);
155		self.slide_left_key = Some(KeyCode::KeyS);
156		self.slide_right_key = Some(KeyCode::KeyF);
157		self.slide_far_key = Some(KeyCode::KeyG);
158		self.slide_near_key = Some(KeyCode::KeyV);
159	}
160	/// Maps `wasd`/`Space`/`ControlLeft` to slide operations.
161	///
162	/// Key           | Operation
163	/// ------------- | ---------------------------
164	/// `w`           | Slides far (in/forward).
165	/// `a`           | Slides left.
166	/// `s`           | Slides near (out/backward).
167	/// `d`           | Slides right.
168	/// `Space`       | Slides up (jump).
169	/// `ControlLeft` | Slides down (crouch).
170	///
171	/// This mapping isn't symmetric to the `ijkl`/`hn` orbit mapping but more intuitive to gamers
172	/// compared with [`Self::map_esdf`].
173	pub const fn map_wasd(&mut self) {
174		self.slide_up_key = Some(KeyCode::Space);
175		self.slide_down_key = Some(KeyCode::ControlLeft);
176		self.slide_left_key = Some(KeyCode::KeyA);
177		self.slide_right_key = Some(KeyCode::KeyD);
178		self.slide_far_key = Some(KeyCode::KeyW);
179		self.slide_near_key = Some(KeyCode::KeyS);
180	}
181}
182
183impl Default for TrackballInput {
184	fn default() -> Self {
185		Self {
186			velocity: TrackballVelocity::default(),
187			wheel_unit: TrackballWheelUnit::default(),
188
189			first_key_transmission: 1.0,
190			orbit_key_transmission: 1.0,
191			screw_key_transmission: 1.0,
192			slide_key_transmission: 1.0,
193			scale_key_transmission: 1.0,
194
195			first_mouse_transmission: 1.0,
196			orbit_mouse_transmission: 1.0,
197			slide_mouse_transmission: 1.0,
198			scale_wheel_transmission: 1.0,
199
200			first_touch_transmission: 1.0,
201			orbit_touch_transmission: 1.0,
202			screw_touch_transmission: 1.0,
203			slide_touch_transmission: 1.0,
204			scale_touch_transmission: 1.0,
205
206			focus: true,
207
208			gamer_key: Some(KeyCode::KeyM),
209
210			ortho_key: Some(KeyCode::KeyP),
211
212			reset_key: Some(KeyCode::Enter),
213
214			first_key: Some(KeyCode::ShiftLeft),
215			first_button: Some(MouseButton::Middle),
216			first_left_key: Some(KeyCode::ArrowLeft),
217			first_right_key: Some(KeyCode::ArrowRight),
218			first_up_key: Some(KeyCode::ArrowUp),
219			first_down_key: Some(KeyCode::ArrowDown),
220
221			orbit_button: Some(MouseButton::Left),
222			screw_left_key: Some(KeyCode::KeyU),
223			screw_right_key: Some(KeyCode::KeyO),
224			orbit_left_key: Some(KeyCode::KeyJ),
225			orbit_right_key: Some(KeyCode::KeyL),
226			orbit_up_key: Some(KeyCode::KeyI),
227			orbit_down_key: Some(KeyCode::KeyK),
228
229			slide_button: Some(MouseButton::Right),
230			slide_up_key: Some(KeyCode::KeyE),
231			slide_down_key: Some(KeyCode::KeyD),
232			slide_left_key: Some(KeyCode::KeyS),
233			slide_right_key: Some(KeyCode::KeyF),
234			slide_far_key: Some(KeyCode::KeyG),
235			slide_near_key: Some(KeyCode::KeyV),
236
237			scale_in_key: Some(KeyCode::KeyH),
238			scale_out_key: Some(KeyCode::KeyN),
239		}
240	}
241}
242
243/// [`TrackballInput`] setting translating between linear and angular velocity.
244#[derive(Debug, Clone, Copy)]
245pub enum TrackballVelocity {
246	/// Linear velocity.
247	Linear(f32),
248	/// Angular velocity.
249	Angular(f32),
250}
251
252impl TrackballVelocity {
253	/// Converts to angular velocity where `r` is the radius.
254	#[must_use]
255	pub fn to_angular(self, r: f32) -> Self {
256		match self {
257			Self::Angular(w) => Self::Angular(w),
258			Self::Linear(v) => Self::Angular(v / r),
259		}
260	}
261	/// Converts to linear velocity where `r` is the radius.
262	#[must_use]
263	pub fn to_linear(self, r: f32) -> Self {
264		match self {
265			Self::Angular(w) => Self::Linear(w * r),
266			Self::Linear(v) => Self::Linear(v),
267		}
268	}
269	/// Underlying quantity.
270	#[must_use]
271	pub const fn into_inner(self) -> f32 {
272		match self {
273			Self::Angular(w) => w,
274			Self::Linear(v) => v,
275		}
276	}
277}
278
279impl Default for TrackballVelocity {
280	/// Angular velocity of 45 degrees per second.
281	///
282	/// That is the default fixed vertical field of view per second.
283	fn default() -> Self {
284		Self::Angular(Fixed::default().into_inner())
285	}
286}
287
288/// [`TrackballInput`] setting translating wheel units in coherent scale denominators.
289#[derive(Debug, Clone, Copy)]
290#[non_exhaustive]
291pub enum TrackballWheelUnit {
292	/// Wheel clicks per turn (cpt).
293	///
294	/// Defaults to 24 cpt, that are 15°=360°/24 per click which agrees with most devices. Some
295	/// devices have 18 cpt instead, that are 20°=360/18 per click.
296	///
297	/// You can count the cpt of your device by marking the start of your wheel before rotating it a
298	/// full turn. Each noticeable step when rotating is called a wheel click, not to be confused
299	/// with a middle mouse button click.
300	Cpt(f32),
301	/// Wheel clicks per second (cps).
302	///
303	/// Some devices scroll smooth without noticeable steps when rotating. They specify their units
304	/// in cps (e.g., 1 000 cps). This unit will be translated to the trackball's angular velocity.
305	Cps(f32),
306}
307
308impl TrackballWheelUnit {
309	/// Coherent [`Scale`] denominator.
310	///
311	/// [`Scale`]: trackball::Scale
312	#[must_use]
313	pub fn denominator(self, w: f32) -> f32 {
314		match self {
315			Self::Cpt(cpt) => cpt,
316			Self::Cps(cps) => cps / w,
317		}
318	}
319}
320
321impl Default for TrackballWheelUnit {
322	/// 24 cpt, that are 15°=360°/24 per click.
323	fn default() -> Self {
324		Self::Cpt(24.0)
325	}
326}