From 16810308e4a865dc8ccac09dd5a10fa698e3e008 Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Sun, 5 Dec 2021 19:25:15 +0100 Subject: [PATCH 1/2] Add `Device::send_event` and `RawDevice::send_event`. Some devices (such as keyboards) support writing events through event nodes to turn LEDs off and on, play sound effects or play ff effects. This commits adds the appropriate methods in the public API of the crate. I also added an example to showcase the new functionality. --- examples/blink_keyboard_leds.rs | 31 +++++++++++++++++++++++++++++++ src/raw_stream.rs | 16 ++++++++++++++++ src/sync_stream.rs | 10 ++++++++++ 3 files changed, 57 insertions(+) create mode 100644 examples/blink_keyboard_leds.rs diff --git a/examples/blink_keyboard_leds.rs b/examples/blink_keyboard_leds.rs new file mode 100644 index 0000000..3d7c3c8 --- /dev/null +++ b/examples/blink_keyboard_leds.rs @@ -0,0 +1,31 @@ +use evdev::{EventType, InputEvent, LedType}; + +mod _pick_device; + +fn main() { + let mut d = _pick_device::pick_device(); + println!("{}", d); + println!("Blinking the Keyboard LEDS..."); + for i in 0..5 { + let on = i % 2 != 0; + d.send_event(&InputEvent::new( + EventType::LED, + LedType::LED_CAPSL.0, + if on { i32::MAX } else { 0 }, + )) + .unwrap(); + d.send_event(&InputEvent::new( + EventType::LED, + LedType::LED_NUML.0, + if on { i32::MAX } else { 0 }, + )) + .unwrap(); + d.send_event(&InputEvent::new( + EventType::LED, + LedType::LED_SCROLLL.0, + if on { i32::MAX } else { 0 }, + )) + .unwrap(); + std::thread::sleep(std::time::Duration::from_secs(1)); + } +} diff --git a/src/raw_stream.rs b/src/raw_stream.rs index 984a113..ddfa403 100644 --- a/src/raw_stream.rs +++ b/src/raw_stream.rs @@ -610,6 +610,22 @@ impl RawDevice { } Ok(()) } + + /// Send an event to the device. + /// + /// Events that are typically sent to devices are + /// [EventType::LED] (turn device LEDs on and off), + /// [EventType::SOUND] (play a sound on the device) + /// and [EventType::FORCEFEEDBACK] (play force feedback events on the device, i.e. rumble). + pub fn send_event(&mut self, event: &InputEvent) -> io::Result<()> { + let raw_event = event.as_ref(); + let bytes_written = unsafe { + let buf = crate::cast_to_bytes(raw_event); + nix::unistd::write(self.as_raw_fd(), buf)? + }; + debug_assert_eq!(bytes_written, mem::size_of_val(raw_event)); + Ok(()) + } } impl AsRawFd for RawDevice { diff --git a/src/sync_stream.rs b/src/sync_stream.rs index 14dba2f..6c3b8c9 100644 --- a/src/sync_stream.rs +++ b/src/sync_stream.rs @@ -342,6 +342,16 @@ impl Device { pub fn ungrab(&mut self) -> io::Result<()> { self.raw.ungrab() } + + /// Send an event to the device. + /// + /// Events that are typically sent to devices are + /// [EventType::LED] (turn device LEDs on and off), + /// [EventType::SOUND] (play a sound on the device) + /// and [EventType::FORCEFEEDBACK] (play force feedback events on the device, i.e. rumble). + pub fn send_event(&mut self, event: &InputEvent) -> io::Result<()> { + self.raw.send_event(event) + } } impl AsRawFd for Device { From ab0f260115ac768111f521d5437496d48dddc13c Mon Sep 17 00:00:00 2001 From: Nicolas Koch Date: Mon, 6 Dec 2021 09:59:50 +0100 Subject: [PATCH 2/2] Update PR to bring it more in line with `VirtualDevice::emit` --- examples/blink_keyboard_leds.rs | 34 ++++++++++++++++----------------- src/raw_stream.rs | 14 +++++--------- src/sync_stream.rs | 6 +++--- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/examples/blink_keyboard_leds.rs b/examples/blink_keyboard_leds.rs index 3d7c3c8..bd20874 100644 --- a/examples/blink_keyboard_leds.rs +++ b/examples/blink_keyboard_leds.rs @@ -8,23 +8,23 @@ fn main() { println!("Blinking the Keyboard LEDS..."); for i in 0..5 { let on = i % 2 != 0; - d.send_event(&InputEvent::new( - EventType::LED, - LedType::LED_CAPSL.0, - if on { i32::MAX } else { 0 }, - )) - .unwrap(); - d.send_event(&InputEvent::new( - EventType::LED, - LedType::LED_NUML.0, - if on { i32::MAX } else { 0 }, - )) - .unwrap(); - d.send_event(&InputEvent::new( - EventType::LED, - LedType::LED_SCROLLL.0, - if on { i32::MAX } else { 0 }, - )) + d.send_events(&[ + InputEvent::new( + EventType::LED, + LedType::LED_CAPSL.0, + if on { i32::MAX } else { 0 }, + ), + InputEvent::new( + EventType::LED, + LedType::LED_NUML.0, + if on { i32::MAX } else { 0 }, + ), + InputEvent::new( + EventType::LED, + LedType::LED_SCROLLL.0, + if on { i32::MAX } else { 0 }, + ), + ]) .unwrap(); std::thread::sleep(std::time::Duration::from_secs(1)); } diff --git a/src/raw_stream.rs b/src/raw_stream.rs index ddfa403..d6c5a71 100644 --- a/src/raw_stream.rs +++ b/src/raw_stream.rs @@ -1,4 +1,5 @@ use std::fs::{File, OpenOptions}; +use std::io::Write; use std::mem::MaybeUninit; use std::os::unix::io::{AsRawFd, RawFd}; use std::path::Path; @@ -616,15 +617,10 @@ impl RawDevice { /// Events that are typically sent to devices are /// [EventType::LED] (turn device LEDs on and off), /// [EventType::SOUND] (play a sound on the device) - /// and [EventType::FORCEFEEDBACK] (play force feedback events on the device, i.e. rumble). - pub fn send_event(&mut self, event: &InputEvent) -> io::Result<()> { - let raw_event = event.as_ref(); - let bytes_written = unsafe { - let buf = crate::cast_to_bytes(raw_event); - nix::unistd::write(self.as_raw_fd(), buf)? - }; - debug_assert_eq!(bytes_written, mem::size_of_val(raw_event)); - Ok(()) + /// and [EventType::FORCEFEEDBACK] (play force feedback effects on the device, i.e. rumble). + pub fn send_events(&mut self, events: &[InputEvent]) -> io::Result<()> { + let bytes = unsafe { crate::cast_to_bytes(events) }; + self.file.write_all(bytes) } } diff --git a/src/sync_stream.rs b/src/sync_stream.rs index 6c3b8c9..3e8d3b1 100644 --- a/src/sync_stream.rs +++ b/src/sync_stream.rs @@ -348,9 +348,9 @@ impl Device { /// Events that are typically sent to devices are /// [EventType::LED] (turn device LEDs on and off), /// [EventType::SOUND] (play a sound on the device) - /// and [EventType::FORCEFEEDBACK] (play force feedback events on the device, i.e. rumble). - pub fn send_event(&mut self, event: &InputEvent) -> io::Result<()> { - self.raw.send_event(event) + /// and [EventType::FORCEFEEDBACK] (play force feedback effects on the device, i.e. rumble). + pub fn send_events(&mut self, events: &[InputEvent]) -> io::Result<()> { + self.raw.send_events(events) } }