Skip to content

Commit

Permalink
Add button change event handler
Browse files Browse the repository at this point in the history
  • Loading branch information
pixix4 committed Feb 25, 2024
1 parent 64bb536 commit ca64a5b
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 19 deletions.
File renamed without changes.
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand All @@ -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"]
Expand Down
1 change: 0 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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/*
Expand Down
26 changes: 26 additions & 0 deletions examples/button_handlers.rs
Original file line number Diff line number Diff line change
@@ -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));
}
}
69 changes: 62 additions & 7 deletions src/ev3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ struct ButtonMapEntry {
pub key_code: u32,
}

type ButtonChangeHandler = Box<dyn Fn(HashSet<String>)>;
type ButtonHandler = Box<dyn Fn(bool)>;

/// This implementation depends on the availability of the EVIOCGKEY ioctl
Expand All @@ -211,6 +212,7 @@ type ButtonHandler = Box<dyn Fn(bool)>;
struct ButtonFileHandler {
file_map: HashMap<String, FileMapEntry>,
button_map: HashMap<String, ButtonMapEntry>,
button_change_handler: Option<ButtonChangeHandler>,
button_handlers: HashMap<String, ButtonHandler>,
pressed_buttons: HashSet<String>,
}
Expand All @@ -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()
Expand All @@ -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(),
}
Expand All @@ -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<ButtonHandler>) {
if let Some(listener) = listener {
/// Sets an event handler for the given button.
fn set_button_handler(&mut self, name: &str, handler: Option<ButtonHandler>) {
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<ButtonChangeHandler>) {
self.button_change_handler = handler;
}

/// Gets a copy of the currently pressed buttons.
fn get_pressed_buttons(&self) -> HashSet<String> {
self.pressed_buttons.clone()
Expand Down Expand Up @@ -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());
}
}
}
}

Expand All @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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<String>) + '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);
Expand Down
14 changes: 7 additions & 7 deletions src/ev3_button_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 [<is_ $button_name>] (&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 {"]
Expand All @@ -45,14 +45,14 @@ macro_rules! ev3_button_functions {
pub fn [<set_ $button_name _handler>](&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 [<remove_ $button_name _handler>](&mut self) {
self.button_handler
.borrow_mut()
.set_button_listener("$button_name", None);
.set_button_handler(stringify!($button_name), None);
}
}
};
Expand Down

0 comments on commit ca64a5b

Please sign in to comment.