From ca64a5b5bcf6482759eb18eb3b50e483a42ff1f2 Mon Sep 17 00:00:00 2001 From: Lars Westermann Date: Sun, 25 Feb 2024 07:37:20 +0100 Subject: [PATCH] Add button change event handler --- .cargo/{config => config.toml} | 0 Cargo.toml | 8 ++-- docker/Dockerfile | 1 - examples/button_handlers.rs | 26 +++++++++++++ src/ev3.rs | 69 ++++++++++++++++++++++++++++++---- src/ev3_button_functions.rs | 14 +++---- 6 files changed, 99 insertions(+), 19 deletions(-) rename .cargo/{config => config.toml} (100%) create mode 100644 examples/button_handlers.rs diff --git a/.cargo/config b/.cargo/config.toml similarity index 100% rename from .cargo/config rename to .cargo/config.toml diff --git a/Cargo.toml b/Cargo.toml index 970e42d..e2b3ea2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,10 +38,6 @@ lto = true strip = "debuginfo" opt-level = "z" -[[example]] -name = "screen" -required-features = ["screen"] - [package.metadata.docs.rs] features = ["ev3", "screen"] rustdoc-args = ["--cfg", "docsrs"] @@ -50,6 +46,10 @@ rustdoc-args = ["--cfg", "docsrs"] name = "buttons" required-features = ["ev3"] +[[example]] +name = "screen" +required-features = ["screen"] + [[test]] name = "ev3" required-features = ["ev3"] diff --git a/docker/Dockerfile b/docker/Dockerfile index 57668f7..cf35f9d 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -3,7 +3,6 @@ FROM debian:trixie-slim RUN dpkg --add-architecture armel RUN apt-get update -# RUN sed -i "s#deb http://security.debian.org/debian-security stretch/updates main#deb http://deb.debian.org/debian-security stretch/updates main#g" /etc/apt/sources.list RUN apt-get --yes install curl cmake pkg-config clang g++ g++-arm-linux-gnueabi crossbuild-essential-armel libssl-dev libssl-dev:armel libclang-dev \ && rm -rf /var/lib/apt/lists/* diff --git a/examples/button_handlers.rs b/examples/button_handlers.rs new file mode 100644 index 0000000..8b253a6 --- /dev/null +++ b/examples/button_handlers.rs @@ -0,0 +1,26 @@ +extern crate ev3dev_lang_rust; + +use ev3dev_lang_rust::{Button, Ev3Result}; + +fn main() -> Ev3Result<()> { + let mut button = Button::new()?; + + button.set_change_handler(|pressed_buttons| println!("Pressed buttons: {:?}", pressed_buttons)); + + button.set_up_handler(|is_pressed| println!("Button 'up' is pressed: {}", is_pressed)); + button.set_down_handler(|is_pressed| println!("Button 'down' is pressed: {}", is_pressed)); + button.set_left_handler(|is_pressed| println!("Button 'left' is pressed: {}", is_pressed)); + button.set_right_handler(|is_pressed| println!("Button 'right' is pressed: {}", is_pressed)); + button.set_enter_handler(|is_pressed| println!("Button 'enter' is pressed: {}", is_pressed)); + button.set_backspace_handler(|is_pressed| { + println!("Button 'backspace' is pressed: {}", is_pressed) + }); + button.set_backspace_handler(|is_pressed| { + println!("Button 'backspace' is pressed: {}", is_pressed) + }); + + loop { + button.process(); + std::thread::sleep(std::time::Duration::from_millis(100)); + } +} diff --git a/src/ev3.rs b/src/ev3.rs index 88b8ece..d780676 100644 --- a/src/ev3.rs +++ b/src/ev3.rs @@ -203,6 +203,7 @@ struct ButtonMapEntry { pub key_code: u32, } +type ButtonChangeHandler = Box)>; type ButtonHandler = Box; /// This implementation depends on the availability of the EVIOCGKEY ioctl @@ -211,6 +212,7 @@ type ButtonHandler = Box; struct ButtonFileHandler { file_map: HashMap, button_map: HashMap, + button_change_handler: Option, button_handlers: HashMap, pressed_buttons: HashSet, } @@ -220,6 +222,10 @@ impl std::fmt::Debug for ButtonFileHandler { f.debug_struct("ButtonFileHandler") .field("file_map", &self.file_map) .field("button_map", &self.button_map) + .field( + "button_change_handler", + &self.button_change_handler.is_some(), + ) .field("button_handlers", &self.button_map.keys()) .field("pressed_buttons", &self.pressed_buttons) .finish() @@ -232,6 +238,7 @@ impl ButtonFileHandler { ButtonFileHandler { file_map: HashMap::new(), button_map: HashMap::new(), + button_change_handler: None, button_handlers: HashMap::new(), pressed_buttons: HashSet::new(), } @@ -258,15 +265,20 @@ impl ButtonFileHandler { Ok(()) } - /// Sets an event listener for the given button. - fn set_button_listener(&mut self, name: &str, listener: Option) { - if let Some(listener) = listener { + /// Sets an event handler for the given button. + fn set_button_handler(&mut self, name: &str, handler: Option) { + if let Some(listener) = handler { self.button_handlers.insert(name.to_owned(), listener); } else { self.button_handlers.remove(name); } } + /// Sets an event handler for any button state change. + fn set_button_change_handler(&mut self, handler: Option) { + self.button_change_handler = handler; + } + /// Gets a copy of the currently pressed buttons. fn get_pressed_buttons(&self) -> HashSet { self.pressed_buttons.clone() @@ -309,11 +321,20 @@ impl ButtonFileHandler { } let difference = old_pressed_buttons.symmetric_difference(&self.pressed_buttons); + + let mut difference_count = 0; for button in difference { + difference_count += 1; if self.button_handlers.contains_key(button) { self.button_handlers[button](self.get_button_state(button)); } } + + if difference_count > 0 { + if let Some(ref handler) = self.button_change_handler { + handler(self.get_pressed_buttons()); + } + } } } @@ -329,10 +350,10 @@ impl ButtonFileHandler { /// use std::time::Duration; /// /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> { -/// let button = Button::new()?; +/// let mut button = Button::new()?; /// /// button.set_down_handler(|is_pressed| { -/// println("Is 'down' pressed: {is_pressed}"); +/// println!("Is 'down' pressed: {is_pressed}"); /// }); /// /// loop { @@ -379,10 +400,10 @@ impl Button { /// use std::time::Duration; /// /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> { - /// let button = Button::new()?; + /// let mut button = Button::new()?; /// /// button.set_down_handler(|is_pressed| { - /// println("Is 'down' pressed: {is_pressed}"); + /// println!("Is 'down' pressed: {is_pressed}"); /// }); /// /// loop { @@ -420,6 +441,40 @@ impl Button { self.button_handler.borrow().get_pressed_buttons() } + /// Set an event handler, that is called by `process()` if any button state changes. + /// Has a set of all pressed buttons as parameter. + /// + /// ```no_run + /// use ev3dev_lang_rust::Button; + /// use std::thread; + /// use std::time::Duration; + /// + /// # fn main() -> ev3dev_lang_rust::Ev3Result<()> { + /// let mut button = Button::new()?; + /// + /// button.set_change_handler(|pressed_buttons| { + /// println!("pressed buttons: {:?}", pressed_buttons); + /// }); + /// + /// loop { + /// button.process(); + /// thread::sleep(Duration::from_millis(100)); + /// } + /// # } + /// ``` + pub fn set_change_handler(&mut self, handler: impl Fn(HashSet) + 'static) { + self.button_handler + .borrow_mut() + .set_button_change_handler(Some(Box::new(handler))) + } + + /// Removes the change event handler. + pub fn remove_change_handler(&mut self) { + self.button_handler + .borrow_mut() + .set_button_change_handler(None) + } + ev3_button_functions!(up); ev3_button_functions!(down); ev3_button_functions!(left); diff --git a/src/ev3_button_functions.rs b/src/ev3_button_functions.rs index ac97a40..5351e6d 100644 --- a/src/ev3_button_functions.rs +++ b/src/ev3_button_functions.rs @@ -14,26 +14,26 @@ macro_rules! ev3_button_functions { #[doc = ""] #[doc = "loop {"] #[doc = " button.process();"] - #[doc = " println(\"Is '" $button_name "' pressed: {}\", button.is_" $button_name "());"] + #[doc = " println!(\"Is '" $button_name "' pressed: {}\", button.is_" $button_name "());"] #[doc = " thread::sleep(Duration::from_millis(100));"] #[doc = "}"] #[doc = "# }"] #[doc = "```"] pub fn [] (&self) -> bool { - self.button_handler.borrow().get_button_state("$button_name") + self.button_handler.borrow().get_button_state(stringify!($button_name)) } - #[doc = "Set an event handler for changes in the pressed state of the `" $button_name "` button."] + #[doc = "Set an event handler, that is called by `process()` if the pressed state of the `" $button_name "` button changes."] #[doc = "```no_run"] #[doc = "use ev3dev_lang_rust::Button;"] #[doc = "use std::thread;"] #[doc = "use std::time::Duration;"] #[doc = ""] #[doc = "# fn main() -> ev3dev_lang_rust::Ev3Result<()> {"] - #[doc = "let button = Button::new()?;"] + #[doc = "let mut button = Button::new()?;"] #[doc = ""] #[doc = "button.set_" $button_name "_handler(|is_pressed| {"] - #[doc = " println(\"Is '" $button_name "' pressed: {is_pressed}\");"] + #[doc = " println!(\"Is '" $button_name "' pressed: {}\", is_pressed);"] #[doc = "});"] #[doc = ""] #[doc = "loop {"] @@ -45,14 +45,14 @@ macro_rules! ev3_button_functions { pub fn [](&mut self, handler: impl Fn(bool) + 'static) { self.button_handler .borrow_mut() - .set_button_listener("$button_name", Some(Box::new(handler))); + .set_button_handler(stringify!($button_name), Some(Box::new(handler))); } #[doc = "Removes the event handler of the `" $button_name "` button."] pub fn [](&mut self) { self.button_handler .borrow_mut() - .set_button_listener("$button_name", None); + .set_button_handler(stringify!($button_name), None); } } };