evdev_rs

Struct Device

Source
pub struct Device { /* private fields */ }
Expand description

Opaque struct representing an evdev device

Unlike libevdev, this Device mantains an associated file as an invariant

Implementations§

Source§

impl Device

Source

pub fn new_from_file(file: File) -> Result<Device>

Initialize a new libevdev device from the given file.

This is a shortcut for

use evdev_rs::{Device, UninitDevice};

let uninit_device = UninitDevice::new().unwrap();
let device = uninit_device.set_file(file);

The caller is responsible for opening the file and setting the O_NONBLOCK flag and handling permissions. If the file is opened without O_NONBLOCK flag then next_event should be called with ReadFlag::BLOCKING. Due to the caching nature of next_event we might block while trying to buffer new events even though some events are already present.

Examples found in repository?
examples/vmouse.rs (line 23)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
fn main() -> Result<(), std::io::Error> {
    // Parse command line arguments
    let mut args = std::env::args();

    if args.len() != 2 {
        let n = args.nth(0).unwrap();
        println!("Usage: `{} DEVICE`, eg. `{} /dev/input/event13`", n, n);
        std::process::exit(1);
    }

    let device = &args.nth(1).unwrap();

    // Connect to real keyboard
    let f = File::open(device)?;
    let d = Device::new_from_file(f)?;

    if let Some(n) = d.name() {
        println!(
            "Connected to device: '{}' ({:04x}:{:04x})",
            n,
            d.vendor_id(),
            d.product_id()
        );
    }

    // Create virtual device
    let u = UninitDevice::new().unwrap();

    // Setup device
    // per: https://01.org/linuxgraphics/gfx-docs/drm/input/uinput.html#mouse-movements

    u.set_name("Virtual Mouse");
    u.set_bustype(BusType::BUS_USB as u16);
    u.set_vendor_id(0xabcd);
    u.set_product_id(0xefef);

    // Note mouse keys have to be enabled for this to be detected
    // as a usable device, see: https://stackoverflow.com/a/64559658/6074942
    u.enable_event_type(&EventType::EV_KEY)?;
    u.enable_event_code(&EventCode::EV_KEY(EV_KEY::BTN_LEFT), None)?;
    u.enable_event_code(&EventCode::EV_KEY(EV_KEY::BTN_RIGHT), None)?;

    u.enable_event_type(&EventType::EV_REL)?;
    u.enable_event_code(&EventCode::EV_REL(EV_REL::REL_X), None)?;
    u.enable_event_code(&EventCode::EV_REL(EV_REL::REL_Y), None)?;

    u.enable_event_code(&EventCode::EV_SYN(EV_SYN::SYN_REPORT), None)?;

    // Attempt to create UInputDevice from UninitDevice
    let v = UInputDevice::create_from_device(&u)?;

    loop {
        // Fetch keyboard events
        let (_status, event) = d.next_event(ReadFlag::NORMAL | ReadFlag::BLOCKING)?;

        // Map these to mouse events
        println!("Event: {:?}", event);

        // Map direction keys to mouse events
        let e = match event.event_code {
            EventCode::EV_KEY(EV_KEY::KEY_RIGHT) => Some((EV_REL::REL_X, MOUSE_STEP_X)),
            EventCode::EV_KEY(EV_KEY::KEY_LEFT) => Some((EV_REL::REL_X, -MOUSE_STEP_X)),
            EventCode::EV_KEY(EV_KEY::KEY_UP) => Some((EV_REL::REL_Y, -MOUSE_STEP_Y)),
            EventCode::EV_KEY(EV_KEY::KEY_DOWN) => Some((EV_REL::REL_Y, MOUSE_STEP_Y)),
            _ => None,
        };

        // Write mapped event
        if let Some((e, n)) = e {
            v.write_event(&InputEvent {
                time: event.time,
                event_code: EventCode::EV_REL(e),
                value: n,
            })?;

            v.write_event(&InputEvent {
                time: event.time,
                event_code: EventCode::EV_SYN(EV_SYN::SYN_REPORT),
                value: 0,
            })?;
        }
    }
}
Source

pub fn new_from_fd(file: File) -> Result<Device>

👎Deprecated since 0.5.0: Prefer new_from_file. Some function names were changed so they more closely match their type signature. See issue 42 for discussion https://github.com/ndesh26/evdev-rs/issues/42
Source

pub fn new_from_path<P: AsRef<Path>>(path: P) -> Result<Device>

