ustreamer_input/lib.rs
1//! Browser input event bridge.
2//!
3//! Decodes compact binary input events from the browser and maps them
4//! to abstract application actions. Consumers define their own action types
5//! and mapping logic; this crate provides the raw event decode and a
6//! default mapper with common 3D/2D interaction patterns.
7
8use ustreamer_proto::input::InputEvent;
9
10/// Abstract application action produced by the input mapper.
11/// These cover common interaction patterns for 3D/2D applications.
12/// Consumers can extend or replace these with domain-specific actions.
13#[derive(Debug, Clone)]
14pub enum AppAction {
15 /// Camera orbit / rotation (e.g., left-drag in a 3D viewport).
16 Rotate { dx: f32, dy: f32 },
17 /// Camera zoom (e.g., scroll or middle-drag).
18 Zoom { delta: f32 },
19 /// Camera pan / translate.
20 Pan { dx: f32, dy: f32 },
21 /// Discrete scroll through items (e.g., layers, frames, slices).
22 ScrollStep { delta: i32 },
23 /// Two-axis parameter adjustment via drag (e.g., brightness/contrast).
24 DragAdjust { dx: f32, dy: f32 },
25 /// Raw pointer position update (for cursor overlay rendering).
26 PointerUpdate { x: f32, y: f32 },
27}
28
29/// Maps raw browser input events to application actions based on the current interaction mode.
30pub struct InputMapper {
31 mode: InteractionMode,
32 last_x: f32,
33 last_y: f32,
34 buttons: u8,
35}
36
37/// Interaction modes that determine how pointer drags are interpreted.
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub enum InteractionMode {
40 Rotate,
41 Pan,
42 Zoom,
43 Scroll,
44 /// Two-axis parameter adjustment via drag.
45 DragAdjust,
46}
47
48impl Default for InputMapper {
49 fn default() -> Self {
50 Self {
51 mode: InteractionMode::Rotate,
52 last_x: 0.0,
53 last_y: 0.0,
54 buttons: 0,
55 }
56 }
57}
58
59impl InputMapper {
60 pub fn set_mode(&mut self, mode: InteractionMode) {
61 self.mode = mode;
62 }
63
64 /// Process a raw input event and return zero or more application actions.
65 pub fn process(&mut self, event: &InputEvent) -> Vec<AppAction> {
66 match event {
67 InputEvent::PointerMove { x, y, buttons, .. } => {
68 let dx = x - self.last_x;
69 let dy = y - self.last_y;
70 self.last_x = *x;
71 self.last_y = *y;
72 self.buttons = *buttons;
73
74 let mut actions = vec![AppAction::PointerUpdate { x: *x, y: *y }];
75
76 // Left button drag → mode-dependent action
77 if *buttons & 1 != 0 {
78 match self.mode {
79 InteractionMode::Rotate => {
80 actions.push(AppAction::Rotate { dx, dy });
81 }
82 InteractionMode::Pan => {
83 actions.push(AppAction::Pan { dx, dy });
84 }
85 InteractionMode::Zoom => {
86 actions.push(AppAction::Zoom { delta: dy });
87 }
88 InteractionMode::DragAdjust => {
89 actions.push(AppAction::DragAdjust { dx, dy });
90 }
91 InteractionMode::Scroll => {}
92 }
93 }
94
95 actions
96 }
97 InputEvent::Scroll { delta_y, .. } => {
98 vec![AppAction::ScrollStep {
99 delta: if *delta_y > 0.0 { 1 } else { -1 },
100 }]
101 }
102 InputEvent::PointerDown { x, y, .. } => {
103 self.last_x = *x;
104 self.last_y = *y;
105 vec![]
106 }
107 _ => vec![],
108 }
109 }
110}