From 6f8823abb55e2d9f65cf7abe5635c59280fcf172 Mon Sep 17 00:00:00 2001 From: Zach Reizner Date: Fri, 22 Nov 2019 17:19:38 -0800 Subject: gpu_display: add EventDevice to bridge gpu_display to a virtual input device The EventDevice is a data structure that allows a generic gpu display to send and receive input events in evdev's format to a generic input device, such as virtio-input. BUG=chromium:1023975 TEST=None Change-Id: Ic663cc8c7a3031aee929e09620c5430c27a25190 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1930406 Reviewed-by: Daniel Verkamp Reviewed-by: Stephen Barber Reviewed-by: Noah Gold Tested-by: Daniel Verkamp Tested-by: kokoro Commit-Queue: Daniel Verkamp --- gpu_display/src/event_device.rs | 222 ++++++++++++++++++++++++++++++++++++++++ gpu_display/src/lib.rs | 3 + 2 files changed, 225 insertions(+) create mode 100644 gpu_display/src/event_device.rs (limited to 'gpu_display') diff --git a/gpu_display/src/event_device.rs b/gpu_display/src/event_device.rs new file mode 100644 index 0000000..673a104 --- /dev/null +++ b/gpu_display/src/event_device.rs @@ -0,0 +1,222 @@ +// Copyright 2019 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use std::collections::VecDeque; +use std::io::{self, Read, Write}; +use std::iter::ExactSizeIterator; +use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::net::UnixStream; + +const EVENT_SIZE: usize = 4; +const EVENT_BUFFER_LEN_MAX: usize = 16 * EVENT_SIZE; + +const EV_SYN: u16 = 0x00; +const EV_KEY: u16 = 0x01; +const EV_REL: u16 = 0x02; +const EV_ABS: u16 = 0x03; +const SYN_REPORT: u16 = 0; +const REL_X: u16 = 0x00; +const REL_Y: u16 = 0x01; +const ABS_X: u16 = 0x00; +const ABS_Y: u16 = 0x01; + +// /// Half-way build `EventDevice` with only the `event_socket` defined. Finish building the +// /// `EventDevice` by using `status_socket`. +// pub struct PartialEventDevice(UnixStream); + +// impl PartialEventDevice { +// /// Finish build `EventDevice` by providing the `status_socket`. +// pub fn status_socket(self, status_socket: UnixStream) -> EventDevice { +// EventDevice { +// event_socket: self.0, +// status_socket, +// } +// } +// } + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum EventDeviceKind { + /// Produces relative mouse motions, wheel, and button clicks while the real mouse is captured. + Mouse, + /// Produces absolute motion and touch events from the display window's events. + Touchscreen, + /// Produces key events while the display window has focus. + Keyboard, +} + +#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)] +pub struct EventEncoded { + pub type_: u16, + pub code: u16, + pub value: u32, +} + +impl EventEncoded { + #[inline] + pub fn syn() -> EventEncoded { + EventEncoded { + type_: EV_SYN, + code: SYN_REPORT, + value: 0, + } + } + + #[inline] + pub fn absolute(code: u16, value: u32) -> EventEncoded { + EventEncoded { + type_: EV_ABS, + code, + value, + } + } + + #[inline] + pub fn absolute_x(x: u32) -> EventEncoded { + Self::absolute(ABS_X, x) + } + + #[inline] + pub fn absolute_y(y: u32) -> EventEncoded { + Self::absolute(ABS_Y, y) + } + + #[inline] + pub fn key(code: u16, pressed: bool) -> EventEncoded { + EventEncoded { + type_: EV_KEY, + code, + value: if pressed { 1 } else { 0 }, + } + } + + #[inline] + pub fn from_bytes(v: [u8; 8]) -> EventEncoded { + EventEncoded { + type_: u16::from_le_bytes([v[0], v[1]]), + code: u16::from_le_bytes([v[2], v[3]]), + value: u32::from_le_bytes([v[4], v[5], v[6], v[7]]), + } + } + + #[inline] + pub fn to_bytes(&self) -> [u8; 8] { + let a = self.type_.to_le_bytes(); + let b = self.code.to_le_bytes(); + let c = self.value.to_le_bytes(); + [a[0], a[1], b[0], b[1], c[0], c[1], c[2], c[3]] + } +} + +/// Encapsulates a virtual event device, such as a mouse or keyboard +pub struct EventDevice { + kind: EventDeviceKind, + event_buffer: VecDeque, + event_socket: UnixStream, +} + +impl EventDevice { + pub fn new(kind: EventDeviceKind, event_socket: UnixStream) -> EventDevice { + let _ = event_socket.set_nonblocking(true); + EventDevice { + kind, + event_buffer: Default::default(), + event_socket, + } + } + + #[inline] + pub fn mouse(event_socket: UnixStream) -> EventDevice { + Self::new(EventDeviceKind::Mouse, event_socket) + } + + #[inline] + pub fn touchscreen(event_socket: UnixStream) -> EventDevice { + Self::new(EventDeviceKind::Touchscreen, event_socket) + } + + #[inline] + pub fn keyboard(event_socket: UnixStream) -> EventDevice { + Self::new(EventDeviceKind::Keyboard, event_socket) + } + + #[inline] + pub fn kind(&self) -> EventDeviceKind { + self.kind + } + + /// Flushes the buffered events that did not fit into the underlying transport, if any. + /// + /// Returns `Ok(true)` if, after this function returns, there all the buffer of events is + /// empty. + pub fn flush_buffered_events(&mut self) -> io::Result { + while !self.event_buffer.is_empty() { + let written = self.event_socket.write(&self.event_buffer.as_slices().0)?; + if written == 0 { + return Ok(false); + } + self.event_buffer.drain(..written); + } + Ok(true) + } + + pub fn is_buffered_events_empty(&self) -> bool { + self.event_buffer.is_empty() + } + + pub fn send_report>( + &mut self, + events: E, + ) -> io::Result + where + E::IntoIter: ExactSizeIterator, + { + let it = events.into_iter(); + if self.event_buffer.len() > (EVENT_BUFFER_LEN_MAX - EVENT_SIZE * (it.len() + 1)) { + return Ok(false); + } + + for event in it { + let bytes = event.to_bytes(); + self.event_buffer.extend(bytes.iter()); + } + + self.event_buffer + .extend(EventEncoded::syn().to_bytes().iter()); + + self.flush_buffered_events() + } + + /// Sends the given `event`, returning `Ok(true)` if, after this function returns, there are no + /// buffered events remaining. + pub fn send_event_encoded(&mut self, event: EventEncoded) -> io::Result { + if !self.flush_buffered_events()? { + return Ok(false); + } + + let bytes = event.to_bytes(); + let written = self.event_socket.write(&bytes)?; + + if written == bytes.len() { + return Ok(true); + } + + if self.event_buffer.len() <= (EVENT_BUFFER_LEN_MAX - EVENT_SIZE) { + self.event_buffer.extend(bytes[written..].iter()); + } + + Ok(false) + } + + pub fn recv_event_encoded(&self) -> io::Result { + let mut event_bytes = [0; 8]; + (&self.event_socket).read_exact(&mut event_bytes)?; + Ok(EventEncoded::from_bytes(event_bytes)) + } +} + +impl AsRawFd for EventDevice { + fn as_raw_fd(&self) -> RawFd { + self.event_socket.as_raw_fd() + } +} diff --git a/gpu_display/src/lib.rs b/gpu_display/src/lib.rs index 3067c0e..5c243d6 100644 --- a/gpu_display/src/lib.rs +++ b/gpu_display/src/lib.rs @@ -11,10 +11,13 @@ use std::path::Path; use data_model::VolatileSlice; use sys_util::Error as SysError; +mod event_device; mod gpu_display_wl; #[cfg(feature = "x")] mod gpu_display_x; +pub use event_device::{EventDevice, EventDeviceKind, EventEncoded}; + /// An error generated by `GpuDisplay`. #[derive(Debug)] pub enum GpuDisplayError { -- cgit 1.4.1