Opens a device with the given path as the location of devnode

The devnode file is opened with O_NONBLOCK and all the pending events are first read from the file before creating the device.

Source

pub fn file(&self) -> &File

Returns the file associated with the device

Source

pub fn fd(&self) -> Option<File>

👎Deprecated since 0.5.0: Prefer file. This function can easily be misused. Calling this method, then dropping the returned file will lead to failures e.g. next_event will return an Err()
Source

pub fn change_file(&mut self, file: File) -> Result<File>

Change the file for this device, without re-reading the actual device.

On success, returns the file that was previously associated with this device.

If the file changes after initializing the device, for example after a VT-switch in the X.org X server, this function updates the internal file to the newly opened. No check is made that new file points to the same device. If the device has changed, evdev’s behavior is undefined.

evdev device does not sync itself after changing the file and keeps the current device state. Use next_event with the FORCE_SYNC flag to force a re-sync.

§Example
use evdev_rs::{Device, UninitDevice, ReadFlag, ReadStatus};
let mut dev = Device::new_from_file(File::open("/dev/input/input0")?)?;
dev.change_file(File::open("/dev/input/input1")?)?;
dev.next_event(ReadFlag::FORCE_SYNC);
while dev.next_event(ReadFlag::SYNC).ok().unwrap().0 == ReadStatus::Sync
                            {} // noop

After changing the file, the device is assumed ungrabbed and a caller must call libevdev_grab() again.

Source

pub fn change_fd(&mut self, file: File) -> Result<()>

👎Deprecated since 0.5.0: Prefer new_from_file. Some function names were changed so they more closely match their type signature. See issue 42 for discussion https://github.com/ndesh26/evdev-rs/issues/42
Source

pub fn grab(&mut self, grab: GrabMode) -> Result<()>

Grab or ungrab the device through a kernel EVIOCGRAB.

This prevents other clients (including kernel-internal ones such as rfkill) from receiving events from this device. This is generally a bad idea. Don’t do this. Grabbing an already grabbed device, or ungrabbing an ungrabbed device is a noop and always succeeds.

A grab is an operation tied to a file descriptor, not a device. If a client changes the file descriptor with Device::change_file(), it must also re-issue a grab with libevdev_grab().

Source

pub fn has_event_pending(&self) -> bool

Check if there are events waiting for us.

This function does not consume an event and may not access the device file at all. If there are events queued internally this function will return true. If the internal queue is empty, this function will poll the file descriptor for data.

This is a convenience function for simple processes, most complex programs are expected to use select(2) or poll(2) on the file descriptor. The kernel guarantees that if data is available, it is a multiple of sizeof(struct input_event), and thus calling next_event when select(2) or poll(2) return is safe. You do not need has_event_pending if you’re using select(2) or poll(2).

Source

pub fn driver_version(&self) -> i32

Return the driver version of a device already intialize with set_file

Examples found in repository?
examples/evtest.rs (line 134)
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
fn main() {
    let mut args = std::env::args();

    if args.len() != 2 {
        usage();
        std::process::exit(1);
    }

    let path = &args.nth(1).unwrap();
    let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .custom_flags(libc::O_NONBLOCK)
        .open(path)
        .unwrap();
    let mut buffer = Vec::new();
    let result = file.read_to_end(&mut buffer);
    if result.is_ok() || result.unwrap_err().kind() != ErrorKind::WouldBlock {
        println!("Failed to drain pending events from device file");
    }

    let u_d = UninitDevice::new().unwrap();
    let d = u_d.set_file(file).unwrap();

    println!(
        "Input device ID: bus 0x{:x} vendor 0x{:x} product 0x{:x}",
        d.bustype(),
        d.vendor_id(),
        d.product_id()
    );
    println!("Evdev version: {:x}", d.driver_version());
    println!("Input device name: \"{}\"", d.name().unwrap_or(""));
    println!("Phys location: {}", d.phys().unwrap_or(""));
    println!("Uniq identifier: {}", d.uniq().unwrap_or(""));

    print_bits(&d);
    print_props(&d);

    let mut a: io::Result<(ReadStatus, InputEvent)>;
    loop {
        a = d.next_event(ReadFlag::NORMAL);
        if a.is_ok() {
            let mut result = a.ok().unwrap();
            match result.0 {
                ReadStatus::Sync => {
                    println!("::::::::::::::::::::: dropped ::::::::::::::::::::::");
                    while result.0 == ReadStatus::Sync {
                        print_sync_dropped_event(&result.1);
                        a = d.next_event(ReadFlag::SYNC);
                        if a.is_ok() {
                            result = a.ok().unwrap();
                        } else {
                            break;
                        }
                    }
                    println!("::::::::::::::::::::: re-synced ::::::::::::::::::::");
                }
                ReadStatus::Success => print_event(&result.1),
            }
        } else {
            let err = a.err().unwrap();
            match err.raw_os_error() {
                Some(libc::EAGAIN) => continue,
                _ => {
                    println!("{}", err);
                    break;
                }
            }
        }
    }
}
Source

