Skip to content

Commit ca64a5b

Browse files
committed
Add button change event handler
1 parent 64bb536 commit ca64a5b

File tree

6 files changed

+99
-19
lines changed

6 files changed

+99
-19
lines changed
File renamed without changes.

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,6 @@ lto = true
3838
strip = "debuginfo"
3939
opt-level = "z"
4040

41-
[[example]]
42-
name = "screen"
43-
required-features = ["screen"]
44-
4541
[package.metadata.docs.rs]
4642
features = ["ev3", "screen"]
4743
rustdoc-args = ["--cfg", "docsrs"]
@@ -50,6 +46,10 @@ rustdoc-args = ["--cfg", "docsrs"]
5046
name = "buttons"
5147
required-features = ["ev3"]
5248

49+
[[example]]
50+
name = "screen"
51+
required-features = ["screen"]
52+
5353
[[test]]
5454
name = "ev3"
5555
required-features = ["ev3"]

docker/Dockerfile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ FROM debian:trixie-slim
33
RUN dpkg --add-architecture armel
44

55
RUN apt-get update
6-
# 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
76

87
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 \
98
&& rm -rf /var/lib/apt/lists/*

examples/button_handlers.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
extern crate ev3dev_lang_rust;
2+
3+
use ev3dev_lang_rust::{Button, Ev3Result};
4+
5+
fn main() -> Ev3Result<()> {
6+
let mut button = Button::new()?;
7+
8+
button.set_change_handler(|pressed_buttons| println!("Pressed buttons: {:?}", pressed_buttons));
9+
10+
button.set_up_handler(|is_pressed| println!("Button 'up' is pressed: {}", is_pressed));
11+
button.set_down_handler(|is_pressed| println!("Button 'down' is pressed: {}", is_pressed));
12+
button.set_left_handler(|is_pressed| println!("Button 'left' is pressed: {}", is_pressed));
13+
button.set_right_handler(|is_pressed| println!("Button 'right' is pressed: {}", is_pressed));
14+
button.set_enter_handler(|is_pressed| println!("Button 'enter' is pressed: {}", is_pressed));
15+
button.set_backspace_handler(|is_pressed| {
16+
println!("Button 'backspace' is pressed: {}", is_pressed)
17+
});
18+
button.set_backspace_handler(|is_pressed| {
19+
println!("Button 'backspace' is pressed: {}", is_pressed)
20+
});
21+
22+
loop {
23+
button.process();
24+
std::thread::sleep(std::time::Duration::from_millis(100));
25+
}
26+
}

src/ev3.rs

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ struct ButtonMapEntry {
203203
pub key_code: u32,
204204
}
205205

206+
type ButtonChangeHandler = Box<dyn Fn(HashSet<String>)>;
206207
type ButtonHandler = Box<dyn Fn(bool)>;
207208

208209
/// This implementation depends on the availability of the EVIOCGKEY ioctl
@@ -211,6 +212,7 @@ type ButtonHandler = Box<dyn Fn(bool)>;
211212
struct ButtonFileHandler {
212213
file_map: HashMap<String, FileMapEntry>,
213214
button_map: HashMap<String, ButtonMapEntry>,
215+
button_change_handler: Option<ButtonChangeHandler>,
214216
button_handlers: HashMap<String, ButtonHandler>,
215217
pressed_buttons: HashSet<String>,
216218
}
@@ -220,6 +222,10 @@ impl std::fmt::Debug for ButtonFileHandler {
220222
f.debug_struct("ButtonFileHandler")
221223
.field("file_map", &self.file_map)
222224
.field("button_map", &self.button_map)
225+
.field(
226+
"button_change_handler",
227+
&self.button_change_handler.is_some(),
228+
)
223229
.field("button_handlers", &self.button_map.keys())
224230
.field("pressed_buttons", &self.pressed_buttons)
225231
.finish()
@@ -232,6 +238,7 @@ impl ButtonFileHandler {
232238
ButtonFileHandler {
233239
file_map: HashMap::new(),
234240
button_map: HashMap::new(),
241+
button_change_handler: None,
235242
button_handlers: HashMap::new(),
236243
pressed_buttons: HashSet::new(),
237244
}
@@ -258,15 +265,20 @@ impl ButtonFileHandler {
258265
Ok(())
259266
}
260267

261-
/// Sets an event listener for the given button.
262-
fn set_button_listener(&mut self, name: &str, listener: Option<ButtonHandler>) {
263-
if let Some(listener) = listener {
268+
/// Sets an event handler for the given button.
269+
fn set_button_handler(&mut self, name: &str, handler: Option<ButtonHandler>) {
270+
if let Some(listener) = handler {
264271
self.button_handlers.insert(name.to_owned(), listener);
265272
} else {
266273
self.button_handlers.remove(name);
267274
}
268275
}
269276

277+
/// Sets an event handler for any button state change.
278+
fn set_button_change_handler(&mut self, handler: Option<ButtonChangeHandler>) {
279+
self.button_change_handler = handler;
280+
}
281+
270282
/// Gets a copy of the currently pressed buttons.
271283
fn get_pressed_buttons(&self) -> HashSet<String> {
272284
self.pressed_buttons.clone()
@@ -309,11 +321,20 @@ impl ButtonFileHandler {
309321
}
310322

311323
let difference = old_pressed_buttons.symmetric_difference(&self.pressed_buttons);
324+
325+
let mut difference_count = 0;
312326
for button in difference {
327+
difference_count += 1;
313328
if self.button_handlers.contains_key(button) {
314329
self.button_handlers[button](self.get_button_state(button));
315330
}
316331
}
332+
333+
if difference_count > 0 {
334+
if let Some(ref handler) = self.button_change_handler {
335+
handler(self.get_pressed_buttons());
336+
}
337+
}
317338
}
318339
}
319340

@@ -329,10 +350,10 @@ impl ButtonFileHandler {
329350
/// use std::time::Duration;
330351
///
331352
/// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
332-
/// let button = Button::new()?;
353+
/// let mut button = Button::new()?;
333354
///
334355
/// button.set_down_handler(|is_pressed| {
335-
/// println("Is 'down' pressed: {is_pressed}");
356+
/// println!("Is 'down' pressed: {is_pressed}");
336357
/// });
337358
///
338359
/// loop {
@@ -379,10 +400,10 @@ impl Button {
379400
/// use std::time::Duration;
380401
///
381402
/// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
382-
/// let button = Button::new()?;
403+
/// let mut button = Button::new()?;
383404
///
384405
/// button.set_down_handler(|is_pressed| {
385-
/// println("Is 'down' pressed: {is_pressed}");
406+
/// println!("Is 'down' pressed: {is_pressed}");
386407
/// });
387408
///
388409
/// loop {
@@ -420,6 +441,40 @@ impl Button {
420441
self.button_handler.borrow().get_pressed_buttons()
421442
}
422443

444+
/// Set an event handler, that is called by `process()` if any button state changes.
445+
/// Has a set of all pressed buttons as parameter.
446+
///
447+
/// ```no_run
448+
/// use ev3dev_lang_rust::Button;
449+
/// use std::thread;
450+
/// use std::time::Duration;
451+
///
452+
/// # fn main() -> ev3dev_lang_rust::Ev3Result<()> {
453+
/// let mut button = Button::new()?;
454+
///
455+
/// button.set_change_handler(|pressed_buttons| {
456+
/// println!("pressed buttons: {:?}", pressed_buttons);
457+
/// });
458+
///
459+
/// loop {
460+
/// button.process();
461+
/// thread::sleep(Duration::from_millis(100));
462+
/// }
463+
/// # }
464+
/// ```
465+
pub fn set_change_handler(&mut self, handler: impl Fn(HashSet<String>) + 'static) {
466+
self.button_handler
467+
.borrow_mut()
468+
.set_button_change_handler(Some(Box::new(handler)))
469+
}
470+
471+
/// Removes the change event handler.
472+
pub fn remove_change_handler(&mut self) {
473+
self.button_handler
474+
.borrow_mut()
475+
.set_button_change_handler(None)
476+
}
477+
423478
ev3_button_functions!(up);
424479
ev3_button_functions!(down);
425480
ev3_button_functions!(left);

src/ev3_button_functions.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,26 @@ macro_rules! ev3_button_functions {
1414
#[doc = ""]
1515
#[doc = "loop {"]
1616
#[doc = " button.process();"]
17-
#[doc = " println(\"Is '" $button_name "' pressed: {}\", button.is_" $button_name "());"]
17+
#[doc = " println!(\"Is '" $button_name "' pressed: {}\", button.is_" $button_name "());"]
1818
#[doc = " thread::sleep(Duration::from_millis(100));"]
1919
#[doc = "}"]
2020
#[doc = "# }"]
2121
#[doc = "```"]
2222
pub fn [<is_ $button_name>] (&self) -> bool {
23-
self.button_handler.borrow().get_button_state("$button_name")
23+
self.button_handler.borrow().get_button_state(stringify!($button_name))
2424
}
2525

26-
#[doc = "Set an event handler for changes in the pressed state of the `" $button_name "` button."]
26+
#[doc = "Set an event handler, that is called by `process()` if the pressed state of the `" $button_name "` button changes."]
2727
#[doc = "```no_run"]
2828
#[doc = "use ev3dev_lang_rust::Button;"]
2929
#[doc = "use std::thread;"]
3030
#[doc = "use std::time::Duration;"]
3131
#[doc = ""]
3232
#[doc = "# fn main() -> ev3dev_lang_rust::Ev3Result<()> {"]
33-
#[doc = "let button = Button::new()?;"]
33+
#[doc = "let mut button = Button::new()?;"]
3434
#[doc = ""]
3535
#[doc = "button.set_" $button_name "_handler(|is_pressed| {"]
36-
#[doc = " println(\"Is '" $button_name "' pressed: {is_pressed}\");"]
36+
#[doc = " println!(\"Is '" $button_name "' pressed: {}\", is_pressed);"]
3737
#[doc = "});"]
3838
#[doc = ""]
3939
#[doc = "loop {"]
@@ -45,14 +45,14 @@ macro_rules! ev3_button_functions {
4545
pub fn [<set_ $button_name _handler>](&mut self, handler: impl Fn(bool) + 'static) {
4646
self.button_handler
4747
.borrow_mut()
48-
.set_button_listener("$button_name", Some(Box::new(handler)));
48+
.set_button_handler(stringify!($button_name), Some(Box::new(handler)));
4949
}
5050

5151
#[doc = "Removes the event handler of the `" $button_name "` button."]
5252
pub fn [<remove_ $button_name _handler>](&mut self) {
5353
self.button_handler
5454
.borrow_mut()
55-
.set_button_listener("$button_name", None);
55+
.set_button_handler(stringify!($button_name), None);
5656
}
5757
}
5858
};

0 commit comments

Comments
 (0)