Fix all the current issues:
Changes in Rust, changes in the evdev ABI, and a bug
This commit is contained in:
parent
ee5bab2689
commit
60a7523d4b
4 changed files with 49 additions and 48 deletions
16
Cargo.toml
16
Cargo.toml
|
@ -1,19 +1,19 @@
|
||||||
[package]
|
[package]
|
||||||
name = "evdev"
|
name = "evdev"
|
||||||
version = "0.9.2"
|
version = "0.9.3"
|
||||||
authors = ["Corey Richardson <corey@octayn.net>"]
|
authors = ["Corey Richardson <corey@octayn.net>"]
|
||||||
description = "evdev interface for Linux"
|
description = "evdev interface for Linux"
|
||||||
license = "BSL-1.0/Apache-2.0"
|
license = "Apache-2.0 OR MIT"
|
||||||
repository = "https://github.com/cmr/evdev"
|
repository = "https://github.com/cmr/evdev"
|
||||||
documentation = "https://cmr.github.io/evdev"
|
documentation = "https://docs.rs/evdev"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ioctl = "0.3.3"
|
ioctl = "0.3.3"
|
||||||
bitflags = "*"
|
bitflags = "0.8.2"
|
||||||
errno = "*"
|
errno = "0.2.3"
|
||||||
libc = "*"
|
libc = "0.2.22"
|
||||||
fixedbitset = "*"
|
fixedbitset = "0.1.6"
|
||||||
num = "*"
|
num = "0.1.37"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
unstable = []
|
unstable = []
|
||||||
|
|
12
README.md
12
README.md
|
@ -4,14 +4,16 @@
|
||||||
[![Travis](https://img.shields.io/travis/cmr/evdev.svg?style=flat-square)](https://travis-ci.org/cmr/evdev)
|
[![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)
|
[![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`?
|
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?
|
What does this library support?
|
||||||
===============================
|
===============================
|
||||||
|
@ -23,6 +25,10 @@ closely, where possible.
|
||||||
|
|
||||||
Writing to devices is not yet supported (eg, turning LEDs on).
|
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
|
Example
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
67
src/lib.rs
67
src/lib.rs
|
@ -18,7 +18,7 @@
|
||||||
//! `Device::sync_state` to explicitly synchronize with the kernel state.
|
//! `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
|
//! 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
|
//! 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
|
//! 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
|
//! 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.
|
//! fd returned by `Device::fd` to process events when they are ready.
|
||||||
|
|
||||||
#![cfg(any(target_os = "linux", target_os = "android"))]
|
#![cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
|
@ -47,6 +48,7 @@ use std::path::Path;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
|
use num::traits::WrappingSub;
|
||||||
|
|
||||||
pub use Key::*;
|
pub use Key::*;
|
||||||
pub use FFEffect::*;
|
pub use FFEffect::*;
|
||||||
|
@ -101,7 +103,7 @@ impl std::ops::Deref for Fd {
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Event types supported by the device.
|
/// Event types supported by the device.
|
||||||
flags Types: u32 {
|
pub flags Types: u32 {
|
||||||
/// A bookkeeping event. Usually not important to applications.
|
/// A bookkeeping event. Usually not important to applications.
|
||||||
const SYNCHRONIZATION = 1 << 0x00,
|
const SYNCHRONIZATION = 1 << 0x00,
|
||||||
/// A key changed state. A key, or button, is usually a momentary switch (in the circuit sense). It has two
|
/// 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! {
|
bitflags! {
|
||||||
/// Device properties.
|
/// Device properties.
|
||||||
flags Props: u32 {
|
pub flags Props: u32 {
|
||||||
/// This input device needs a pointer ("cursor") for the user to know its state.
|
/// This input device needs a pointer ("cursor") for the user to know its state.
|
||||||
const POINTER = 1 << 0x00,
|
const POINTER = 1 << 0x00,
|
||||||
/// "direct input devices", according to the header.
|
/// "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.
|
include!("scancodes.rs"); // it's a huge glob of text that I'm tired of skipping over.
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags RelativeAxis: u32 {
|
pub flags RelativeAxis: u32 {
|
||||||
const REL_X = 1 << 0x00,
|
const REL_X = 1 << 0x00,
|
||||||
const REL_Y = 1 << 0x01,
|
const REL_Y = 1 << 0x01,
|
||||||
const REL_Z = 1 << 0x02,
|
const REL_Z = 1 << 0x02,
|
||||||
|
@ -177,7 +179,7 @@ bitflags! {
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags AbsoluteAxis: u64 {
|
pub flags AbsoluteAxis: u64 {
|
||||||
const ABS_X = 1 << 0x00,
|
const ABS_X = 1 << 0x00,
|
||||||
const ABS_Y = 1 << 0x01,
|
const ABS_Y = 1 << 0x01,
|
||||||
const ABS_Z = 1 << 0x02,
|
const ABS_Z = 1 << 0x02,
|
||||||
|
@ -234,12 +236,11 @@ bitflags! {
|
||||||
const ABS_MT_TOOL_X = 1 << 0x3c,
|
const ABS_MT_TOOL_X = 1 << 0x3c,
|
||||||
/// "Center Y tool position"
|
/// "Center Y tool position"
|
||||||
const ABS_MT_TOOL_Y = 1 << 0x3d,
|
const ABS_MT_TOOL_Y = 1 << 0x3d,
|
||||||
const ABS_MAX = 1 << 0x3f,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags Switch: u32 {
|
pub flags Switch: u32 {
|
||||||
/// "set = lid shut"
|
/// "set = lid shut"
|
||||||
const SW_LID = 1 << 0x00,
|
const SW_LID = 1 << 0x00,
|
||||||
/// "set = tablet mode"
|
/// "set = tablet mode"
|
||||||
|
@ -270,16 +271,19 @@ bitflags! {
|
||||||
const SW_LINEIN_INSERT = 1 << 0x0d,
|
const SW_LINEIN_INSERT = 1 << 0x0d,
|
||||||
/// "set = device disabled"
|
/// "set = device disabled"
|
||||||
const SW_MUTE_DEVICE = 1 << 0x0e,
|
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! {
|
bitflags! {
|
||||||
/// LEDs specified by USB HID.
|
/// LEDs specified by USB HID.
|
||||||
flags Led: u32 {
|
pub flags Led: u32 {
|
||||||
const LED_NUML = 1 << 0x00,
|
const LED_NUML = 1 << 0x00,
|
||||||
const LED_CAPSL = 1 << 0x01,
|
const LED_CAPSL = 1 << 0x01,
|
||||||
const LED_SCROLLL = 1 << 0x02,
|
const LED_SCROLLL = 1 << 0x02,
|
||||||
|
const LED_COMPOSE = 1 << 0x03,
|
||||||
const LED_KANA = 1 << 0x04,
|
const LED_KANA = 1 << 0x04,
|
||||||
/// "Stand-by"
|
/// "Stand-by"
|
||||||
const LED_SLEEP = 1 << 0x05,
|
const LED_SLEEP = 1 << 0x05,
|
||||||
|
@ -297,7 +301,7 @@ bitflags! {
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Various miscellaneous event types. Current as of kernel 4.1.
|
/// 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")
|
/// Serial number, only exported for tablets ("Transducer Serial Number")
|
||||||
const MSC_SERIAL = 1 << 0x00,
|
const MSC_SERIAL = 1 << 0x00,
|
||||||
/// Only used by the PowerMate driver, right now.
|
/// Only used by the PowerMate driver, right now.
|
||||||
|
@ -315,7 +319,7 @@ bitflags! {
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags FFStatus: u32 {
|
pub flags FFStatus: u32 {
|
||||||
const FF_STATUS_STOPPED = 1 << 0x00,
|
const FF_STATUS_STOPPED = 1 << 0x00,
|
||||||
const FF_STATUS_PLAYING = 1 << 0x01,
|
const FF_STATUS_PLAYING = 1 << 0x01,
|
||||||
}
|
}
|
||||||
|
@ -344,14 +348,14 @@ pub enum FFEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags Repeat: u32 {
|
pub flags Repeat: u32 {
|
||||||
const REP_DELAY = 1 << 0x00,
|
const REP_DELAY = 1 << 0x00,
|
||||||
const REP_PERIOD = 1 << 0x01,
|
const REP_PERIOD = 1 << 0x01,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags Sound: u32 {
|
pub flags Sound: u32 {
|
||||||
const SND_CLICK = 1 << 0x00,
|
const SND_CLICK = 1 << 0x00,
|
||||||
const SND_BELL = 1 << 0x01,
|
const SND_BELL = 1 << 0x01,
|
||||||
const SND_TONE = 1 << 0x02,
|
const SND_TONE = 1 << 0x02,
|
||||||
|
@ -366,14 +370,9 @@ macro_rules! impl_number {
|
||||||
/// mode,
|
/// mode,
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn number<T: num::FromPrimitive>(&self) -> T {
|
pub fn number<T: num::FromPrimitive>(&self) -> T {
|
||||||
if cfg!(debug_assertions) {
|
let val = self.bits().trailing_zeros();
|
||||||
let val = ffs(self.bits());
|
debug_assert!(self.bits() == 1 << val, "{:?} ought to have only one flag set to be used with .number()", self);
|
||||||
self.bits() == val; // hack to induce the constraint typeof(self.bits()) = typeof(val)
|
T::from_u32(val).unwrap()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
}
|
}
|
||||||
|
@ -392,7 +391,6 @@ pub enum Synchronization {
|
||||||
SYN_MT_REPORT = 2,
|
SYN_MT_REPORT = 2,
|
||||||
/// Ring buffer filled, events were dropped.
|
/// Ring buffer filled, events were dropped.
|
||||||
SYN_DROPPED = 3,
|
SYN_DROPPED = 3,
|
||||||
SYN_MAX = 0xf,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -460,7 +458,7 @@ impl std::fmt::Debug for Device {
|
||||||
}
|
}
|
||||||
if self.ty.contains(ABSOLUTE) {
|
if self.ty.contains(ABSOLUTE) {
|
||||||
ds.field("abs", &self.abs);
|
ds.field("abs", &self.abs);
|
||||||
for idx in (0..0x3f) {
|
for idx in 0..0x3f {
|
||||||
let abs = 1 << idx;
|
let abs = 1 << idx;
|
||||||
// ignore multitouch, we'll handle that later.
|
// ignore multitouch, we'll handle that later.
|
||||||
if (self.abs.bits() & abs) == 1 {
|
if (self.abs.bits() & abs) == 1 {
|
||||||
|
@ -546,7 +544,7 @@ impl std::fmt::Display for Device {
|
||||||
|
|
||||||
if self.ty.contains(KEY) {
|
if self.ty.contains(KEY) {
|
||||||
try!(writeln!(f, " Keys supported:"));
|
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) {
|
if self.key_bits.contains(key_idx) {
|
||||||
// Cross our fingers... (what did this mean?)
|
// Cross our fingers... (what did this mean?)
|
||||||
try!(writeln!(f, " {:?} ({}index {})",
|
try!(writeln!(f, " {:?} ({}index {})",
|
||||||
|
@ -561,7 +559,7 @@ impl std::fmt::Display for Device {
|
||||||
}
|
}
|
||||||
if self.ty.contains(ABSOLUTE) {
|
if self.ty.contains(ABSOLUTE) {
|
||||||
try!(writeln!(f, " Absolute Axes:"));
|
try!(writeln!(f, " Absolute Axes:"));
|
||||||
for idx in (0..0x3f) {
|
for idx in 0..0x3f {
|
||||||
let abs = 1<< idx;
|
let abs = 1<< idx;
|
||||||
if self.abs.bits() & abs != 0 {
|
if self.abs.bits() & abs != 0 {
|
||||||
// FIXME: abs val Debug is gross
|
// FIXME: abs val Debug is gross
|
||||||
|
@ -577,7 +575,7 @@ impl std::fmt::Display for Device {
|
||||||
}
|
}
|
||||||
if self.ty.contains(SWITCH) {
|
if self.ty.contains(SWITCH) {
|
||||||
try!(writeln!(f, " Switches:"));
|
try!(writeln!(f, " Switches:"));
|
||||||
for idx in (0..0xf) {
|
for idx in 0..0xf {
|
||||||
let sw = 1 << idx;
|
let sw = 1 << idx;
|
||||||
if sw < SW_MAX.bits() && self.switch.bits() & sw == 1 {
|
if sw < SW_MAX.bits() && self.switch.bits() & sw == 1 {
|
||||||
try!(writeln!(f, " {:?} ({:?}, index {})",
|
try!(writeln!(f, " {:?} ({:?}, index {})",
|
||||||
|
@ -589,7 +587,7 @@ impl std::fmt::Display for Device {
|
||||||
}
|
}
|
||||||
if self.ty.contains(LED) {
|
if self.ty.contains(LED) {
|
||||||
try!(writeln!(f, " LEDs:"));
|
try!(writeln!(f, " LEDs:"));
|
||||||
for idx in (0..0xf) {
|
for idx in 0..0xf {
|
||||||
let led = 1 << idx;
|
let led = 1 << idx;
|
||||||
if led < LED_MAX.bits() && self.led.bits() & led == 1 {
|
if led < LED_MAX.bits() && self.led.bits() & led == 1 {
|
||||||
try!(writeln!(f, " {:?} ({:?}, index {})",
|
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 {
|
impl Device {
|
||||||
pub fn fd(&self) -> RawFd {
|
pub fn fd(&self) -> RawFd {
|
||||||
self.fd
|
self.fd
|
||||||
|
@ -800,6 +794,7 @@ impl Device {
|
||||||
|
|
||||||
if dev.ty.contains(LED) {
|
if dev.ty.contains(LED) {
|
||||||
do_ioctl!(eviocgbit(*fd, LED.number(), 0xf, &mut bits as *mut u32 as *mut u8));
|
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");
|
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()));
|
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) {
|
if self.ty.contains(ABSOLUTE) {
|
||||||
for idx in (0..0x28) {
|
for idx in 0..0x28 {
|
||||||
let abs = 1 << idx;
|
let abs = 1 << idx;
|
||||||
// ignore multitouch, we'll handle that later.
|
// ignore multitouch, we'll handle that later.
|
||||||
if abs < ABS_MT_SLOT.bits() && self.abs.bits() & abs != 1 {
|
if abs < ABS_MT_SLOT.bits() && self.abs.bits() & abs != 1 {
|
||||||
|
@ -885,7 +880,7 @@ impl Device {
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.ty.contains(KEY) {
|
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 self.key_bits.contains(key_idx) {
|
||||||
if old_state.key_vals[key_idx] != self.state.key_vals[key_idx] {
|
if old_state.key_vals[key_idx] != self.state.key_vals[key_idx] {
|
||||||
self.pending_events.push(ioctl::input_event {
|
self.pending_events.push(ioctl::input_event {
|
||||||
|
@ -899,7 +894,7 @@ impl Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.ty.contains(ABSOLUTE) {
|
if self.ty.contains(ABSOLUTE) {
|
||||||
for idx in (0..0x3f) {
|
for idx in 0..0x3f {
|
||||||
let abs = 1 << idx;
|
let abs = 1 << idx;
|
||||||
if self.abs.bits() & abs != 0 {
|
if self.abs.bits() & abs != 0 {
|
||||||
if old_state.abs_vals[idx as usize] != self.state.abs_vals[idx as usize] {
|
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) {
|
if self.ty.contains(SWITCH) {
|
||||||
for idx in (0..0xf) {
|
for idx in 0..0xf {
|
||||||
let sw = 1 << idx;
|
let sw = 1 << idx;
|
||||||
if sw < SW_MAX.bits() && self.switch.bits() & sw == 1 {
|
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] {
|
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) {
|
if self.ty.contains(LED) {
|
||||||
for idx in (0..0xf) {
|
for idx in 0..0xf {
|
||||||
let led = 1 << idx;
|
let led = 1 << idx;
|
||||||
if led < LED_MAX.bits() && self.led.bits() & led == 1 {
|
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] {
|
if old_state.led_vals[idx as usize] != self.state.led_vals[idx as usize] {
|
||||||
|
|
|
@ -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.
|
// behave yet though.
|
||||||
|
|
Loading…
Reference in a new issue