pub fn set_kernel_abs_info(&self, code: &EventCode, absinfo: &AbsInfo)

Set the device’s EV_ABS axis to the value defined in the abs parameter. This will be written to the kernel.

Source

pub fn kernel_set_led_value( &self, code: &EventCode, value: LedState, ) -> Result<()>

Turn an LED on or off.

enabling an LED requires write permissions on the device’s file descriptor.

Source

pub fn set_clock_id(&self, clockid: i32) -> Result<()>

Set the clock ID to be used for timestamps. Further events from this device will report an event time based on the given clock.

This is a modification only affecting this representation of this device.

Source

pub fn next_event(&self, flags: ReadFlag) -> Result<(ReadStatus, InputEvent)>

Get the next event from the device. This function operates in two different modes: normal mode or sync mode.

In normal mode (when flags has evdev::NORMAL set), this function returns ReadStatus::Success and returns the event. If no events are available at this time, it returns -EAGAIN as Err.

If the current event is an EV_SYN::SYN_DROPPED event, this function returns ReadStatus::Sync and is set to the EV_SYN event.The caller should now call this function with the evdev::SYNC flag set, to get the set of events that make up the device state delta. This function returns ReadStatus::Sync for each event part of that delta, until it returns -EAGAIN once all events have been synced.

If a device needs to be synced by the caller but the caller does not call with the evdev::SYNC flag set, all events from the diff are dropped after evdev updates its internal state and event processing continues as normal. Note that the current slot and the state of touch points may have updated during the SYN_DROPPED event, it is strongly recommended that a caller ignoring all sync events calls current_slot and checks the ABS_MT_TRACKING_ID values for all slots.

If a device has changed state without events being enqueued in evdev, e.g. after changing the file descriptor, use the evdev::FORCE_SYNC flag. This triggers an internal sync of the device and next_event returns ReadStatus::Sync.

