| // Copyright 2019 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| //! Linux input system bindings. |
| |
| pub mod constants; |
| |
| use std::mem::size_of; |
| |
| use constants::*; |
| use data_model::Le16; |
| use data_model::SLe32; |
| use zerocopy::AsBytes; |
| use zerocopy::FromBytes; |
| use zerocopy::FromZeroes; |
| |
| /// Allows a raw input event of the implementor's type to be decoded into |
| /// a virtio_input_event. |
| pub trait InputEventDecoder { |
| const SIZE: usize; |
| fn decode(data: &[u8]) -> virtio_input_event; |
| } |
| |
| #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, FromZeroes, FromBytes, AsBytes)] |
| #[repr(C)] |
| pub struct input_event { |
| pub timestamp_fields: [u64; 2], |
| pub type_: u16, |
| pub code: u16, |
| pub value: i32, |
| } |
| |
| impl input_event { |
| pub fn from_virtio_input_event(other: &virtio_input_event) -> input_event { |
| input_event { |
| timestamp_fields: [0, 0], |
| type_: other.type_.into(), |
| code: other.code.into(), |
| value: other.value.into(), |
| } |
| } |
| } |
| |
| impl InputEventDecoder for input_event { |
| const SIZE: usize = size_of::<Self>(); |
| |
| fn decode(data: &[u8]) -> virtio_input_event { |
| let e = input_event::read_from(data).unwrap(); |
| virtio_input_event { |
| type_: Le16::from(e.type_), |
| code: Le16::from(e.code), |
| value: SLe32::from(e.value), |
| } |
| } |
| } |
| |
| #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, AsBytes, FromZeroes, FromBytes)] |
| #[repr(C)] |
| pub struct virtio_input_event { |
| pub type_: Le16, |
| pub code: Le16, |
| pub value: SLe32, |
| } |
| |
| impl InputEventDecoder for virtio_input_event { |
| const SIZE: usize = size_of::<Self>(); |
| |
| fn decode(data: &[u8]) -> virtio_input_event { |
| virtio_input_event::read_from(data).unwrap() |
| } |
| } |
| |
| impl virtio_input_event { |
| #[inline] |
| pub fn syn() -> virtio_input_event { |
| virtio_input_event { |
| type_: Le16::from(EV_SYN), |
| code: Le16::from(SYN_REPORT), |
| value: SLe32::from(0), |
| } |
| } |
| |
| #[inline] |
| pub fn absolute(code: u16, value: i32) -> virtio_input_event { |
| virtio_input_event { |
| type_: Le16::from(EV_ABS), |
| code: Le16::from(code), |
| value: SLe32::from(value), |
| } |
| } |
| |
| #[inline] |
| pub fn relative(code: u16, value: i32) -> virtio_input_event { |
| virtio_input_event { |
| type_: Le16::from(EV_REL), |
| code: Le16::from(code), |
| value: SLe32::from(value), |
| } |
| } |
| |
| #[inline] |
| pub fn multitouch_tracking_id(id: i32) -> virtio_input_event { |
| Self::absolute(ABS_MT_TRACKING_ID, id) |
| } |
| |
| #[inline] |
| pub fn multitouch_slot(slot: i32) -> virtio_input_event { |
| Self::absolute(ABS_MT_SLOT, slot) |
| } |
| |
| #[inline] |
| pub fn multitouch_absolute_x(x: i32) -> virtio_input_event { |
| Self::absolute(ABS_MT_POSITION_X, x) |
| } |
| |
| #[inline] |
| pub fn multitouch_absolute_y(y: i32) -> virtio_input_event { |
| Self::absolute(ABS_MT_POSITION_Y, y) |
| } |
| |
| #[inline] |
| pub fn absolute_x(x: i32) -> virtio_input_event { |
| Self::absolute(ABS_X, x) |
| } |
| |
| #[inline] |
| pub fn absolute_y(y: i32) -> virtio_input_event { |
| Self::absolute(ABS_Y, y) |
| } |
| |
| #[inline] |
| pub fn relative_x(x: i32) -> virtio_input_event { |
| Self::relative(REL_X, x) |
| } |
| |
| #[inline] |
| pub fn relative_y(y: i32) -> virtio_input_event { |
| Self::relative(REL_Y, y) |
| } |
| |
| #[inline] |
| pub fn touch(has_contact: bool) -> virtio_input_event { |
| Self::key(BTN_TOUCH, has_contact, false) |
| } |
| |
| #[inline] |
| pub fn left_click(has_contact: bool) -> virtio_input_event { |
| Self::key(BTN_LEFT, has_contact, false) |
| } |
| |
| #[inline] |
| pub fn wheel(delta: i32) -> virtio_input_event { |
| Self::relative(REL_WHEEL, delta) |
| } |
| |
| #[inline] |
| pub fn right_click(has_contact: bool) -> virtio_input_event { |
| Self::key(BTN_RIGHT, has_contact, false) |
| } |
| |
| #[inline] |
| pub fn middle_click(has_contact: bool) -> virtio_input_event { |
| Self::key(BTN_MIDDLE, has_contact, false) |
| } |
| |
| #[inline] |
| pub fn forward_click(has_contact: bool) -> virtio_input_event { |
| Self::key(BTN_FORWARD, has_contact, false) |
| } |
| |
| #[inline] |
| pub fn back_click(has_contact: bool) -> virtio_input_event { |
| Self::key(BTN_BACK, has_contact, false) |
| } |
| |
| #[inline] |
| pub fn finger_tool(active: bool) -> virtio_input_event { |
| Self::key(BTN_TOOL_FINGER, active, false) |
| } |
| |
| /// Repeated keys must set the `repeat` option if the key was already down, or repeated keys |
| /// will not be seen correctly by the guest. |
| #[inline] |
| pub fn key(code: u16, down: bool, repeat: bool) -> virtio_input_event { |
| virtio_input_event { |
| type_: Le16::from(EV_KEY), |
| code: Le16::from(code), |
| value: SLe32::from(match (down, repeat) { |
| (true, true) => 2, |
| (true, false) => 1, |
| // repeat is not meaningful for key up events. |
| _ => 0, |
| }), |
| } |
| } |
| |
| /// If the event is EV_LED for the given LED code, return if it is on. |
| pub fn get_led_state(&self, led_code: u16) -> Option<bool> { |
| if self.type_ == EV_LED && self.code == led_code { |
| return match self.value.to_native() { |
| 0 => Some(false), |
| 1 => Some(true), |
| _ => None, |
| }; |
| } |
| None |
| } |
| } |