Fix all the current issues:

Changes in Rust, changes in the evdev ABI, and a bug
This commit is contained in:
Corey Richardson 2017-04-27 19:42:45 -04:00
parent ee5bab2689
commit 60a7523d4b
No known key found for this signature in database
GPG key ID: A89E9F8FB71E9B8B
4 changed files with 49 additions and 48 deletions

View file

@ -1,19 +1,19 @@
[package]
name = "evdev"
version = "0.9.2"
version = "0.9.3"
authors = ["Corey Richardson <corey@octayn.net>"]
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 = []

View file

@ -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
=======

View file

@ -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<T: num::FromPrimitive>(&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<T: num::FromPrimitive, U: num::ToPrimitive>(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] {

View file

@ -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.