Examples found in repository?
examples/evtest.rs (line 144)
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
fn main() {
    let mut args = std::env::args();

    if args.len() != 2 {
        usage();
        std::process::exit(1);
    }

    let path = &args.nth(1).unwrap();
    let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .custom_flags(libc::O_NONBLOCK)
        .open(path)
        .unwrap();
    let mut buffer = Vec::new();
    let result = file.read_to_end(&mut buffer);
    if result.is_ok() || result.unwrap_err().kind() != ErrorKind::WouldBlock {
        println!("Failed to drain pending events from device file");
    }

    let u_d = UninitDevice::new().unwrap();
    let d = u_d.set_file(file).unwrap();

    println!(
        "Input device ID: bus 0x{:x} vendor 0x{:x} product 0x{:x}",
        d.bustype(),
        d.vendor_id(),
        d.product_id()
    );
    println!("Evdev version: {:x}", d.driver_version());
    println!("Input device name: \"{}\"", d.name().unwrap_or(""));
    println!("Phys location: {}", d.phys().unwrap_or(""));
    println!("Uniq identifier: {}", d.uniq().unwrap_or(""));

    print_bits(&d);
    print_props(&d);

    let mut a: io::Result<(ReadStatus, InputEvent)>;
    loop {
        a = d.next_event(ReadFlag::NORMAL);
        if a.is_ok() {
            let mut result = a.ok().unwrap();
            match result.0 {
                ReadStatus::Sync => {
                    println!("::::::::::::::::::::: dropped ::::::::::::::::::::::");
                    while result.0 == ReadStatus::Sync {
                        print_sync_dropped_event(&result.1);
                        a = d.next_event(ReadFlag::SYNC);
                        if a.is_ok() {
                            result = a.ok().unwrap();
                        } else {
                            break;
                        }
                    }
                    println!("::::::::::::::::::::: re-synced ::::::::::::::::::::");
                }
                ReadStatus::Success => print_event(&result.1),
            }
        } else {
            let err = a.err().unwrap();
            match err.raw_os_error() {
                Some(libc::EAGAIN) => continue,
                _ => {
                    println!("{}", err);
                    break;
                }
            }
        }
    }
}
More examples
Hide additional examples
examples/vmouse.rs (line 62)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
fn main() -> Result<(), std::io::Error> {
    // Parse command line arguments
    let mut args = std::env::args();

    if args.len() != 2 {
        let n = args.nth(0).unwrap();
        println!("Usage: `{} DEVICE`, eg. `{} /dev/input/event13`", n, n);
        std::process::exit(1);
    }

    let device = &args.nth(1).unwrap();

    // Connect to real keyboard
    let f = File::open(device)?;
    let d = Device::new_from_file(f)?;

    if let Some(n) = d.name() {
        println!(
            "Connected to device: '{}' ({:04x}:{:04x})",
            n,
            d.vendor_id(),
            d.product_id()
        );
    }

    // Create virtual device
    let u = UninitDevice::new().unwrap();

    // Setup device
    // per: https://01.org/linuxgraphics/gfx-docs/drm/input/uinput.html#mouse-movements

    u.set_name("Virtual Mouse");
    u.set_bustype(BusType::BUS_USB as u16);
    u.set_vendor_id(0xabcd);
    u.set_product_id(0xefef);

    // Note mouse keys have to be enabled for this to be detected
    // as a usable device, see: https://stackoverflow.com/a/64559658/6074942
    u.enable_event_type(&EventType::EV_KEY)?;
    u.enable_event_code(&EventCode::EV_KEY(EV_KEY::BTN_LEFT), None)?;
    u.enable_event_code(&EventCode::EV_KEY(EV_KEY::BTN_RIGHT), None)?;

    u.enable_event_type(&EventType::EV_REL)?;
    u.enable_event_code(&EventCode::EV_REL(EV_REL::REL_X), None)?;
    u.enable_event_code(&EventCode::EV_REL(EV_REL::REL_Y), None)?;

    u.enable_event_code(&EventCode::EV_SYN(EV_SYN::SYN_REPORT), None)?;

    // Attempt to create UInputDevice from UninitDevice
    let v = UInputDevice::create_from_device(&u)?;

    loop {
        // Fetch keyboard events
        let (_status, event) = d.next_event(ReadFlag::NORMAL | ReadFlag::BLOCKING)?;

        // Map these to mouse events
        println!("Event: {:?}", event);

        // Map direction keys to mouse events
        let e = match event.event_code {
            EventCode::EV_KEY(EV_KEY::KEY_RIGHT) => Some((EV_REL::REL_X, MOUSE_STEP_X)),
            EventCode::EV_KEY(EV_KEY::KEY_LEFT) => Some((EV_REL::REL_X, -MOUSE_STEP_X)),
            EventCode::EV_KEY(EV_KEY::KEY_UP) => Some((EV_REL::REL_Y, -MOUSE_STEP_Y)),
            EventCode::EV_KEY(EV_KEY::KEY_DOWN) => Some((EV_REL::REL_Y, MOUSE_STEP_Y)),
            _ => None,
        };

        // Write mapped event
        if let Some((e, n)) = e {
            v.write_event(&InputEvent {
                time: event.time,
                event_code: EventCode::EV_REL(e),
                value: n,
            })?;

            v.write_event(&InputEvent {
                time: event.time,
                event_code: EventCode::EV_SYN(EV_SYN::SYN_REPORT),
                value: 0,
            })?;
        }
    }
}

Trait Implementations§

Source§

impl Debug for Device

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl DeviceWrapper for Device

Source§

fn raw(&self) -> *mut libevdev

Source§

fn enable<E: Enable>(&self, e: E) -> Result<()>

Forcibly enable an EventType/InputProp on this device, even if the underlying device does not support it. While this cannot make the device actually report such events, it will now return true for has(). Read more
Source§

fn enable_property(&self, prop: &InputProp) -> Result<()>

Enables this property, a call to set_file will overwrite any previously set values Read more
Source§

fn enable_event_type(&self, ev_type: &EventType) -> Result<()>

Forcibly enable an event type on this device, even if the underlying device does not support it. While this cannot make the device actually report such events, it will now return true for libevdev_has_event_type(). Read more
Source§

