commit
62bb393491
4 changed files with 55 additions and 60 deletions
|
@ -12,7 +12,7 @@ bitflags = "0.8.2"
|
||||||
libc = "0.2.22"
|
libc = "0.2.22"
|
||||||
fixedbitset = "0.1.6"
|
fixedbitset = "0.1.6"
|
||||||
num = "0.1.37"
|
num = "0.1.37"
|
||||||
nix = "0.8.1"
|
nix = "0.9.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
unstable = []
|
unstable = []
|
||||||
|
|
12
README.md
12
README.md
|
@ -11,16 +11,18 @@ Nice(r) access to `evdev` devices.
|
||||||
What is `evdev`?
|
What is `evdev`?
|
||||||
===================
|
===================
|
||||||
|
|
||||||
`evdev` is the Linux kernel's generic input interface. This crate exposes
|
`evdev` is the Linux kernel's generic input interface, also implemented by other
|
||||||
access to these sorts of input devices. There is some trickery involved, so
|
kernels such as FreeBSD.
|
||||||
please read the crate documentation.
|
|
||||||
|
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?
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
This library exposes raw evdev events, but uses the Rust `Iterator` trait to
|
This library exposes raw evdev events, but uses the Rust `Iterator` trait to
|
||||||
do so, and will handle `SYN_DROPPED` events properly for the client. I try to
|
do so, and will handle `SYN_DROPPED` events properly for the client. I try to
|
||||||
match [libevdev](http://www.freedesktop.org/software/libevdev/doc/latest/)
|
match [libevdev](https://www.freedesktop.org/software/libevdev/doc/latest/)
|
||||||
closely, where possible.
|
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).
|
||||||
|
@ -33,5 +35,5 @@ Example
|
||||||
=======
|
=======
|
||||||
|
|
||||||
See <examples/evtest.rs> for an example of using this library (which roughly
|
See <examples/evtest.rs> for an example of using this library (which roughly
|
||||||
corresponds to the userspace [evtest](http://cgit.freedesktop.org/evtest/)
|
corresponds to the userspace [evtest](https://cgit.freedesktop.org/evtest/)
|
||||||
tool.
|
tool.
|
||||||
|
|
62
src/lib.rs
62
src/lib.rs
|
@ -31,7 +31,7 @@
|
||||||
//! It is recommended that you dedicate a thread to processing input events, or use epoll with the
|
//! It is recommended that you dedicate a thread to processing input events, or use epoll with the
|
||||||
//! 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(unix, target_os = "android"))]
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -47,10 +47,9 @@ pub mod raw;
|
||||||
use std::os::unix::io::*;
|
use std::os::unix::io::*;
|
||||||
use std::os::unix::ffi::*;
|
use std::os::unix::ffi::*;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::ffi::CString;
|
use std::ffi::{CString, CStr};
|
||||||
use std::mem::size_of;
|
use std::mem::{size_of, transmute};
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use num::traits::WrappingSub;
|
|
||||||
|
|
||||||
use nix::Error;
|
use nix::Error;
|
||||||
|
|
||||||
|
@ -71,6 +70,21 @@ macro_rules! do_ioctl {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! do_ioctl_buf {
|
||||||
|
($buf:ident, $name:ident, $fd:expr) => {
|
||||||
|
unsafe {
|
||||||
|
let blen = $buf.len();
|
||||||
|
match ::raw::$name($fd, &mut $buf[..]) {
|
||||||
|
Ok(len) if len >= 0 => {
|
||||||
|
$buf[blen - 1] = 0;
|
||||||
|
Some(CStr::from_ptr(&mut $buf[0] as *mut u8 as *mut _).to_owned())
|
||||||
|
},
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Event types supported by the device.
|
/// Event types supported by the device.
|
||||||
pub flags Types: u32 {
|
pub flags Types: u32 {
|
||||||
|
@ -669,7 +683,7 @@ impl Device {
|
||||||
pub fn open(path: &AsRef<Path>) -> Result<Device, Error> {
|
pub fn open(path: &AsRef<Path>) -> Result<Device, Error> {
|
||||||
let cstr = match CString::new(path.as_ref().as_os_str().as_bytes()) {
|
let cstr = match CString::new(path.as_ref().as_os_str().as_bytes()) {
|
||||||
Ok(s) => s,
|
Ok(s) => s,
|
||||||
Err(e) => return Err(Error::InvalidPath),
|
Err(_) => return Err(Error::InvalidPath),
|
||||||
};
|
};
|
||||||
// FIXME: only need for writing is for setting LED values. re-evaluate always using RDWR
|
// FIXME: only need for writing is for setting LED values. re-evaluate always using RDWR
|
||||||
// later.
|
// later.
|
||||||
|
@ -711,34 +725,14 @@ impl Device {
|
||||||
|
|
||||||
let mut bits: u32 = 0;
|
let mut bits: u32 = 0;
|
||||||
let mut bits64: u64 = 0;
|
let mut bits64: u64 = 0;
|
||||||
let mut vec = Vec::with_capacity(256);
|
let mut buf = [0u8; 256];
|
||||||
|
|
||||||
do_ioctl!(eviocgbit(fd, 0, 4, &mut bits as *mut u32 as *mut u8));
|
do_ioctl!(eviocgbit(fd, 0, 4, &mut bits as *mut u32 as *mut u8));
|
||||||
dev.ty = Types::from_bits(bits).expect("evdev: unexpected type bits! report a bug");
|
dev.ty = Types::from_bits(bits).expect("evdev: unexpected type bits! report a bug");
|
||||||
|
|
||||||
let dev_len = do_ioctl!(eviocgname(fd, vec.as_mut_ptr(), 255));
|
dev.name = do_ioctl_buf!(buf, eviocgname, fd).unwrap_or(CString::default());
|
||||||
unsafe { vec.set_len(dev_len as usize - 1) };
|
dev.phys = do_ioctl_buf!(buf, eviocgphys, fd);
|
||||||
dev.name = CString::new(vec.clone()).unwrap();
|
dev.uniq = do_ioctl_buf!(buf, eviocguniq, fd);
|
||||||
|
|
||||||
match unsafe { eviocgphys(fd, vec.as_mut_ptr(), 255) } {
|
|
||||||
Ok(phys_len) => {
|
|
||||||
if phys_len > 0 {
|
|
||||||
unsafe { vec.set_len(phys_len as usize - 1) };
|
|
||||||
dev.phys = Some(CString::new(vec.clone()).unwrap());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(_) => { /* not essential */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
match unsafe { eviocguniq(fd, vec.as_mut_ptr(), 255) } {
|
|
||||||
Ok(uniq_len) => {
|
|
||||||
if uniq_len > 0 {
|
|
||||||
unsafe { vec.set_len(uniq_len as usize - 1) };
|
|
||||||
dev.uniq = Some(CString::new(vec.clone()).unwrap());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(_) => { /* not essential */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
do_ioctl!(eviocgid(fd, &mut dev.id));
|
do_ioctl!(eviocgid(fd, &mut dev.id));
|
||||||
let mut driver_version: i32 = 0;
|
let mut driver_version: i32 = 0;
|
||||||
|
@ -748,7 +742,7 @@ impl Device {
|
||||||
((driver_version >> 8) & 0xff) as u8,
|
((driver_version >> 8) & 0xff) as u8,
|
||||||
(driver_version & 0xff) as u8);
|
(driver_version & 0xff) as u8);
|
||||||
|
|
||||||
do_ioctl!(eviocgprop(fd, &mut bits as *mut u32 as *mut u8, 0x1f)); // FIXME: handle old kernel
|
do_ioctl!(eviocgprop(fd, std::slice::from_raw_parts_mut(&mut bits as *mut u32 as *mut u8, 0x1f))); // FIXME: handle old kernel
|
||||||
dev.props = Props::from_bits(bits).expect("evdev: unexpected prop bits! report a bug");
|
dev.props = Props::from_bits(bits).expect("evdev: unexpected prop bits! report a bug");
|
||||||
|
|
||||||
if dev.ty.contains(KEY) {
|
if dev.ty.contains(KEY) {
|
||||||
|
@ -798,7 +792,7 @@ impl Device {
|
||||||
/// If there is an error at any point, the state will not be synchronized completely.
|
/// If there is an error at any point, the state will not be synchronized completely.
|
||||||
pub fn sync_state(&mut self) -> Result<(), Error> {
|
pub fn sync_state(&mut self) -> Result<(), Error> {
|
||||||
if self.ty.contains(KEY) {
|
if self.ty.contains(KEY) {
|
||||||
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, transmute::<&mut [u32], &mut [u8]>(self.state.key_vals.as_mut_slice())));
|
||||||
}
|
}
|
||||||
if self.ty.contains(ABSOLUTE) {
|
if self.ty.contains(ABSOLUTE) {
|
||||||
for idx in 0..0x28 {
|
for idx in 0..0x28 {
|
||||||
|
@ -810,10 +804,10 @@ impl Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.ty.contains(SWITCH) {
|
if self.ty.contains(SWITCH) {
|
||||||
do_ioctl!(eviocgsw(self.fd, self.state.switch_vals.as_mut_slice().as_mut_ptr() as *mut u32 as *mut u8, self.state.switch_vals.len()));
|
do_ioctl!(eviocgsw(self.fd, transmute::<&mut [u32], &mut [u8]>(self.state.switch_vals.as_mut_slice())));
|
||||||
}
|
}
|
||||||
if self.ty.contains(LED) {
|
if self.ty.contains(LED) {
|
||||||
do_ioctl!(eviocgled(self.fd, self.state.led_vals.as_mut_slice().as_mut_ptr() as *mut u32 as *mut u8, self.state.led_vals.len()));
|
do_ioctl!(eviocgled(self.fd, transmute::<&mut [u32], &mut [u8]>(self.state.led_vals.as_mut_slice())));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -928,7 +922,7 @@ impl Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill_events(&mut self) -> Result<(), Error> {
|
fn fill_events(&mut self) -> Result<(), Error> {
|
||||||
let mut buf = &mut self.pending_events;
|
let buf = &mut self.pending_events;
|
||||||
loop {
|
loop {
|
||||||
buf.reserve(20);
|
buf.reserve(20);
|
||||||
let pre_len = buf.len();
|
let pre_len = buf.len();
|
||||||
|
|
39
src/raw.rs
39
src/raw.rs
|
@ -3,12 +3,12 @@ ioctl!(read eviocgid with b'E', 0x02; /*struct*/ input_id);
|
||||||
ioctl!(read eviocgkeycode with b'E', 0x04; [::libc::c_uint; 2]);
|
ioctl!(read eviocgkeycode with b'E', 0x04; [::libc::c_uint; 2]);
|
||||||
ioctl!(read eviocgrep with b'E', 0x03; [::libc::c_uint; 2]);
|
ioctl!(read eviocgrep with b'E', 0x03; [::libc::c_uint; 2]);
|
||||||
ioctl!(read eviocgversion with b'E', 0x01; ::libc::c_int);
|
ioctl!(read eviocgversion with b'E', 0x01; ::libc::c_int);
|
||||||
ioctl!(write eviocrmff with b'E', 0x81; ::libc::c_int);
|
ioctl!(write_int eviocrmff with b'E', 0x81);
|
||||||
// ioctl!(read eviocgkeycode_v2 with b'E', 0x04; /*struct*/ input_keymap_entry);
|
// ioctl!(read eviocgkeycode_v2 with b'E', 0x04; /*struct*/ input_keymap_entry);
|
||||||
// TODO #define EVIOCSFF _IOC ( _IOC_WRITE , 'E' , 0x80 , sizeof ( struct ff_effect ) )
|
// TODO #define EVIOCSFF _IOC ( _IOC_WRITE , 'E' , 0x80 , sizeof ( struct ff_effect ) )
|
||||||
ioctl!(write eviocskeycode with b'E', 0x04; [::libc::c_uint; 2]);
|
ioctl!(write_ptr eviocskeycode with b'E', 0x04; [::libc::c_uint; 2]);
|
||||||
// ioctl!(write eviocskeycode_v2 with b'E', 0x04; /*struct*/ input_keymap_entry);
|
// ioctl!(write_int eviocskeycode_v2 with b'E', 0x04; /*struct*/ input_keymap_entry);
|
||||||
ioctl!(write eviocsrep with b'E', 0x03; [::libc::c_uint; 2]);
|
ioctl!(write_ptr eviocsrep with b'E', 0x03; [::libc::c_uint; 2]);
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -168,7 +168,6 @@ impl ::std::default::Default for ff_condition_effect {
|
||||||
}
|
}
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[allow(raw_pointer_derive)]
|
|
||||||
pub struct ff_periodic_effect {
|
pub struct ff_periodic_effect {
|
||||||
pub waveform: u16,
|
pub waveform: u16,
|
||||||
pub period: u16,
|
pub period: u16,
|
||||||
|
@ -192,26 +191,26 @@ impl ::std::default::Default for ff_rumble_effect {
|
||||||
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
|
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
|
||||||
}
|
}
|
||||||
|
|
||||||
ioctl!(read buf eviocgname with b'E', 0x06; u8);
|
ioctl!(read_buf eviocgname with b'E', 0x06; u8);
|
||||||
ioctl!(read buf eviocgphys with b'E', 0x07; u8);
|
ioctl!(read_buf eviocgphys with b'E', 0x07; u8);
|
||||||
ioctl!(read buf eviocguniq with b'E', 0x08; u8);
|
ioctl!(read_buf eviocguniq with b'E', 0x08; u8);
|
||||||
ioctl!(read buf eviocgprop with b'E', 0x09; u8);
|
ioctl!(read_buf eviocgprop with b'E', 0x09; u8);
|
||||||
ioctl!(read buf eviocgmtslots with b'E', 0x0a; u8);
|
ioctl!(read_buf eviocgmtslots with b'E', 0x0a; u8);
|
||||||
ioctl!(read buf eviocgkey with b'E', 0x18; u8);
|
ioctl!(read_buf eviocgkey with b'E', 0x18; u8);
|
||||||
ioctl!(read buf eviocgled with b'E', 0x19; u8);
|
ioctl!(read_buf eviocgled with b'E', 0x19; u8);
|
||||||
ioctl!(read buf eviocgsnd with b'E', 0x1a; u8);
|
ioctl!(read_buf eviocgsnd with b'E', 0x1a; u8);
|
||||||
ioctl!(read buf eviocgsw with b'E', 0x1b; u8);
|
ioctl!(read_buf eviocgsw with b'E', 0x1b; u8);
|
||||||
|
|
||||||
ioctl!(write eviocsff with b'E', 0x80; ff_effect);
|
ioctl!(write_ptr eviocsff with b'E', 0x80; ff_effect);
|
||||||
ioctl!(write eviocgrab with b'E', 0x90; ::libc::c_int);
|
ioctl!(write_int eviocgrab with b'E', 0x90);
|
||||||
ioctl!(write eviocrevoke with b'E', 0x91; ::libc::c_int);
|
ioctl!(write_int eviocrevoke with b'E', 0x91);
|
||||||
ioctl!(write eviocsclockid with b'E', 0xa0; ::libc::c_int);
|
ioctl!(write_int eviocsclockid with b'E', 0xa0);
|
||||||
|
|
||||||
pub unsafe fn eviocgbit(fd: ::libc::c_int, ev: u32, len: ::libc::c_int, buf: *mut u8) -> ::nix::Result<i32> {
|
pub unsafe fn eviocgbit(fd: ::libc::c_int, ev: u32, len: ::libc::c_int, buf: *mut u8) -> ::nix::Result<i32> {
|
||||||
convert_ioctl_res!(::nix::sys::ioctl::ioctl(fd, ior!(b'E', 0x20 + ev, len) as ::libc::c_ulong, buf))
|
convert_ioctl_res!(::nix::libc::ioctl(fd, ior!(b'E', 0x20 + ev, len) as ::libc::c_ulong, buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn eviocgabs(fd: ::libc::c_int, abs: u32, buf: *mut input_absinfo) -> ::nix::Result<i32> {
|
pub unsafe fn eviocgabs(fd: ::libc::c_int, abs: u32, buf: *mut input_absinfo) -> ::nix::Result<i32> {
|
||||||
convert_ioctl_res!(::nix::sys::ioctl::ioctl(fd, ior!(b'E', 0x40 + abs, ::std::mem::size_of::<input_absinfo>()) as ::libc::c_ulong, buf))
|
convert_ioctl_res!(::nix::libc::ioctl(fd, ior!(b'E', 0x40 + abs, ::std::mem::size_of::<input_absinfo>()) as ::libc::c_ulong, buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue