b9874d0941
Add redbear-usb-storage-check in-guest binary that validates USB mass storage read and write I/O: discovers /scheme/disk/ devices, writes a test pattern to sector 2048, reads it back, verifies match, restores original content. Updates test-usb-storage-qemu.sh with write-proof verification step. Includes all accumulated Red Bear OS work: kernel patches, relibc patches, driver infrastructure, DRM/GPU, KDE recipes, firmware, validation tooling, build system hardening, and documentation.
300 lines
11 KiB
Rust
300 lines
11 KiB
Rust
use crate::types::*;
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
pub enum GestureType {
|
|
None,
|
|
ScrollBegin,
|
|
ScrollUpdate { dx: f64, dy: f64 },
|
|
ScrollEnd,
|
|
PinchBegin,
|
|
PinchUpdate { scale: f64 },
|
|
PinchEnd,
|
|
SwipeBegin { finger_count: u32 },
|
|
SwipeUpdate { dx: f64, dy: f64, finger_count: u32 },
|
|
SwipeEnd,
|
|
Tap { finger_count: u32 },
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct GestureEvent {
|
|
pub gesture_type: GestureType,
|
|
pub timestamp_us: u64,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Default)]
|
|
struct FingerState {
|
|
x: i32,
|
|
y: i32,
|
|
touching: bool,
|
|
start_x: i32,
|
|
start_y: i32,
|
|
}
|
|
|
|
const MAX_FINGERS: usize = 5;
|
|
const TAP_THRESHOLD_PX: i32 = 20;
|
|
const TAP_MAX_DURATION_US: u64 = 300_000;
|
|
const SWIPE_THRESHOLD_PX: i32 = 50;
|
|
|
|
pub struct GestureRecognizer {
|
|
fingers: [FingerState; MAX_FINGERS],
|
|
prev_fingers: [FingerState; MAX_FINGERS],
|
|
gesture_active: GestureType,
|
|
finger_count_at_start: u32,
|
|
start_timestamp: u64,
|
|
pinch_initial_dist: f64,
|
|
}
|
|
|
|
impl GestureRecognizer {
|
|
pub fn new() -> Self {
|
|
GestureRecognizer {
|
|
fingers: [FingerState::default(); MAX_FINGERS],
|
|
prev_fingers: [FingerState::default(); MAX_FINGERS],
|
|
gesture_active: GestureType::None,
|
|
finger_count_at_start: 0,
|
|
start_timestamp: 0,
|
|
pinch_initial_dist: 0.0,
|
|
}
|
|
}
|
|
|
|
pub fn update_slot(
|
|
&mut self,
|
|
slot: usize,
|
|
x: i32,
|
|
y: i32,
|
|
touching: bool,
|
|
timestamp_us: u64,
|
|
) -> Vec<GestureEvent> {
|
|
if slot >= MAX_FINGERS {
|
|
return Vec::new();
|
|
}
|
|
|
|
let was_touching = self.fingers[slot].touching;
|
|
self.prev_fingers[slot] = self.fingers[slot];
|
|
self.fingers[slot].x = x;
|
|
self.fingers[slot].y = y;
|
|
self.fingers[slot].touching = touching;
|
|
|
|
if touching && !was_touching {
|
|
self.fingers[slot].start_x = x;
|
|
self.fingers[slot].start_y = y;
|
|
self.fingers[slot].x = x;
|
|
self.fingers[slot].y = y;
|
|
|
|
let count = self.active_finger_count();
|
|
if count == 1 {
|
|
self.finger_count_at_start = 1;
|
|
self.start_timestamp = timestamp_us;
|
|
} else if count >= 2 {
|
|
self.finger_count_at_start = count;
|
|
self.start_timestamp = timestamp_us;
|
|
}
|
|
}
|
|
|
|
if !touching && was_touching {
|
|
let duration = timestamp_us.saturating_sub(self.start_timestamp);
|
|
let dx = self.fingers[slot].x - self.fingers[slot].start_x;
|
|
let dy = self.fingers[slot].y - self.fingers[slot].start_y;
|
|
let distance = ((dx * dx + dy * dy) as f64).sqrt();
|
|
|
|
if distance < TAP_THRESHOLD_PX as f64
|
|
&& duration < TAP_MAX_DURATION_US
|
|
&& self.gesture_active == GestureType::None
|
|
{
|
|
let remaining = self.active_finger_count();
|
|
if remaining == 0 {
|
|
let fc = self.finger_count_at_start.max(1);
|
|
self.finger_count_at_start = 0;
|
|
return vec![GestureEvent {
|
|
gesture_type: GestureType::Tap { finger_count: fc },
|
|
timestamp_us,
|
|
}];
|
|
}
|
|
}
|
|
|
|
if self.gesture_active != GestureType::None {
|
|
let end = self.end_gesture(timestamp_us);
|
|
self.finger_count_at_start = 0;
|
|
return end;
|
|
}
|
|
|
|
self.finger_count_at_start = 0;
|
|
}
|
|
|
|
if touching && self.active_finger_count() >= 2 {
|
|
return self.detect_multi_finger_update(timestamp_us);
|
|
}
|
|
|
|
Vec::new()
|
|
}
|
|
|
|
fn active_finger_count(&self) -> u32 {
|
|
self.fingers.iter().filter(|f| f.touching).count() as u32
|
|
}
|
|
|
|
fn detect_multi_finger_update(&mut self, timestamp_us: u64) -> Vec<GestureEvent> {
|
|
let active: Vec<usize> = self
|
|
.fingers
|
|
.iter()
|
|
.enumerate()
|
|
.filter(|(_, f)| f.touching)
|
|
.map(|(i, _)| i)
|
|
.collect();
|
|
|
|
if active.len() < 2 {
|
|
return Vec::new();
|
|
}
|
|
|
|
match self.gesture_active {
|
|
GestureType::None => {
|
|
let count = active.len() as u32;
|
|
|
|
if count >= 3 {
|
|
self.gesture_active = GestureType::SwipeBegin { finger_count: count };
|
|
self.start_timestamp = timestamp_us;
|
|
self.pinch_initial_dist = self.finger_pair_distance(active[0], active[1]);
|
|
return vec![GestureEvent {
|
|
gesture_type: GestureType::SwipeBegin { finger_count: count },
|
|
timestamp_us,
|
|
}];
|
|
}
|
|
|
|
if count == 2 {
|
|
let dx0 = self.fingers[active[0]].x - self.prev_fingers[active[0]].x;
|
|
let dy0 = self.fingers[active[0]].y - self.prev_fingers[active[0]].y;
|
|
let dx1 = self.fingers[active[1]].x - self.prev_fingers[active[1]].x;
|
|
let dy1 = self.fingers[active[1]].y - self.prev_fingers[active[1]].y;
|
|
|
|
let avg_dx = (dx0 + dx1) as f64 / 2.0;
|
|
let avg_dy = (dy0 + dy1) as f64 / 2.0;
|
|
let movement = (avg_dx * avg_dx + avg_dy * avg_dy).sqrt();
|
|
|
|
let current_dist = self.finger_pair_distance(active[0], active[1]);
|
|
let dist_change = if self.pinch_initial_dist > 0.0 {
|
|
((current_dist - self.pinch_initial_dist) / self.pinch_initial_dist).abs()
|
|
} else {
|
|
0.0
|
|
};
|
|
|
|
if dist_change > 0.05 {
|
|
self.gesture_active = GestureType::PinchBegin;
|
|
self.start_timestamp = timestamp_us;
|
|
self.pinch_initial_dist = current_dist;
|
|
return vec![GestureEvent {
|
|
gesture_type: GestureType::PinchBegin,
|
|
timestamp_us,
|
|
}];
|
|
}
|
|
|
|
if movement > 2.0 {
|
|
self.gesture_active = GestureType::ScrollBegin;
|
|
self.start_timestamp = timestamp_us;
|
|
return vec![GestureEvent {
|
|
gesture_type: GestureType::ScrollBegin,
|
|
timestamp_us,
|
|
}];
|
|
}
|
|
}
|
|
}
|
|
GestureType::ScrollBegin | GestureType::ScrollUpdate { .. } => {
|
|
if active.len() >= 2 {
|
|
let dx0 = self.fingers[active[0]].x - self.prev_fingers[active[0]].x;
|
|
let dy0 = self.fingers[active[0]].y - self.prev_fingers[active[0]].y;
|
|
let dx1 = self.fingers[active[1]].x - self.prev_fingers[active[1]].x;
|
|
let dy1 = self.fingers[active[1]].y - self.prev_fingers[active[1]].y;
|
|
|
|
let avg_dx = (dx0 + dx1) as f64 / 2.0;
|
|
let avg_dy = (dy0 + dy1) as f64 / 2.0;
|
|
|
|
self.gesture_active = GestureType::ScrollUpdate {
|
|
dx: avg_dx,
|
|
dy: avg_dy,
|
|
};
|
|
return vec![GestureEvent {
|
|
gesture_type: GestureType::ScrollUpdate {
|
|
dx: avg_dx,
|
|
dy: avg_dy,
|
|
},
|
|
timestamp_us,
|
|
}];
|
|
}
|
|
}
|
|
GestureType::PinchBegin | GestureType::PinchUpdate { .. } => {
|
|
if active.len() >= 2 {
|
|
let current_dist = self.finger_pair_distance(active[0], active[1]);
|
|
let scale = if self.pinch_initial_dist > 0.0 {
|
|
current_dist / self.pinch_initial_dist
|
|
} else {
|
|
1.0
|
|
};
|
|
self.gesture_active = GestureType::PinchUpdate { scale };
|
|
return vec![GestureEvent {
|
|
gesture_type: GestureType::PinchUpdate { scale },
|
|
timestamp_us,
|
|
}];
|
|
}
|
|
}
|
|
GestureType::SwipeBegin { finger_count } | GestureType::SwipeUpdate { finger_count, .. } => {
|
|
if !active.is_empty() {
|
|
let first = active[0];
|
|
let dx = self.fingers[first].x - self.prev_fingers[first].x;
|
|
let dy = self.fingers[first].y - self.prev_fingers[first].y;
|
|
let fc = match self.gesture_active {
|
|
GestureType::SwipeBegin { finger_count: fc } | GestureType::SwipeUpdate { finger_count: fc, .. } => fc,
|
|
_ => finger_count,
|
|
};
|
|
self.gesture_active = GestureType::SwipeUpdate {
|
|
dx: dx as f64,
|
|
dy: dy as f64,
|
|
finger_count: fc,
|
|
};
|
|
return vec![GestureEvent {
|
|
gesture_type: GestureType::SwipeUpdate {
|
|
dx: dx as f64,
|
|
dy: dy as f64,
|
|
finger_count: fc,
|
|
},
|
|
timestamp_us,
|
|
}];
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
Vec::new()
|
|
}
|
|
|
|
fn end_gesture(&mut self, timestamp_us: u64) -> Vec<GestureEvent> {
|
|
let end_type = match self.gesture_active {
|
|
GestureType::ScrollBegin | GestureType::ScrollUpdate { .. } => GestureType::ScrollEnd,
|
|
GestureType::PinchBegin | GestureType::PinchUpdate { .. } => GestureType::PinchEnd,
|
|
GestureType::SwipeBegin { .. } | GestureType::SwipeUpdate { .. } => GestureType::SwipeEnd,
|
|
_ => GestureType::None,
|
|
};
|
|
self.gesture_active = GestureType::None;
|
|
|
|
if end_type == GestureType::None {
|
|
Vec::new()
|
|
} else {
|
|
vec![GestureEvent {
|
|
gesture_type: end_type,
|
|
timestamp_us,
|
|
}]
|
|
}
|
|
}
|
|
|
|
fn finger_pair_distance(&self, a: usize, b: usize) -> f64 {
|
|
let dx = self.fingers[a].x - self.fingers[b].x;
|
|
let dy = self.fingers[a].y - self.fingers[b].y;
|
|
((dx * dx + dy * dy) as f64).sqrt()
|
|
}
|
|
|
|
pub fn reset(&mut self) {
|
|
self.fingers = [FingerState::default(); MAX_FINGERS];
|
|
self.prev_fingers = [FingerState::default(); MAX_FINGERS];
|
|
self.gesture_active = GestureType::None;
|
|
self.finger_count_at_start = 0;
|
|
self.start_timestamp = 0;
|
|
self.pinch_initial_dist = 0.0;
|
|
}
|
|
}
|