cadmus_core/
input.rs

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
17// Event types
18pub const EV_SYN: u16 = 0x00;
19pub const EV_KEY: u16 = 0x01;
20pub const EV_ABS: u16 = 0x03;
21pub const EV_MSC: u16 = 0x04;
22
23// Event codes
24pub 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
35// Event values
36pub 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;
40// pub const MSC_RAW_GSENSOR_BACK: i32 = 0x1b;
41// pub const MSC_RAW_GSENSOR_FRONT: i32 = 0x1c;
42
43// The indices of this clockwise ordering of the sensor values match the Forma's rotation values.
44pub 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
55// Key codes
56pub 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];
64// Synthetic touch button
65pub const BTN_TOUCH: u16 = 330;
66// The following key codes are fake, and are used to support
67// software toggles within this design
68pub 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, // type
92    pub code: u16,
93    pub value: i32,
94}
95
96// Handle different touch protocols
97#[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, // Pressure won't indicate a finger release.
109    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            // The absolute value accounts for the wrapping around that might occur,
445            // since `tv_sec` can't grow forever.
446            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}