strat9_kernel/shell/
mouse.rs1pub extern "C" fn mouse_task_main() -> ! {
4 let mut prev_left = false;
6 let mut selecting = false;
7 let mut scrollbar_dragging = false;
8 let mut last_scrollbar_drag_tick = 0u64;
9 let mut pending_scrollbar_drag_y: Option<usize> = None;
10 let mut pending_selection_pos: Option<(usize, usize)> = None;
11 let mut pending_mouse_cursor: Option<(i32, i32)> = None;
12 let mut pending_scroll_delta: i32 = 0;
13 let mut mouse_x: i32 = 0;
14 let mut mouse_y: i32 = 0;
15
16 const MAX_MOUSE_EVENTS_PER_TURN: usize = 16;
18 const SCROLLBAR_DRAG_MIN_TICKS: u64 = 1;
19 const MOUSE_RENDER_MIN_TICKS: u64 = 1;
20 let mut last_mouse_render_tick = 0u64;
21
22 loop {
23 let ticks = crate::process::scheduler::ticks();
24 if crate::hardware::usb::hid::is_available() {
25 crate::hardware::usb::hid::poll_all();
26 }
27 crate::arch::vga::try_with_writer(|writer| {
28 if crate::arch::mouse::MOUSE_READY.load(core::sync::atomic::Ordering::Relaxed) {
29 let mut scroll_delta: i32 = 0;
30 let mut left_pressed = false;
31 let mut left_released = false;
32 let mut left_held = false;
33 let mut had_events = false;
34
35 let mut mouse_events_seen = 0usize;
36 while let Some(ev) = crate::arch::mouse::read_event() {
37 had_events = true;
38 scroll_delta += ev.dz as i32;
39 if ev.left && !prev_left {
40 left_pressed = true;
41 }
42 if !ev.left && prev_left {
43 left_released = true;
44 }
45 if ev.left && prev_left {
46 left_held = true;
47 }
48 prev_left = ev.left;
49 mouse_events_seen += 1;
50 if mouse_events_seen >= MAX_MOUSE_EVENTS_PER_TURN {
51 break;
55 }
56 }
57
58 let has_pending_visual = pending_scroll_delta != 0
59 || pending_scrollbar_drag_y.is_some()
60 || pending_selection_pos.is_some()
61 || pending_mouse_cursor.is_some();
62
63 if had_events || left_held || has_pending_visual {
64 let (new_mx, new_my) = crate::arch::mouse::mouse_pos();
65 let moved = new_mx != mouse_x || new_my != mouse_y;
66 mouse_x = new_mx;
67 mouse_y = new_my;
68 if had_events {
69 pending_scroll_delta += scroll_delta;
70 }
71
72 if left_pressed {
73 let (mx, my) = (new_mx as usize, new_my as usize);
74 if writer.scrollbar_hit_test(mx, my) {
75 writer.scrollbar_click(mx, my);
76 writer.clear_selection();
77 selecting = false;
78 scrollbar_dragging = true;
79 pending_scrollbar_drag_y = None;
80 } else {
81 writer.start_selection(mx, my);
82 selecting = true;
83 scrollbar_dragging = false;
84 pending_selection_pos = None;
85 }
86 last_mouse_render_tick = ticks;
87 } else if left_held && scrollbar_dragging && moved {
88 pending_scrollbar_drag_y = Some(new_my as usize);
89 } else if left_held && selecting && moved {
90 pending_selection_pos = Some((new_mx as usize, new_my as usize));
91 }
92 if left_released && !prev_left {
95 if selecting {
96 writer.end_selection();
97 selecting = false;
98 pending_selection_pos = None;
99 }
100 if scrollbar_dragging {
101 if let Some(py) = pending_scrollbar_drag_y.take() {
102 writer.scrollbar_drag_to(py);
103 }
104 }
105 scrollbar_dragging = false;
106 last_mouse_render_tick = ticks;
107 }
108
109 if moved {
110 pending_mouse_cursor = Some((new_mx, new_my));
111 }
112
113 let render_due =
114 ticks.saturating_sub(last_mouse_render_tick) >= MOUSE_RENDER_MIN_TICKS;
115 let drag_due =
116 ticks.saturating_sub(last_scrollbar_drag_tick) >= SCROLLBAR_DRAG_MIN_TICKS;
117 let has_pending_visual = pending_scroll_delta != 0
118 || pending_scrollbar_drag_y.is_some()
119 || pending_selection_pos.is_some()
120 || pending_mouse_cursor.is_some();
121 if has_pending_visual && (render_due || left_pressed || left_released) {
122 let mut rendered = false;
123
124 if pending_scroll_delta > 0 {
126 writer.scroll_view_down((pending_scroll_delta as usize) * 3);
127 pending_scroll_delta = 0;
128 rendered = true;
129 } else if pending_scroll_delta < 0 {
130 writer.scroll_view_up(((-pending_scroll_delta) as usize) * 3);
131 pending_scroll_delta = 0;
132 rendered = true;
133 }
134
135 if drag_due {
136 if selecting {
137 if let Some((sx, sy)) = pending_selection_pos.take() {
138 writer.update_selection(sx, sy);
139 rendered = true;
140 }
141 }
142 if scrollbar_dragging {
143 if let Some(py) = pending_scrollbar_drag_y.take() {
144 writer.scrollbar_drag_to(py);
145 last_scrollbar_drag_tick = ticks;
146 rendered = true;
147 }
148 }
149 }
150
151 if let Some((cx, cy)) = pending_mouse_cursor.take() {
152 writer.update_mouse_cursor(cx, cy);
153 rendered = true;
154 }
155
156 if rendered {
157 last_mouse_render_tick = ticks;
158 }
159 }
160 }
161 }
162 });
163 crate::process::yield_task();
164 }
165}