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}