1use crate::device::CURRENT_DEVICE;
2use crate::framebuffer::Display;
3use crate::geom::{LinearDir, Point};
4use crate::settings::ButtonScheme;
5use anyhow::{Context, Error};
6use fxhash::FxHashMap;
7use std::ffi::CString;
8use std::fs::File;
9use std::io::Read;
10use std::mem::{self, MaybeUninit};
11use std::os::unix::io::AsRawFd;
12use std::ptr;
13use std::slice;
14use std::sync::mpsc::{self, Receiver, Sender};
15use std::thread;
16
17pub const EV_SYN: u16 = 0x00;
19pub const EV_KEY: u16 = 0x01;
20pub const EV_ABS: u16 = 0x03;
21pub const EV_MSC: u16 = 0x04;
22
23pub const ABS_MT_TRACKING_ID: u16 = 0x39;
25pub const ABS_MT_POSITION_X: u16 = 0x35;
26pub const ABS_MT_POSITION_Y: u16 = 0x36;
27pub const ABS_MT_PRESSURE: u16 = 0x3a;
28pub const ABS_MT_TOUCH_MAJOR: u16 = 0x30;
29pub const ABS_X: u16 = 0x00;
30pub const ABS_Y: u16 = 0x01;
31pub const ABS_PRESSURE: u16 = 0x18;
32pub const MSC_RAW: u16 = 0x03;
33pub const SYN_REPORT: u16 = 0x00;
34
35pub const MSC_RAW_GSENSOR_PORTRAIT_DOWN: i32 = 0x17;
37pub const MSC_RAW_GSENSOR_PORTRAIT_UP: i32 = 0x18;
38pub const MSC_RAW_GSENSOR_LANDSCAPE_RIGHT: i32 = 0x19;
39pub const MSC_RAW_GSENSOR_LANDSCAPE_LEFT: i32 = 0x1a;
40pub const GYROSCOPE_ROTATIONS: [i32; 4] = [
45 MSC_RAW_GSENSOR_LANDSCAPE_LEFT,
46 MSC_RAW_GSENSOR_PORTRAIT_UP,
47 MSC_RAW_GSENSOR_LANDSCAPE_RIGHT,
48 MSC_RAW_GSENSOR_PORTRAIT_DOWN,
49];
50
51pub const VAL_RELEASE: i32 = 0;
52pub const VAL_PRESS: i32 = 1;
53pub const VAL_REPEAT: i32 = 2;
54
55pub const KEY_POWER: u16 = 116;
57pub const KEY_HOME: u16 = 102;
58pub const KEY_LIGHT: u16 = 90;
59pub const KEY_BACKWARD: u16 = 193;
60pub const KEY_FORWARD: u16 = 194;
61pub const PEN_ERASE: u16 = 331;
62pub const PEN_HIGHLIGHT: u16 = 332;
63pub const SLEEP_COVER: [u16; 2] = [59, 35];
64pub const BTN_TOUCH: u16 = 330;
66pub const KEY_ROTATE_DISPLAY: u16 = 0xffff;
69pub const KEY_BUTTON_SCHEME: u16 = 0xfffe;
70
71pub const SINGLE_TOUCH_CODES: TouchCodes = TouchCodes {
72 pressure: ABS_PRESSURE,
73 x: ABS_X,
74 y: ABS_Y,
75};
76
77pub const MULTI_TOUCH_CODES_A: TouchCodes = TouchCodes {
78 pressure: ABS_MT_TOUCH_MAJOR,
79 x: ABS_MT_POSITION_X,
80 y: ABS_MT_POSITION_Y,
81};
82
83pub const MULTI_TOUCH_CODES_B: TouchCodes = TouchCodes {
84 pressure: ABS_MT_PRESSURE,
85 ..MULTI_TOUCH_CODES_A
86};
87
88#[repr(C)]
89pub struct InputEvent {
90 pub time: libc::timeval,
91 pub kind: u16, pub code: u16,
93 pub value: i32,
94}
95
96#[derive(Debug)]
98pub struct TouchCodes {
99 pressure: u16,
100 x: u16,
101 y: u16,
102}
103
104#[derive(Debug, Copy, Clone, Eq, PartialEq)]
105pub enum TouchProto {
106 Single,
107 MultiA,
108 MultiB, MultiC,
110}
111
112#[derive(Debug, Copy, Clone, Eq, PartialEq)]
113pub enum FingerStatus {
114 Down,
115 Motion,
116 Up,
117}
118
119#[derive(Debug, Copy, Clone, Eq, PartialEq)]
120pub enum ButtonStatus {
121 Pressed,
122 Released,
123 Repeated,
124}
125
126impl ButtonStatus {
127 pub fn try_from_raw(value: i32) -> Option<ButtonStatus> {
128 match value {
129 VAL_RELEASE => Some(ButtonStatus::Released),
130 VAL_PRESS => Some(ButtonStatus::Pressed),
131 VAL_REPEAT => Some(ButtonStatus::Repeated),
132 _ => None,
133 }
134 }
135}
136
137#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
138pub enum ButtonCode {
139 Power,
140 Home,
141 Light,
142 Backward,
143 Forward,
144 Erase,
145 Highlight,
146 Raw(u16),
147}
148
149impl ButtonCode {
150 fn from_raw(code: u16, rotation: i8, button_scheme: ButtonScheme) -> ButtonCode {
151 match code {
152 KEY_POWER => ButtonCode::Power,
153 KEY_HOME => ButtonCode::Home,
154 KEY_LIGHT => ButtonCode::Light,
155 KEY_BACKWARD => resolve_button_direction(LinearDir::Backward, rotation, button_scheme),
156 KEY_FORWARD => resolve_button_direction(LinearDir::Forward, rotation, button_scheme),
157 PEN_ERASE => ButtonCode::Erase,
158 PEN_HIGHLIGHT => ButtonCode::Highlight,
159 _ => ButtonCode::Raw(code),
160 }
161 }
162}
163
164fn resolve_button_direction(
165 mut direction: LinearDir,
166 rotation: i8,
167 button_scheme: ButtonScheme,
168) -> ButtonCode {
169 if (CURRENT_DEVICE.should_invert_buttons(rotation)) ^ (button_scheme == ButtonScheme::Inverted)
170 {
171 direction = direction.opposite();
172 }
173
174 if direction == LinearDir::Forward {
175 return ButtonCode::Forward;
176 }
177
178 ButtonCode::Backward
179}
180
181pub fn display_rotate_event(n: i8) -> InputEvent {
182 let mut tp = libc::timeval {
183 tv_sec: 0,
184 tv_usec: 0,
185 };
186 unsafe {
187 libc::gettimeofday(&mut tp, ptr::null_mut());
188 }
189 InputEvent {
190 time: tp,
191 kind: EV_KEY,
192 code: KEY_ROTATE_DISPLAY,
193 value: n as i32,
194 }
195}
196
197pub fn button_scheme_event(v: i32) -> InputEvent {
198 let mut tp = libc::timeval {
199 tv_sec: 0,
200 tv_usec: 0,
201 };
202 unsafe {
203 libc::gettimeofday(&mut tp, ptr::null_mut());
204 }
205 InputEvent {
206 time: tp,
207 kind: EV_KEY,
208 code: KEY_BUTTON_SCHEME,
209 value: v,
210 }
211}
212
213#[derive(Debug, Copy, Clone)]
214pub enum DeviceEvent {
215 Finger {
216 id: i32,
217 time: f64,
218 status: FingerStatus,
219 position: Point,
220 },
221 Button {
222 time: f64,
223 code: ButtonCode,
224 status: ButtonStatus,
225 },
226 Plug(PowerSource),
227 Unplug(PowerSource),
228 RotateScreen(i8),
229 CoverOn,
230 CoverOff,
231 NetUp,
232 UserActivity,
233}
234
235#[derive(Debug, Copy, Clone, Eq, PartialEq)]
236pub enum PowerSource {
237 Host,
238 Wall,
239}
240
241pub fn seconds(time: libc::timeval) -> f64 {
242 time.tv_sec as f64 + time.tv_usec as f64 / 1e6
243}
244
245pub fn raw_events(paths: Vec<String>) -> (Sender<InputEvent>, Receiver<InputEvent>) {
246 let (tx, rx) = mpsc::channel();
247 let tx2 = tx.clone();
248 thread::spawn(move || parse_raw_events(&paths, &tx));
249 (tx2, rx)
250}
251
252pub fn parse_raw_events(paths: &[String], tx: &Sender<InputEvent>) -> Result<(), Error> {
253 let mut files = Vec::new();
254 let mut pfds = Vec::new();
255
256 for path in paths.iter() {
257 let file = File::open(path).with_context(|| format!("can't open input file {}", path))?;
258 let fd = file.as_raw_fd();
259 files.push(file);
260 pfds.push(libc::pollfd {
261 fd,
262 events: libc::POLLIN,
263 revents: 0,
264 });
265 }
266
267 loop {
268 let ret = unsafe { libc::poll(pfds.as_mut_ptr(), pfds.len() as libc::nfds_t, -1) };
269 if ret < 0 {
270 break;
271 }
272 for (pfd, mut file) in pfds.iter().zip(&files) {
273 if pfd.revents & libc::POLLIN != 0 {
274 let mut input_event = MaybeUninit::<InputEvent>::uninit();
275 unsafe {
276 let event_slice = slice::from_raw_parts_mut(
277 input_event.as_mut_ptr() as *mut u8,
278 mem::size_of::<InputEvent>(),
279 );
280 if file.read_exact(event_slice).is_err() {
281 break;
282 }
283 tx.send(input_event.assume_init()).ok();
284 }
285 }
286 }
287 }
288
289 Ok(())
290}
291
292pub fn usb_events() -> Receiver<DeviceEvent> {
293 let (tx, rx) = mpsc::channel();
294 thread::spawn(move || parse_usb_events(&tx));
295 rx
296}
297
298fn parse_usb_events(tx: &Sender<DeviceEvent>) {
299 let path = CString::new("/tmp/nickel-hardware-status").unwrap();
300 let fd = unsafe { libc::open(path.as_ptr(), libc::O_NONBLOCK | libc::O_RDWR) };
301
302 if fd < 0 {
303 return;
304 }
305
306 let mut pfd = libc::pollfd {
307 fd,
308 events: libc::POLLIN,
309 revents: 0,
310 };
311
312 const BUF_LEN: usize = 256;
313
314 loop {
315 let ret = unsafe { libc::poll(&mut pfd as *mut libc::pollfd, 1, -1) };
316
317 if ret < 0 {
318 break;
319 }
320
321 let buf = CString::new(vec![1; BUF_LEN]).unwrap();
322 let c_buf = buf.into_raw();
323
324 if pfd.revents & libc::POLLIN != 0 {
325 let n = unsafe { libc::read(fd, c_buf as *mut libc::c_void, BUF_LEN as libc::size_t) };
326 let buf = unsafe { CString::from_raw(c_buf) };
327 if n > 0 {
328 if let Ok(s) = buf.to_str() {
329 for msg in s[..n as usize].lines() {
330 if msg == "usb plug add" {
331 tx.send(DeviceEvent::Plug(PowerSource::Host)).ok();
332 } else if msg == "usb plug remove" {
333 tx.send(DeviceEvent::Unplug(PowerSource::Host)).ok();
334 } else if msg == "usb ac add" {
335 tx.send(DeviceEvent::Plug(PowerSource::Wall)).ok();
336 } else if msg == "usb ac remove" {
337 tx.send(DeviceEvent::Unplug(PowerSource::Wall)).ok();
338 } else if msg.starts_with("network bound") {
339 tx.send(DeviceEvent::NetUp).ok();
340 }
341 }
342 }
343 } else {
344 break;
345 }
346 }
347 }
348}
349
350pub fn device_events(
351 rx: Receiver<InputEvent>,
352 display: Display,
353 button_scheme: ButtonScheme,
354) -> Receiver<DeviceEvent> {
355 let (ty, ry) = mpsc::channel();
356 thread::spawn(move || parse_device_events(&rx, &ty, display, button_scheme));
357 ry
358}
359
360struct TouchState {
361 position: Point,
362 pressure: i32,
363}
364
365impl Default for TouchState {
366 fn default() -> Self {
367 TouchState {
368 position: Point::default(),
369 pressure: 0,
370 }
371 }
372}
373
374pub fn parse_device_events(
375 rx: &Receiver<InputEvent>,
376 ty: &Sender<DeviceEvent>,
377 display: Display,
378 button_scheme: ButtonScheme,
379) {
380 let mut id = 0;
381 let mut last_activity = -60;
382 let Display {
383 mut dims,
384 mut rotation,
385 } = display;
386 let mut fingers: FxHashMap<i32, Point> = FxHashMap::default();
387 let mut packets: FxHashMap<i32, TouchState> = FxHashMap::default();
388 let proto = CURRENT_DEVICE.proto;
389
390 let mut tc = match proto {
391 TouchProto::Single => SINGLE_TOUCH_CODES,
392 TouchProto::MultiA => MULTI_TOUCH_CODES_A,
393 TouchProto::MultiB => MULTI_TOUCH_CODES_B,
394 TouchProto::MultiC => MULTI_TOUCH_CODES_B,
395 };
396
397 if proto == TouchProto::Single {
398 packets.insert(id, TouchState::default());
399 }
400
401 let (mut mirror_x, mut mirror_y) = CURRENT_DEVICE.should_mirror_axes(rotation);
402 if CURRENT_DEVICE.should_swap_axes(rotation) {
403 mem::swap(&mut tc.x, &mut tc.y);
404 }
405
406 let mut button_scheme = button_scheme;
407
408 while let Ok(evt) = rx.recv() {
409 if evt.kind == EV_ABS {
410 if evt.code == ABS_MT_TRACKING_ID {
411 if evt.value >= 0 {
412 id = evt.value;
413 packets.insert(id, TouchState::default());
414 }
415 } else if evt.code == tc.x {
416 if let Some(state) = packets.get_mut(&id) {
417 state.position.x = if mirror_x {
418 dims.0 as i32 - 1 - evt.value
419 } else {
420 evt.value
421 };
422 }
423 } else if evt.code == tc.y {
424 if let Some(state) = packets.get_mut(&id) {
425 state.position.y = if mirror_y {
426 dims.1 as i32 - 1 - evt.value
427 } else {
428 evt.value
429 };
430 }
431 } else if evt.code == tc.pressure {
432 if let Some(state) = packets.get_mut(&id) {
433 state.pressure = evt.value;
434 if proto == TouchProto::Single
435 && CURRENT_DEVICE.mark() == 3
436 && state.pressure == 0
437 {
438 state.position.x = dims.0 as i32 - 1 - state.position.x;
439 mem::swap(&mut state.position.x, &mut state.position.y);
440 }
441 }
442 }
443 } else if evt.kind == EV_SYN && evt.code == SYN_REPORT {
444 if (evt.time.tv_sec - last_activity).abs() >= 60 {
447 last_activity = evt.time.tv_sec;
448 ty.send(DeviceEvent::UserActivity).ok();
449 }
450
451 if proto == TouchProto::MultiB {
452 fingers.retain(|other_id, other_position| {
453 packets.contains_key(&other_id)
454 || ty
455 .send(DeviceEvent::Finger {
456 id: *other_id,
457 time: seconds(evt.time),
458 status: FingerStatus::Up,
459 position: *other_position,
460 })
461 .is_err()
462 });
463 }
464
465 for (&id, state) in &packets {
466 if let Some(&pos) = fingers.get(&id) {
467 if state.pressure > 0 {
468 if state.position != pos {
469 ty.send(DeviceEvent::Finger {
470 id,
471 time: seconds(evt.time),
472 status: FingerStatus::Motion,
473 position: state.position,
474 })
475 .unwrap();
476 fingers.insert(id, state.position);
477 }
478 } else {
479 ty.send(DeviceEvent::Finger {
480 id,
481 time: seconds(evt.time),
482 status: FingerStatus::Up,
483 position: state.position,
484 })
485 .unwrap();
486 fingers.remove(&id);
487 }
488 } else if state.pressure > 0 {
489 ty.send(DeviceEvent::Finger {
490 id,
491 time: seconds(evt.time),
492 status: FingerStatus::Down,
493 position: state.position,
494 })
495 .unwrap();
496 fingers.insert(id, state.position);
497 }
498 }
499
500 if proto != TouchProto::Single {
501 packets.clear();
502 }
503 } else if evt.kind == EV_KEY {
504 if SLEEP_COVER.contains(&evt.code) {
505 if evt.value == VAL_PRESS {
506 ty.send(DeviceEvent::CoverOn).ok();
507 } else if evt.value == VAL_RELEASE {
508 ty.send(DeviceEvent::CoverOff).ok();
509 } else if evt.value == VAL_REPEAT {
510 ty.send(DeviceEvent::CoverOn).ok();
511 }
512 } else if evt.code == KEY_BUTTON_SCHEME {
513 if evt.value == VAL_PRESS {
514 button_scheme = ButtonScheme::Inverted;
515 } else {
516 button_scheme = ButtonScheme::Natural;
517 }
518 } else if evt.code == KEY_ROTATE_DISPLAY {
519 let next_rotation = evt.value as i8;
520 if next_rotation != rotation {
521 let delta = (rotation - next_rotation).abs();
522 if delta % 2 == 1 {
523 mem::swap(&mut tc.x, &mut tc.y);
524 mem::swap(&mut dims.0, &mut dims.1);
525 }
526 rotation = next_rotation;
527 let should_mirror = CURRENT_DEVICE.should_mirror_axes(rotation);
528 mirror_x = should_mirror.0;
529 mirror_y = should_mirror.1;
530 }
531 } else if evt.code != BTN_TOUCH {
532 if let Some(button_status) = ButtonStatus::try_from_raw(evt.value) {
533 ty.send(DeviceEvent::Button {
534 time: seconds(evt.time),
535 code: ButtonCode::from_raw(evt.code, rotation, button_scheme),
536 status: button_status,
537 })
538 .unwrap();
539 }
540 }
541 } else if evt.kind == EV_MSC && evt.code == MSC_RAW {
542 if evt.value >= MSC_RAW_GSENSOR_PORTRAIT_DOWN
543 && evt.value <= MSC_RAW_GSENSOR_LANDSCAPE_LEFT
544 {
545 let next_rotation = GYROSCOPE_ROTATIONS
546 .iter()
547 .position(|&v| v == evt.value)
548 .map(|i| CURRENT_DEVICE.transformed_gyroscope_rotation(i as i8));
549 if let Some(next_rotation) = next_rotation {
550 ty.send(DeviceEvent::RotateScreen(next_rotation)).ok();
551 }
552 }
553 }
554 }
555}