From 60a7523d4b14e31c028c3e96f3fe5ad74a137ca5 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Thu, 27 Apr 2017 19:42:45 -0400 Subject: [PATCH] Fix all the current issues: Changes in Rust, changes in the evdev ABI, and a bug --- Cargo.toml | 16 ++++++------- README.md | 12 +++++++--- src/lib.rs | 67 ++++++++++++++++++++++++---------------------------- src/tests.rs | 2 +- 4 files changed, 49 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 593ee46..53c97a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,19 @@ [package] name = "evdev" -version = "0.9.2" +version = "0.9.3" authors = ["Corey Richardson "] description = "evdev interface for Linux" -license = "BSL-1.0/Apache-2.0" +license = "Apache-2.0 OR MIT" repository = "https://github.com/cmr/evdev" -documentation = "https://cmr.github.io/evdev" +documentation = "https://docs.rs/evdev" [dependencies] ioctl = "0.3.3" -bitflags = "*" -errno = "*" -libc = "*" -fixedbitset = "*" -num = "*" +bitflags = "0.8.2" +errno = "0.2.3" +libc = "0.2.22" +fixedbitset = "0.1.6" +num = "0.1.37" [features] unstable = [] diff --git a/README.md b/README.md index 326656f..0fd6f0c 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,16 @@ [![Travis](https://img.shields.io/travis/cmr/evdev.svg?style=flat-square)](https://travis-ci.org/cmr/evdev) [![Crates.io](https://img.shields.io/crates/v/evdev.svg?style=flat-square)](https://crates.io/crates/evdev) -[Documentation](https://cmr.github.io/evdev) +[Documentation](https://docs.rs/evdev) -Nice(r) access to `evdev`. Works on Rust >= 1.2.0. +Nice(r) access to `evdev` devices. What is `evdev`? =================== -`evdev` is the Linux kernel's generic input interface. +`evdev` is the Linux kernel's generic input interface. This crate exposes +access to these sorts of input devices. There is some trickery involved, so +please read the crate documentation. What does this library support? =============================== @@ -23,6 +25,10 @@ closely, where possible. Writing to devices is not yet supported (eg, turning LEDs on). +There is no abstraction for gamepad-like devices that allows mapping button +numbers to logical buttons, nor is one planned. Such a thing should take place +in a higher-level crate, likely supporting multiple platforms. + Example ======= diff --git a/src/lib.rs b/src/lib.rs index 8f3f01e..b7c9440 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ //! `Device::sync_state` to explicitly synchronize with the kernel state. //! //! As the state changes, the kernel will write events into a ring buffer. The application can read -//! from this ring buffer, thus retreiving events. However, if the ring buffer becomes full, the +//! from this ring buffer, thus retrieving events. However, if the ring buffer becomes full, the //! kernel will *drop* every event in the ring buffer and leave an event telling userspace that it //! did so. At this point, if the application were using the events it received to update its //! internal idea of what state the hardware device is in, it will be wrong: it is missing some @@ -32,6 +32,7 @@ //! fd returned by `Device::fd` to process events when they are ready. #![cfg(any(target_os = "linux", target_os = "android"))] +#![allow(non_camel_case_types)] #[macro_use] extern crate bitflags; @@ -47,6 +48,7 @@ use std::path::Path; use std::ffi::CString; use std::mem::size_of; use fixedbitset::FixedBitSet; +use num::traits::WrappingSub; pub use Key::*; pub use FFEffect::*; @@ -101,7 +103,7 @@ impl std::ops::Deref for Fd { bitflags! { /// Event types supported by the device. - flags Types: u32 { + pub flags Types: u32 { /// A bookkeeping event. Usually not important to applications. const SYNCHRONIZATION = 1 << 0x00, /// A key changed state. A key, or button, is usually a momentary switch (in the circuit sense). It has two @@ -140,7 +142,7 @@ bitflags! { bitflags! { /// Device properties. - flags Props: u32 { + pub flags Props: u32 { /// This input device needs a pointer ("cursor") for the user to know its state. const POINTER = 1 << 0x00, /// "direct input devices", according to the header. @@ -162,7 +164,7 @@ bitflags! { include!("scancodes.rs"); // it's a huge glob of text that I'm tired of skipping over. bitflags! { - flags RelativeAxis: u32 { + pub flags RelativeAxis: u32 { const REL_X = 1 << 0x00, const REL_Y = 1 << 0x01, const REL_Z = 1 << 0x02, @@ -177,7 +179,7 @@ bitflags! { } bitflags! { - flags AbsoluteAxis: u64 { + pub flags AbsoluteAxis: u64 { const ABS_X = 1 << 0x00, const ABS_Y = 1 << 0x01, const ABS_Z = 1 << 0x02, @@ -234,12 +236,11 @@ bitflags! { const ABS_MT_TOOL_X = 1 << 0x3c, /// "Center Y tool position" const ABS_MT_TOOL_Y = 1 << 0x3d, - const ABS_MAX = 1 << 0x3f, } } bitflags! { - flags Switch: u32 { + pub flags Switch: u32 { /// "set = lid shut" const SW_LID = 1 << 0x00, /// "set = tablet mode" @@ -270,16 +271,19 @@ bitflags! { const SW_LINEIN_INSERT = 1 << 0x0d, /// "set = device disabled" const SW_MUTE_DEVICE = 1 << 0x0e, - const SW_MAX = 1 << 0x0f, + /// "set = pen inserted" + const SW_PEN_INSERTED = 1 << 0x0f, + const SW_MAX = 0xf, } } bitflags! { /// LEDs specified by USB HID. - flags Led: u32 { + pub flags Led: u32 { const LED_NUML = 1 << 0x00, const LED_CAPSL = 1 << 0x01, const LED_SCROLLL = 1 << 0x02, + const LED_COMPOSE = 1 << 0x03, const LED_KANA = 1 << 0x04, /// "Stand-by" const LED_SLEEP = 1 << 0x05, @@ -297,7 +301,7 @@ bitflags! { bitflags! { /// Various miscellaneous event types. Current as of kernel 4.1. - flags Misc: u32 { + pub flags Misc: u32 { /// Serial number, only exported for tablets ("Transducer Serial Number") const MSC_SERIAL = 1 << 0x00, /// Only used by the PowerMate driver, right now. @@ -315,7 +319,7 @@ bitflags! { } bitflags! { - flags FFStatus: u32 { + pub flags FFStatus: u32 { const FF_STATUS_STOPPED = 1 << 0x00, const FF_STATUS_PLAYING = 1 << 0x01, } @@ -344,14 +348,14 @@ pub enum FFEffect { } bitflags! { - flags Repeat: u32 { + pub flags Repeat: u32 { const REP_DELAY = 1 << 0x00, const REP_PERIOD = 1 << 0x01, } } bitflags! { - flags Sound: u32 { + pub flags Sound: u32 { const SND_CLICK = 1 << 0x00, const SND_BELL = 1 << 0x01, const SND_TONE = 1 << 0x02, @@ -366,14 +370,9 @@ macro_rules! impl_number { /// mode, #[inline(always)] pub fn number(&self) -> T { - if cfg!(debug_assertions) { - let val = ffs(self.bits()); - self.bits() == val; // hack to induce the constraint typeof(self.bits()) = typeof(val) - if self.bits() != 1 << val { - panic!("{:?} ought to have only one flag set to be used with .number()", self); - } - } - T::from_u32(ffs(self.bits())).unwrap() + let val = self.bits().trailing_zeros(); + debug_assert!(self.bits() == 1 << val, "{:?} ought to have only one flag set to be used with .number()", self); + T::from_u32(val).unwrap() } })* } @@ -392,7 +391,6 @@ pub enum Synchronization { SYN_MT_REPORT = 2, /// Ring buffer filled, events were dropped. SYN_DROPPED = 3, - SYN_MAX = 0xf, } #[derive(Clone)] @@ -460,7 +458,7 @@ impl std::fmt::Debug for Device { } if self.ty.contains(ABSOLUTE) { ds.field("abs", &self.abs); - for idx in (0..0x3f) { + for idx in 0..0x3f { let abs = 1 << idx; // ignore multitouch, we'll handle that later. if (self.abs.bits() & abs) == 1 { @@ -546,7 +544,7 @@ impl std::fmt::Display for Device { if self.ty.contains(KEY) { try!(writeln!(f, " Keys supported:")); - for key_idx in (0..self.key_bits.len()) { + for key_idx in 0..self.key_bits.len() { if self.key_bits.contains(key_idx) { // Cross our fingers... (what did this mean?) try!(writeln!(f, " {:?} ({}index {})", @@ -561,7 +559,7 @@ impl std::fmt::Display for Device { } if self.ty.contains(ABSOLUTE) { try!(writeln!(f, " Absolute Axes:")); - for idx in (0..0x3f) { + for idx in 0..0x3f { let abs = 1<< idx; if self.abs.bits() & abs != 0 { // FIXME: abs val Debug is gross @@ -577,7 +575,7 @@ impl std::fmt::Display for Device { } if self.ty.contains(SWITCH) { try!(writeln!(f, " Switches:")); - for idx in (0..0xf) { + for idx in 0..0xf { let sw = 1 << idx; if sw < SW_MAX.bits() && self.switch.bits() & sw == 1 { try!(writeln!(f, " {:?} ({:?}, index {})", @@ -589,7 +587,7 @@ impl std::fmt::Display for Device { } if self.ty.contains(LED) { try!(writeln!(f, " LEDs:")); - for idx in (0..0xf) { + for idx in 0..0xf { let led = 1 << idx; if led < LED_MAX.bits() && self.led.bits() & led == 1 { try!(writeln!(f, " {:?} ({:?}, index {})", @@ -625,10 +623,6 @@ impl Drop for Device { } } -fn ffs(x: U) -> T { - T::from_u32(31 - U::to_u64(&x).unwrap().leading_zeros()).unwrap() -} - impl Device { pub fn fd(&self) -> RawFd { self.fd @@ -800,6 +794,7 @@ impl Device { if dev.ty.contains(LED) { do_ioctl!(eviocgbit(*fd, LED.number(), 0xf, &mut bits as *mut u32 as *mut u8)); + println!("{:b}", bits); dev.led = Led::from_bits(bits).expect("evdev: unexpected led bits! report a bug"); } @@ -829,7 +824,7 @@ impl Device { do_ioctl!(eviocgkey(self.fd, self.state.key_vals.as_mut_slice().as_mut_ptr() as *mut u32 as *mut u8, self.state.key_vals.len())); } if self.ty.contains(ABSOLUTE) { - for idx in (0..0x28) { + for idx in 0..0x28 { let abs = 1 << idx; // ignore multitouch, we'll handle that later. if abs < ABS_MT_SLOT.bits() && self.abs.bits() & abs != 1 { @@ -885,7 +880,7 @@ impl Device { }; if self.ty.contains(KEY) { - for key_idx in (0..self.key_bits.len()) { + for key_idx in 0..self.key_bits.len() { if self.key_bits.contains(key_idx) { if old_state.key_vals[key_idx] != self.state.key_vals[key_idx] { self.pending_events.push(ioctl::input_event { @@ -899,7 +894,7 @@ impl Device { } } if self.ty.contains(ABSOLUTE) { - for idx in (0..0x3f) { + for idx in 0..0x3f { let abs = 1 << idx; if self.abs.bits() & abs != 0 { if old_state.abs_vals[idx as usize] != self.state.abs_vals[idx as usize] { @@ -914,7 +909,7 @@ impl Device { } } if self.ty.contains(SWITCH) { - for idx in (0..0xf) { + for idx in 0..0xf { let sw = 1 << idx; if sw < SW_MAX.bits() && self.switch.bits() & sw == 1 { if old_state.switch_vals[idx as usize] != self.state.switch_vals[idx as usize] { @@ -929,7 +924,7 @@ impl Device { } } if self.ty.contains(LED) { - for idx in (0..0xf) { + for idx in 0..0xf { let led = 1 << idx; if led < LED_MAX.bits() && self.led.bits() & led == 1 { if old_state.led_vals[idx as usize] != self.state.led_vals[idx as usize] { diff --git a/src/tests.rs b/src/tests.rs index b04a5bb..3067118 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,2 +1,2 @@ -// woo tests! should really test compensate_droped... I don't even know how it's *supposed* to +// woo tests! should really test compensate_dropped... I don't even know how it's *supposed* to // behave yet though.