Skip to main content

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                        }
339                    }
340                }
341            } else {
342                break;
343            }
344        }
345    }
346}
347
348pub fn device_events(
349    rx: Receiver<InputEvent>,
350    display: Display,
351    button_scheme: ButtonScheme,
352) -> Receiver<DeviceEvent> {
353    let (ty, ry) = mpsc::channel();
354    thread::spawn(move || parse_device_events(&rx, &ty, display, button_scheme));
355    ry
356}
357
358struct TouchState {
359    position: Point,
360    pressure: i32,
361}
362
363impl Default for TouchState {
364    fn default() -> Self {
365        TouchState {
366            position: Point::default(),
367            pressure: 0,
368        }
369    }
370}
371
372pub fn parse_device_events(
373    rx: &Receiver<InputEvent>,
374    ty: &Sender<DeviceEvent>,
375    display: Display,
376    button_scheme: ButtonScheme,
377) {
378    let mut id = 0;
379    let mut last_activity = -60;
380    let Display {
381        mut dims,
382        mut rotation,
383    } = display;
384    let mut fingers: FxHashMap<i32, Point> = FxHashMap::default();
385    let mut packets: FxHashMap<i32, TouchState> = FxHashMap::default();
386    let proto = CURRENT_DEVICE.proto;
387
388    let mut tc = match proto {
389        TouchProto::Single => SINGLE_TOUCH_CODES,
390        TouchProto::MultiA => MULTI_TOUCH_CODES_A,
391        TouchProto::MultiB => MULTI_TOUCH_CODES_B,
392        TouchProto::MultiC => MULTI_TOUCH_CODES_B,
393    };
394
395    if proto == TouchProto::Single {
396        packets.insert(id, TouchState::default());
397    }
398
399    let (mut mirror_x, mut mirror_y) = CURRENT_DEVICE.should_mirror_axes(rotation);
400    if CURRENT_DEVICE.should_swap_axes(rotation) {
401        mem::swap(&mut tc.x, &mut tc.y);
402    }
403
404    let mut button_scheme = button_scheme;
405
406    while let Ok(evt) = rx.recv() {
407        if evt.kind == EV_ABS {
408            if evt.code == ABS_MT_TRACKING_ID {
409                if evt.value >= 0 {
410                    id = evt.value;
411                    packets.insert(id, TouchState::default());
412                }
413            } else if evt.code == tc.x {
414                if let Some(state) = packets.get_mut(&id) {
415                    state.position.x = if mirror_x {
416                        dims.0 as i32 - 1 - evt.value
417                    } else {
418                        evt.value
419                    };
420                }
421            } else if evt.code == tc.y {
422                if let Some(state) = packets.get_mut(&id) {
423                    state.position.y = if mirror_y {
424                        dims.1 as i32 - 1 - evt.value
425                    } else {
426                        evt.value
427                    };
428                }
429            } else if evt.code == tc.pressure {
430                if let Some(state) = packets.get_mut(&id) {
431                    state.pressure = evt.value;
432                    if proto == TouchProto::Single
433                        && CURRENT_DEVICE.mark() == 3
434                        && state.pressure == 0
435                    {
436                        state.position.x = dims.0 as i32 - 1 - state.position.x;
437                        mem::swap(&mut state.position.x, &mut state.position.y);
438                    }
439                }
440            }
441        } else if evt.kind == EV_SYN && evt.code == SYN_REPORT {
442            // The absolute value accounts for the wrapping around that might occur,
443            // since `tv_sec` can't grow forever.
444            if (evt.time.tv_sec - last_activity).abs() >= 60 {
445                last_activity = evt.time.tv_sec;
446                ty.send(DeviceEvent::UserActivity).ok();
447            }
448
449            if proto == TouchProto::MultiB {
450                fingers.retain(|other_id, other_position| {
451                    packets.contains_key(&other_id)
452                        || ty
453                            .send(DeviceEvent::Finger {
454                                id: *other_id,
455                                time: seconds(evt.time),
456                                status: FingerStatus::Up,
457                                position: *other_position,
458                            })
459                            .is_err()
460                });
461            }
462
463            for (&id, state) in &packets {
464                if let Some(&pos) = fingers.get(&id) {
465                    if state.pressure > 0 {
466                        if state.position != pos {
467                            ty.send(DeviceEvent::Finger {
468                                id,
469                                time: seconds(evt.time),
470                                status: FingerStatus::Motion,
471                                position: state.position,
472                            })
473                            .unwrap();
474                            fingers.insert(id, state.position);
475                        }
476                    } else {
477                        ty.send(DeviceEvent::Finger {
478                            id,
479                            time: seconds(evt.time),
480                            status: FingerStatus::Up,
481                            position: state.position,
482                        })
483                        .unwrap();
484                        fingers.remove(&id);
485                    }
486                } else if state.pressure > 0 {
487                    ty.send(DeviceEvent::Finger {
488                        id,
489                        time: seconds(evt.time),
490                        status: FingerStatus::Down,
491                        position: state.position,
492                    })
493                    .unwrap();
494                    fingers.insert(id, state.position);
495                }
496            }
497
498            if proto != TouchProto::Single {
499                packets.clear();
500            }
501        } else if evt.kind == EV_KEY {
502            if SLEEP_COVER.contains(&evt.code) {
503                if evt.value == VAL_PRESS {
504                    ty.send(DeviceEvent::CoverOn).ok();
505                } else if evt.value == VAL_RELEASE {
506                    ty.send(DeviceEvent::CoverOff).ok();
507                } else if evt.value == VAL_REPEAT {
508                    ty.send(DeviceEvent::CoverOn).ok();
509                }
510            } else if evt.code == KEY_BUTTON_SCHEME {
511                if evt.value == VAL_PRESS {
512                    button_scheme = ButtonScheme::Inverted;
513                } else {
514                    button_scheme = ButtonScheme::Natural;
515                }
516            } else if evt.code == KEY_ROTATE_DISPLAY {
517                let next_rotation = evt.value as i8;
518                if next_rotation != rotation {
519                    let delta = (rotation - next_rotation).abs();
520                    if delta % 2 == 1 {
521                        mem::swap(&mut tc.x, &mut tc.y);
522                        mem::swap(&mut dims.0, &mut dims.1);
523                    }
524                    rotation = next_rotation;
525                    let should_mirror = CURRENT_DEVICE.should_mirror_axes(rotation);
526                    mirror_x = should_mirror.0;
527                    mirror_y = should_mirror.1;
528                }
529            } else if evt.code != BTN_TOUCH {
530                if let Some(button_status) = ButtonStatus::try_from_raw(evt.value) {
531                    ty.send(DeviceEvent::Button {
532                        time: seconds(evt.time),
533                        code: ButtonCode::from_raw(evt.code, rotation, button_scheme),
534                        status: button_status,
535                    })
536                    .unwrap();
537                }
538            }
539        } else if evt.kind == EV_MSC && evt.code == MSC_RAW {
540            if evt.value >= MSC_RAW_GSENSOR_PORTRAIT_DOWN
541                && evt.value <= MSC_RAW_GSENSOR_LANDSCAPE_LEFT
542            {
543                let next_rotation = GYROSCOPE_ROTATIONS
544                    .iter()
545                    .position(|&v| v == evt.value)
546                    .map(|i| CURRENT_DEVICE.transformed_gyroscope_rotation(i as i8));
547                if let Some(next_rotation) = next_rotation {
548                    ty.send(DeviceEvent::RotateScreen(next_rotation)).ok();
549                }
550            }
551        }
552    }
553}