diff --git a/Cargo.lock b/Cargo.lock index 9536949058..8dc6ff4359 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,6 +153,7 @@ dependencies = [ "kvm 0.1.0", "kvm_sys 0.1.0", "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "linux_input_sys 0.1.0", "msg_on_socket_derive 0.1.0", "msg_socket 0.1.0", "net_sys 0.1.0", @@ -218,6 +219,7 @@ dependencies = [ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "data_model 0.1.0", "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "linux_input_sys 0.1.0", "sys_util 0.1.0", ] @@ -289,6 +291,15 @@ dependencies = [ "sys_util 0.1.0", ] +[[package]] +name = "linux_input_sys" +version = "0.1.0" +dependencies = [ + "data_model 0.1.0", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", + "sys_util 0.1.0", +] + [[package]] name = "log" version = "0.4.5" diff --git a/devices/Cargo.toml b/devices/Cargo.toml index 7ea90b54b5..236cf4e296 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -24,6 +24,7 @@ io_jail = { path = "../io_jail" } kvm = { path = "../kvm" } kvm_sys = { path = "../kvm_sys" } libc = "*" +linux_input_sys = { path = "../linux_input_sys" } msg_on_socket_derive = { path = "../msg_socket/msg_on_socket_derive" } msg_socket = { path = "../msg_socket" } net_sys = { path = "../net_sys" } diff --git a/devices/src/virtio/input/event_source.rs b/devices/src/virtio/input/event_source.rs index 7ca7e13c8d..d190e18dc0 100644 --- a/devices/src/virtio/input/event_source.rs +++ b/devices/src/virtio/input/event_source.rs @@ -8,6 +8,7 @@ use super::virtio_input_event; use super::InputError; use super::Result; use data_model::DataInit; +use linux_input_sys::input_event; use std::collections::VecDeque; use std::io::Read; use std::io::Write; @@ -15,20 +16,11 @@ use std::mem::size_of; use std::os::unix::io::{AsRawFd, RawFd}; use sys_util::{error, warn}; -#[derive(Copy, Clone, Debug, Default)] -#[repr(C)] -pub struct input_event { - timestamp_fields: [u64; 2], - pub type_: u16, - pub code: u16, - pub value: u32, +trait ConvertFromVirtioInputEvent { + fn from_virtio_input_event(other: &virtio_input_event) -> input_event; } -// Safe because it only has data and has no implicit padding. -unsafe impl DataInit for input_event {} - -impl input_event { - const EVENT_SIZE: usize = size_of::(); +impl ConvertFromVirtioInputEvent for input_event { fn from_virtio_input_event(other: &virtio_input_event) -> input_event { input_event { timestamp_fields: [0, 0], diff --git a/devices/src/virtio/input/mod.rs b/devices/src/virtio/input/mod.rs index 2490c523cf..fb0524043c 100644 --- a/devices/src/virtio/input/mod.rs +++ b/devices/src/virtio/input/mod.rs @@ -15,11 +15,12 @@ use std::os::unix::io::{AsRawFd, RawFd}; use data_model::{DataInit, Le16, Le32}; use sys_util::{error, warn, EventFd, GuestMemory, PollContext, PollToken}; -use self::event_source::{input_event, EvdevEventSource, EventSource, SocketEventSource}; +use self::event_source::{EvdevEventSource, EventSource, SocketEventSource}; use super::{ copy_config, DescriptorChain, DescriptorError, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_INPUT, }; +use linux_input_sys::input_event; use std::collections::BTreeMap; use std::fmt::{self, Display}; use std::io::Read; diff --git a/gpu_display/Cargo.toml b/gpu_display/Cargo.toml index 54f2bad0fe..21ee9ca4e0 100644 --- a/gpu_display/Cargo.toml +++ b/gpu_display/Cargo.toml @@ -11,6 +11,7 @@ x = [] data_model = { path = "../data_model" } libc = "*" sys_util = { path = "../sys_util" } +linux_input_sys = { path = "../linux_input_sys" } [build-dependencies] cc = "=1.0.25" diff --git a/gpu_display/src/event_device.rs b/gpu_display/src/event_device.rs index 673a104698..5f1bbc7e59 100644 --- a/gpu_display/src/event_device.rs +++ b/gpu_display/src/event_device.rs @@ -2,25 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +use data_model::DataInit; +use linux_input_sys::input_event; use std::collections::VecDeque; -use std::io::{self, Read, Write}; +use std::io::{self, Error, ErrorKind, 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_SIZE: usize = input_event::EVENT_SIZE; 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); @@ -45,69 +37,6 @@ pub enum EventDeviceKind { 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, @@ -164,7 +93,7 @@ impl EventDevice { self.event_buffer.is_empty() } - pub fn send_report>( + pub fn send_report>( &mut self, events: E, ) -> io::Result @@ -177,24 +106,24 @@ impl EventDevice { } for event in it { - let bytes = event.to_bytes(); + let bytes = event.as_slice(); self.event_buffer.extend(bytes.iter()); } self.event_buffer - .extend(EventEncoded::syn().to_bytes().iter()); + .extend(input_event::syn().as_slice().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 { + pub fn send_event_encoded(&mut self, event: input_event) -> io::Result { if !self.flush_buffered_events()? { return Ok(false); } - let bytes = event.to_bytes(); + let bytes = event.as_slice(); let written = self.event_socket.write(&bytes)?; if written == bytes.len() { @@ -208,10 +137,16 @@ impl EventDevice { Ok(false) } - pub fn recv_event_encoded(&self) -> io::Result { - let mut event_bytes = [0; 8]; + pub fn recv_event_encoded(&self) -> io::Result { + let mut event_bytes = [0u8; 24]; (&self.event_socket).read_exact(&mut event_bytes)?; - Ok(EventEncoded::from_bytes(event_bytes)) + match input_event::from_slice(&event_bytes) { + Some(event) => Ok(*event), + None => Err(Error::new( + ErrorKind::InvalidInput, + "failed to read input_event", + )), + } } } diff --git a/gpu_display/src/generated/xlib.rs b/gpu_display/src/generated/xlib.rs index 1dc4c9bef6..f6ff382404 100644 --- a/gpu_display/src/generated/xlib.rs +++ b/gpu_display/src/generated/xlib.rs @@ -20,9 +20,13 @@ pub const PointerMotionMask: u32 = 64; pub const ExposureMask: u32 = 32768; pub const KeyPress: u32 = 2; pub const KeyRelease: u32 = 3; +pub const ButtonPress: u32 = 4; +pub const ButtonRelease: u32 = 5; pub const MotionNotify: u32 = 6; pub const Expose: u32 = 12; pub const ClientMessage: u32 = 33; +pub const Button1Mask: u32 = 256; +pub const Button1: u32 = 1; pub const ZPixmap: u32 = 2; pub const XK_VoidSymbol: u32 = 16777215; pub const XK_BackSpace: u32 = 65288; diff --git a/gpu_display/src/generated/xlib_generator.sh b/gpu_display/src/generated/xlib_generator.sh index e64d6620cd..304904a7a6 100755 --- a/gpu_display/src/generated/xlib_generator.sh +++ b/gpu_display/src/generated/xlib_generator.sh @@ -55,7 +55,11 @@ bindgen --no-layout-tests --no-derive-debug \ --whitelist-function XShmPutImage \ --whitelist-function XShmQueryExtension \ --whitelist-var 'XK_.*' \ + --whitelist-var ButtonPress \ --whitelist-var ButtonPressMask \ + --whitelist-var Button1 \ + --whitelist-var Button1Mask \ + --whitelist-var ButtonRelease \ --whitelist-var ButtonReleaseMask \ --whitelist-var ClientMessage \ --whitelist-var Expose \ diff --git a/gpu_display/src/gpu_display_x.rs b/gpu_display/src/gpu_display_x.rs index 1df7fc204e..c0074ca48c 100644 --- a/gpu_display/src/gpu_display_x.rs +++ b/gpu_display/src/gpu_display_x.rs @@ -11,6 +11,8 @@ )] mod xlib; +use linux_input_sys::input_event; +use std::cmp::max; use std::collections::BTreeMap; use std::ffi::{c_void, CStr, CString}; use std::mem::{transmute_copy, zeroed}; @@ -18,17 +20,22 @@ use std::num::NonZeroU32; use std::os::raw::c_ulong; use std::os::unix::io::{AsRawFd, RawFd}; use std::ptr::{null, null_mut, NonNull}; -use std::rc::Rc; +use std::rc::{Rc, Weak}; +use std::time::Duration; use libc::{shmat, shmctl, shmdt, shmget, IPC_CREAT, IPC_PRIVATE, IPC_RMID}; -use crate::{DisplayT, EventDevice, GpuDisplayError, GpuDisplayFramebuffer}; +use crate::{ + keycode_converter::KeycodeTranslator, keycode_converter::KeycodeTypes, DisplayT, EventDevice, + EventDeviceKind, GpuDisplayError, GpuDisplayFramebuffer, +}; use data_model::VolatileSlice; +use sys_util::{error, PollContext, PollToken, WatchingEvents}; const BUFFER_COUNT: usize = 2; -type SurfaceId = NonZeroU32; +type ObjectId = NonZeroU32; /// A wrapper for XFree that takes any type. unsafe fn x_free(t: *mut T) { @@ -119,6 +126,16 @@ impl XEvent { // Some of the event types are dynamic so they need to be passed in. fn as_enum(&self, shm_complete_type: u32) -> XEventEnum { match self.type_() { + xlib::KeyPress | xlib::KeyRelease => XEventEnum::KeyEvent(unsafe { self.0.xkey }), + xlib::ButtonPress => XEventEnum::ButtonEvent { + event: unsafe { self.0.xbutton }, + pressed: true, + }, + xlib::ButtonRelease => XEventEnum::ButtonEvent { + event: unsafe { self.0.xbutton }, + pressed: false, + }, + xlib::MotionNotify => XEventEnum::Motion(unsafe { self.0.xmotion }), xlib::Expose => XEventEnum::Expose, xlib::ClientMessage => { XEventEnum::ClientMessage(unsafe { self.0.xclient.data.l[0] as u64 }) @@ -136,6 +153,12 @@ impl XEvent { } enum XEventEnum { + KeyEvent(xlib::XKeyEvent), + ButtonEvent { + event: xlib::XButtonEvent, + pressed: bool, + }, + Motion(xlib::XMotionEvent), Expose, ClientMessage(u64), ShmCompletionEvent(xlib::ShmSeg), @@ -201,6 +224,8 @@ struct Surface { gc: xlib::GC, width: u32, height: u32, + event_devices: BTreeMap, + keycode_translator: KeycodeTranslator, // Fields for handling the buffer swap chain. buffers: [Option; BUFFER_COUNT], @@ -220,6 +245,7 @@ impl Surface { width: u32, height: u32, ) -> Result { + let keycode_translator = KeycodeTranslator::new(KeycodeTypes::XkbScancode); unsafe { let depth = xlib::XDefaultDepthOfScreen(screen.as_ptr()) as u32; @@ -263,7 +289,16 @@ impl Surface { x_free(size_hints); // We will use redraw the buffer when we are exposed. - xlib::XSelectInput(display.as_ptr(), window, xlib::ExposureMask as i64); + xlib::XSelectInput( + display.as_ptr(), + window, + (xlib::ExposureMask + | xlib::KeyPressMask + | xlib::KeyReleaseMask + | xlib::ButtonPressMask + | xlib::ButtonReleaseMask + | xlib::PointerMotionMask) as i64, + ); xlib::XClearWindow(display.as_ptr(), window); xlib::XMapRaised(display.as_ptr(), window); @@ -279,6 +314,8 @@ impl Surface { gc, width, height, + event_devices: Default::default(), + keycode_translator, buffers: Default::default(), buffer_next: 0, buffer_completion_type, @@ -296,8 +333,53 @@ impl Surface { } } + fn dispatch_to_event_devices(&mut self, events: &[input_event], device_type: EventDeviceKind) { + for event_device in self.event_devices.values_mut() { + if event_device.kind() != device_type { + continue; + } + if let Err(e) = event_device.send_report(events.iter().cloned()) { + error!("error sending events to event device: {}", e); + } + } + } + fn handle_event(&mut self, ev: XEvent) { match ev.as_enum(self.buffer_completion_type) { + XEventEnum::KeyEvent(key) => { + if let Some(linux_keycode) = self.keycode_translator.translate(key.keycode) { + let events = &[input_event::key( + linux_keycode, + key.type_ == xlib::KeyPress as i32, + )]; + self.dispatch_to_event_devices(events, EventDeviceKind::Keyboard); + } + } + XEventEnum::ButtonEvent { + event: button_event, + pressed, + } => { + // We only support a single touch from button 1 (left mouse button). + if button_event.button & xlib::Button1 != 0 { + // The touch event *must* be first per the Linux input subsystem's guidance. + let events = &[ + input_event::touch(pressed), + input_event::absolute_x(max(0, button_event.x) as u32), + input_event::absolute_y(max(0, button_event.y) as u32), + ]; + self.dispatch_to_event_devices(events, EventDeviceKind::Touchscreen); + } + } + XEventEnum::Motion(motion) => { + if motion.state & xlib::Button1Mask != 0 { + let events = &[ + input_event::touch(true), + input_event::absolute_x(max(0, motion.x) as u32), + input_event::absolute_y(max(0, motion.y) as u32), + ]; + self.dispatch_to_event_devices(events, EventDeviceKind::Touchscreen); + } + } XEventEnum::Expose => self.draw_buffer(self.current_buffer()), XEventEnum::ClientMessage(xclient_data) => { if xclient_data == self.delete_window_atom { @@ -449,16 +531,26 @@ impl Drop for Surface { } } +#[derive(PollToken)] +enum DisplayXPollToken { + Display, + EventDevice { event_device_id: u32 }, +} + pub struct DisplayX { + poll_ctx: PollContext, display: XDisplay, screen: XScreen, visual: *mut xlib::Visual, - next_surface_id: SurfaceId, - surfaces: BTreeMap, + next_id: ObjectId, + surfaces: BTreeMap, + event_devices: BTreeMap, } impl DisplayX { pub fn open_display(display: Option<&str>) -> Result { + let poll_ctx = PollContext::new().map_err(|_| GpuDisplayError::Allocate)?; + let display_cstr = match display.map(CString::new) { Some(Ok(s)) => Some(s), Some(Err(_)) => return Err(GpuDisplayError::InvalidPath), @@ -477,6 +569,10 @@ impl DisplayX { None => return Err(GpuDisplayError::Connect), }; + poll_ctx + .add(&display, DisplayXPollToken::Display) + .map_err(|_| GpuDisplayError::Allocate)?; + // Check for required extension. if !display.supports_shm() { return Err(GpuDisplayError::RequiredFeature("xshm extension")); @@ -518,21 +614,31 @@ impl DisplayX { x_free(visual_info); Ok(DisplayX { + poll_ctx, display, screen, visual, - next_surface_id: SurfaceId::new(1).unwrap(), + next_id: ObjectId::new(1).unwrap(), surfaces: Default::default(), + event_devices: Default::default(), }) } } fn surface_ref(&self, surface_id: u32) -> Option<&Surface> { - SurfaceId::new(surface_id).and_then(move |id| self.surfaces.get(&id)) + ObjectId::new(surface_id).and_then(move |id| self.surfaces.get(&id)) } fn surface_mut(&mut self, surface_id: u32) -> Option<&mut Surface> { - SurfaceId::new(surface_id).and_then(move |id| self.surfaces.get_mut(&id)) + ObjectId::new(surface_id).and_then(move |id| self.surfaces.get_mut(&id)) + } + + fn event_device(&self, event_device_id: u32) -> Option<&EventDevice> { + ObjectId::new(event_device_id).and_then(move |id| self.event_devices.get(&id)) + } + + fn event_device_mut(&mut self, event_device_id: u32) -> Option<&mut EventDevice> { + ObjectId::new(event_device_id).and_then(move |id| self.event_devices.get_mut(&id)) } fn handle_event(&mut self, ev: XEvent) { @@ -545,10 +651,8 @@ impl DisplayX { return; } } -} -impl DisplayT for DisplayX { - fn dispatch_events(&mut self) { + fn dispatch_display_events(&mut self) { loop { self.display.flush(); if !self.display.pending_events() { @@ -559,6 +663,54 @@ impl DisplayT for DisplayX { } } + fn handle_event_device(&mut self, event_device_id: u32) { + if let Some(event_device) = self.event_device(event_device_id) { + // TODO(zachr): decode the event and forward to the device. + let _ = event_device.recv_event_encoded(); + } + } + + fn handle_poll_ctx(&mut self) -> sys_util::Result<()> { + let poll_events = self.poll_ctx.wait_timeout(Duration::default())?.to_owned(); + for poll_event in poll_events.as_ref().iter_writable() { + if let DisplayXPollToken::EventDevice { event_device_id } = poll_event.token() { + if let Some(event_device) = self.event_device_mut(event_device_id) { + if !event_device.flush_buffered_events()? { + continue; + } + } + // Although this looks exactly like the previous if-block, we need to reborrow self + // as immutable in order to make use of self.poll_ctx. + if let Some(event_device) = self.event_device(event_device_id) { + self.poll_ctx.modify( + event_device, + WatchingEvents::empty().set_read(), + DisplayXPollToken::EventDevice { event_device_id }, + )?; + } + } + } + + for poll_event in poll_events.as_ref().iter_readable() { + match poll_event.token() { + DisplayXPollToken::Display => self.dispatch_display_events(), + DisplayXPollToken::EventDevice { event_device_id } => { + self.handle_event_device(event_device_id) + } + } + } + + Ok(()) + } +} + +impl DisplayT for DisplayX { + fn dispatch_events(&mut self) { + if let Err(e) = self.handle_poll_ctx() { + error!("failed to dispatch events: {}", e); + } + } + fn create_surface( &mut self, parent_surface_id: Option, @@ -576,15 +728,19 @@ impl DisplayT for DisplayX { width, height, )?; - let new_surface_id = self.next_surface_id; + let new_surface_id = self.next_id; self.surfaces.insert(new_surface_id, new_surface); - self.next_surface_id = SurfaceId::new(self.next_surface_id.get() + 1).unwrap(); + self.next_id = ObjectId::new(self.next_id.get() + 1).unwrap(); Ok(new_surface_id.get()) } fn release_surface(&mut self, surface_id: u32) { - SurfaceId::new(surface_id).and_then(|id| self.surfaces.remove(&id)); + if let Some(mut surface) = + ObjectId::new(surface_id).and_then(|id| self.surfaces.remove(&id)) + { + self.event_devices.append(&mut surface.event_devices); + } } fn framebuffer(&mut self, surface_id: u32) -> Option { @@ -638,19 +794,46 @@ impl DisplayT for DisplayX { fn set_position(&mut self, surface_id: u32, x: u32, y: u32) { // unsupported } - fn import_event_device(&mut self, _event_device: EventDevice) -> Result { - Err(GpuDisplayError::Unsupported) + + fn import_event_device(&mut self, event_device: EventDevice) -> Result { + let new_event_device_id = self.next_id; + + self.poll_ctx + .add( + &event_device, + DisplayXPollToken::EventDevice { + event_device_id: new_event_device_id.get(), + }, + ) + .map_err(|_| GpuDisplayError::Allocate)?; + + self.event_devices.insert(new_event_device_id, event_device); + self.next_id = ObjectId::new(self.next_id.get() + 1).unwrap(); + + Ok(new_event_device_id.get()) } - fn release_event_device(&mut self, _event_device_id: u32) { - // unsupported + + fn release_event_device(&mut self, event_device_id: u32) { + ObjectId::new(event_device_id).and_then(|id| self.event_devices.remove(&id)); } + fn attach_event_device(&mut self, surface_id: u32, event_device_id: u32) { - // unsupported + let event_device_id = match ObjectId::new(event_device_id) { + Some(id) => id, + None => return, + }; + let surface_id = match ObjectId::new(surface_id) { + Some(id) => id, + None => return, + }; + let surface = self.surfaces.get_mut(&surface_id).unwrap(); + let event_device = self.event_devices.remove(&event_device_id).unwrap(); + surface.event_devices.insert(event_device_id, event_device); } } impl AsRawFd for DisplayX { fn as_raw_fd(&self) -> RawFd { - self.display.as_raw_fd() + self.poll_ctx.as_raw_fd() } } diff --git a/gpu_display/src/lib.rs b/gpu_display/src/lib.rs index 8985405004..1d9fcdce70 100644 --- a/gpu_display/src/lib.rs +++ b/gpu_display/src/lib.rs @@ -17,7 +17,7 @@ mod gpu_display_wl; mod gpu_display_x; mod keycode_converter; -pub use event_device::{EventDevice, EventDeviceKind, EventEncoded}; +pub use event_device::{EventDevice, EventDeviceKind}; /// An error generated by `GpuDisplay`. #[derive(Debug)]