use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use crate::error::Result;
use crate::types::{Button, ButtonMask};
use crate::device::Device;
pub struct EventHandle {
alive: Arc<AtomicBool>,
}
impl std::fmt::Debug for EventHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EventHandle")
.field("active", &self.alive.load(Ordering::Relaxed))
.finish()
}
}
impl EventHandle {
pub(crate) fn new(alive: Arc<AtomicBool>) -> Self {
Self { alive }
}
}
impl Drop for EventHandle {
fn drop(&mut self) {
self.alive.store(false, Ordering::Release);
}
}
pub(crate) const POLL_INTERVAL: Duration = Duration::from_millis(50);
impl Device {
pub fn on_button_press<F>(&self, button: Button, f: F) -> Result<EventHandle>
where
F: Fn(bool) + Send + 'static,
{
self.enable_button_stream()?;
let alive = Arc::new(AtomicBool::new(true));
let alive_clone = Arc::clone(&alive);
let rx = self.button_events();
std::thread::Builder::new()
.name("makcu-event-press".into())
.spawn(move || {
let mut prev_state = false;
while alive_clone.load(Ordering::Acquire) {
match rx.recv_timeout(POLL_INTERVAL) {
Ok(mask) => {
let current = mask.is_pressed(button);
if current != prev_state {
prev_state = current;
f(current);
}
}
Err(crossbeam_channel::RecvTimeoutError::Timeout) => continue,
Err(crossbeam_channel::RecvTimeoutError::Disconnected) => break,
}
}
})?;
Ok(EventHandle { alive })
}
pub fn on_button_event<F>(&self, f: F) -> Result<EventHandle>
where
F: Fn(ButtonMask) + Send + 'static,
{
self.enable_button_stream()?;
let alive = Arc::new(AtomicBool::new(true));
let alive_clone = Arc::clone(&alive);
let rx = self.button_events();
std::thread::Builder::new()
.name("makcu-event-any".into())
.spawn(move || {
while alive_clone.load(Ordering::Acquire) {
match rx.recv_timeout(POLL_INTERVAL) {
Ok(mask) => f(mask),
Err(crossbeam_channel::RecvTimeoutError::Timeout) => continue,
Err(crossbeam_channel::RecvTimeoutError::Disconnected) => break,
}
}
})?;
Ok(EventHandle { alive })
}
}
#[cfg(feature = "async")]
use crate::device::AsyncDevice;
#[cfg(feature = "async")]
impl AsyncDevice {
pub async fn on_button_press<F>(&self, button: Button, f: F) -> Result<EventHandle>
where
F: Fn(bool) + Send + 'static,
{
self.enable_button_stream().await?;
let alive = Arc::new(AtomicBool::new(true));
let alive_clone = Arc::clone(&alive);
let rx = self.button_events();
std::thread::Builder::new()
.name("makcu-async-event-press".into())
.spawn(move || {
let mut prev_state = false;
while alive_clone.load(Ordering::Acquire) {
match rx.recv_timeout(POLL_INTERVAL) {
Ok(mask) => {
let current = mask.is_pressed(button);
if current != prev_state {
prev_state = current;
f(current);
}
}
Err(crossbeam_channel::RecvTimeoutError::Timeout) => continue,
Err(crossbeam_channel::RecvTimeoutError::Disconnected) => break,
}
}
})?;
Ok(EventHandle { alive })
}
pub async fn on_button_event<F>(&self, f: F) -> Result<EventHandle>
where
F: Fn(ButtonMask) + Send + 'static,
{
self.enable_button_stream().await?;
let alive = Arc::new(AtomicBool::new(true));
let alive_clone = Arc::clone(&alive);
let rx = self.button_events();
std::thread::Builder::new()
.name("makcu-async-event-any".into())
.spawn(move || {
while alive_clone.load(Ordering::Acquire) {
match rx.recv_timeout(POLL_INTERVAL) {
Ok(mask) => f(mask),
Err(crossbeam_channel::RecvTimeoutError::Timeout) => continue,
Err(crossbeam_channel::RecvTimeoutError::Disconnected) => break,
}
}
})?;
Ok(EventHandle { alive })
}
}