fn enable_event_code( &self, ev_code: &EventCode, data: Option<EnableCodeData>, ) -> Result<()>

Forcibly enable an event type on this device, even if the underlying device does not support it. While this cannot make the device actually report such events, it will now return true for libevdev_has_event_code(). Read more
Source§

fn disable<E: Enable>(&self, d: E) -> Result<()>

Forcibly disable an EventType/EventCode on this device, even if the underlying device provides it. This effectively mutes the respective set of events. has() will return false for this EventType/EventCode Read more
Source§

fn disable_event_type(&self, ev_type: &EventType) -> Result<()>

Forcibly disable an event type on this device, even if the underlying device provides it. This effectively mutes the respective set of events. libevdev will filter any events matching this type and none will reach the caller. libevdev_has_event_type() will return false for this type. Read more
Source§

fn disable_event_code(&self, code: &EventCode) -> Result<()>

Forcibly disable an event code on this device, even if the underlying device provides it. This effectively mutes the respective set of events. libevdev will filter any events matching this type and code and none will reach the caller. has_event_code will return false for this code. Read more
Source§

fn has<E: Enable>(&self, e: E) -> bool

Returns true if device support the InputProp/EventType/EventCode and false otherwise
Source§

fn has_property(&self, prop: &InputProp) -> bool

Returns true if device support the property and false otherwise Read more
Source§

fn has_event_type(&self, ev_type: &EventType) -> bool

Returns true is the device support this event type and false otherwise Read more
Source§

fn has_event_code(&self, code: &EventCode) -> bool

Return true is the device support this event type and code and false otherwise Read more
Source§

fn name(&self) -> Option<&str>

Get device’s name, as set by the kernel, or overridden by a call to set_name
Source§

fn phys(&self) -> Option<&str>

Get device’s physical location, as set by the kernel, or overridden by a call to set_phys
Source§

fn uniq(&self) -> Option<&str>

Get device’s unique identifier, as set by the kernel, or overridden by a call to set_uniq
Source§

fn set_name(&self, field: &str)

Source§

fn set_phys(&self, field: &str)

Source§

fn set_uniq(&self, field: &str)

Source§

fn product_id(&self) -> u16

Source§

fn vendor_id(&self) -> u16

Source§

fn bustype(&self) -> u16

Source§

fn version(&self) -> u16

Source§

fn set_product_id(&self, field: u16)

Source§

fn set_vendor_id(&self, field: u16)

Source§

fn set_bustype(&self, field: u16)

Source§

fn set_version(&self, field: u16)

Source§

fn abs_info(&self, code: &EventCode) -> Option<AbsInfo>

Get the axis info for the given axis, as advertised by the kernel. Read more
Source§

fn set_abs_info(&self, code: &EventCode, absinfo: &AbsInfo)

Change the abs info for the given EV_ABS event code, if the code exists. Read more
Source§

fn event_value(&self, code: &EventCode) -> Option<i32>

Returns the current value of the event type. Read more
Source§

fn set_event_value(&self, code: &EventCode, val: i32) -> Result<()>

Set the value for a given event type and code. Read more
Source§

fn abs_minimum(&self, code: u32) -> Result<i32>

Source§

fn abs_maximum(&self, code: u32) -> Result<i32>

Source§

fn abs_fuzz(&self, code: u32) -> Result<i32>

Source§

fn abs_flat(&self, code: u32) -> Result<i32>

Source§

fn abs_resolution(&self, code: u32) -> Result<i32>

Source§

fn set_abs_minimum(&self, code: u32, val: i32)

Source§

fn set_abs_maximum(&self, code: u32, val: i32)

Source§

fn set_abs_fuzz(&self, code: u32, val: i32)

Source§

fn set_abs_flat(&self, code: u32, val: i32)

Source§

fn set_abs_resolution(&self, code: u32, val: i32)

Source§

fn slot_value(&self, slot: u32, code: &EventCode) -> Option<i32>

Return the current value of the code for the given slot. Read more
Source§

fn set_slot_value(&self, slot: u32, code: &EventCode, val: i32) -> Result<()>

Set the value for a given code for the given slot. Read more
Source§

fn num_slots(&self) -> Option<i32>

Get the number of slots supported by this device. Read more
Source§

fn current_slot(&self) -> Option<i32>

Get the currently active slot. Read more
Source§

impl Drop for Device

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl Send for Device

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.