ndless_async/
keypad.rs

1//! Listens for button presses and releases from the keypad.
2//!
3//! To get started, [create a `KeypadListener`][KeypadListener::new] and read
4//! its documentation.
5
6use alloc::rc::{Rc, Weak};
7use core::cell::{Ref, RefCell};
8use core::future::Future;
9use core::mem;
10use core::pin::Pin;
11use core::task::{Context, Poll};
12use core::time::Duration;
13
14use crossbeam_queue::ArrayQueue;
15use futures_util::{stream::Stream, task::AtomicWaker, StreamExt};
16use ignore_result::Ignore;
17use ndless::input::{iter_keys, Key};
18use ndless::prelude::*;
19use ndless::timer::{get_ticks, Ticks, TICKS_PER_SECOND};
20
21use crate::timer::TimerListener;
22
23/// The state of the key, either pressed or released.
24#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)]
25pub enum KeyState {
26	Pressed,
27	Released,
28}
29
30/// One event representing a key press or release.
31#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)]
32pub struct KeyEvent {
33	pub key: Key,
34	pub state: KeyState,
35	/// Tick that this event occurred
36	pub tick_at: u32,
37}
38
39struct SharedKeyQueue {
40	queue: ArrayQueue<KeyEvent>,
41	waker: AtomicWaker,
42}
43
44#[derive(Default)]
45struct KeypadListenerInner {
46	queues: RefCell<Vec<Rc<SharedKeyQueue>>>,
47	keys: RefCell<Vec<Key>>,
48}
49
50impl KeypadListenerInner {
51	fn poll(&self) {
52		let mut queues = self.queues.borrow_mut();
53		queues.retain(|queue| Rc::strong_count(queue) > 1);
54		if queues.is_empty() {
55			return;
56		}
57		let mut keys = self.keys.borrow_mut();
58		let mut retain_i = 0;
59		let mut change = false;
60		iter_keys().for_each(|key| {
61			if let Some((i, _)) = keys.iter().enumerate().find(|(_, other)| key == **other) {
62				if i > retain_i {
63					let (beginning, end) = keys.split_at_mut(i);
64					mem::swap(&mut beginning[retain_i], &mut end[0]);
65				}
66				retain_i += 1;
67			} else {
68				change = true;
69				keys.push(key);
70				let tick_at = get_ticks();
71				queues.iter_mut().for_each(|queue| {
72					queue
73						.queue
74						.push(KeyEvent {
75							key,
76							state: KeyState::Pressed,
77							tick_at,
78						})
79						.ignore()
80				});
81				if keys.len() > retain_i + 1 {
82					let (last, beginning) = keys.split_last_mut().unwrap();
83					mem::swap(&mut beginning[retain_i], last);
84				}
85				retain_i += 1;
86			}
87		});
88		let tick_at = get_ticks();
89		for _ in retain_i..keys.len() {
90			change = true;
91			let key = keys.pop().unwrap();
92			queues.iter_mut().for_each(|queue| {
93				queue
94					.queue
95					.push(KeyEvent {
96						key,
97						state: KeyState::Released,
98						tick_at,
99					})
100					.ignore()
101			});
102		}
103		if change {
104			queues.iter_mut().for_each(|queue| queue.waker.wake());
105		}
106	}
107}
108
109/// Polls the keypad.
110///
111/// ```rust
112/// use ndless_async::task::{block_on, AsyncListeners};
113/// use ndless_async::keypad::{KeypadListener, KeyState};
114/// use ndless_async::StreamExt;
115///
116/// let listeners = AsyncListeners::new();
117/// block_on(&listeners, async {
118///     let keypad = KeypadListener::new(&listeners.timer());
119///     let mut stream = keypad.stream();
120///     while let Some(event) = stream.next().await {
121///         println!(
122///             "Key {:?} was {}",
123///             event.key,
124///             if event.state == KeyState::Released {
125///                 "released"
126///             } else {
127///                 "pressed"
128///             }
129///         );
130///     }
131/// });
132/// ```
133pub struct KeypadListener<'a> {
134	timer_listener: Option<&'a TimerListener>,
135	rate: u32,
136	interval: RefCell<Weak<RefCell<dyn Future<Output = ()> + Unpin>>>,
137	inner: Rc<KeypadListenerInner>,
138}
139
140impl<'a> KeypadListener<'a> {
141	/// Creates a new keypad listener that polls the keypad 30 times per second.
142	/// Use the `new_with_*` series of functions to change the polling rate. You
143	/// may also poll the keypad manually by using
144	/// [`new_manually_polled`][KeypadListener::new_manually_polled].
145	pub fn new(timer_listener: &'a TimerListener) -> Self {
146		Self::new_with_hz(timer_listener, 30)
147	}
148	/// Creates a new keypad listener that polls the keypad with the specified
149	/// number of events per second.
150	pub fn new_with_hz(timer_listener: &'a TimerListener, hz: u32) -> Self {
151		Self::new_with_ticks(timer_listener, TICKS_PER_SECOND / hz)
152	}
153	/// Creates a new keypad listener that polls the keypad every `dur`
154	/// milliseconds.
155	pub fn new_with_ms(timer_listener: &'a TimerListener, dur: u32) -> Self {
156		Self::new_with_rate(timer_listener, Duration::from_millis(dur as u64))
157	}
158	/// Creates a new keypad listener that polls the keypad with the specified
159	/// interval.
160	pub fn new_with_rate(timer_listener: &'a TimerListener, dur: Duration) -> Self {
161		Self::new_with_ticks(timer_listener, dur.as_ticks())
162	}
163	/// Creates a new keypad listener that polls the keypad every specified
164	/// ticks.
165	pub fn new_with_ticks(timer_listener: &'a TimerListener, ticks: u32) -> Self {
166		Self {
167			timer_listener: Some(timer_listener),
168			rate: ticks,
169			interval: RefCell::new(Weak::<RefCell<futures_util::future::Ready<()>>>::new()),
170			inner: Default::default(),
171		}
172	}
173	/// Creates a new keypad listener that isn't automatically polled. You'll
174	/// need to use [`poll`][KeypadListener::poll] periodically to poll the
175	/// keypad.
176	pub fn new_manually_polled() -> Self {
177		Self {
178			timer_listener: None,
179			rate: 0,
180			interval: RefCell::new(Weak::<RefCell<futures_util::future::Ready<()>>>::new()),
181			inner: Rc::new(Default::default()),
182		}
183	}
184	fn interval(&self) -> Rc<RefCell<dyn Future<Output = ()> + Unpin>> {
185		if let Some(interval) = self.interval.borrow().upgrade() {
186			return interval;
187		}
188		let listener = self.inner.clone();
189		let interval: Rc<RefCell<dyn Future<Output = ()> + Unpin>> =
190			if let Some(timer_listener) = self.timer_listener {
191				Rc::new(RefCell::new(
192					timer_listener.every_ticks(self.rate).for_each(move |_| {
193						listener.poll();
194						futures_util::future::ready(())
195					}),
196				))
197			} else {
198				Rc::new(RefCell::new(futures_util::future::pending()))
199			};
200		self.interval.replace(Rc::downgrade(&interval));
201		interval
202	}
203	/// Polls the keypad. You shouldn't have to use this normally.
204	pub fn poll(&self) {
205		self.inner.poll();
206	}
207	/// Each call to `stream` returns a unique stream, meaning that calling it
208	/// from different tasks will allow each task to receive every event. A
209	/// buffer of 100 keypress events is allocated. Use
210	/// [`stream_with_buffer`][KeypadListener::stream_with_buffer] to specify a
211	/// custom size.
212	///
213	/// ## Warning
214	/// Don't use this function in a loop. You should call `stream` before the
215	/// loop, or use a stream combinator such as [`for_each`]. Failure to do so
216	/// will result in lost events and less efficient code.
217	///
218	/// [`for_each`]: https://docs.rs/futures-util/0.3.*/futures_util/stream/trait.StreamExt.html#method.for_each
219	pub fn stream(&self) -> KeyStream {
220		let mut queues = self.inner.queues.borrow_mut();
221		let queue = Rc::new(SharedKeyQueue {
222			queue: ArrayQueue::new(100),
223			waker: AtomicWaker::new(),
224		});
225		queues.push(queue.clone());
226		KeyStream {
227			queue,
228			interval: self.interval(),
229		}
230	}
231	/// This is the same as [`stream`][KeypadListener::stream], except that it
232	/// allows specifying a buffer size other than the default of 100.
233	///
234	/// ## Warning
235	/// Don't use this function in a loop. You should call `stream_with_buffer`
236	/// before the loop, or use a stream combinator such as [`for_each`].
237	/// Failure to do so will result in lost events and less efficient code.
238	///
239	/// [`for_each`]: https://docs.rs/futures-util/0.3.*/futures_util/stream/trait.StreamExt.html#method.for_each
240	pub fn stream_with_buffer(&self, size: usize) -> KeyStream {
241		let mut queues = self.inner.queues.borrow_mut();
242		let queue = Rc::new(SharedKeyQueue {
243			queue: ArrayQueue::new(size),
244			waker: AtomicWaker::new(),
245		});
246		queues.push(queue.clone());
247		KeyStream {
248			queue,
249			interval: self.interval(),
250		}
251	}
252	/// Returns a [`Ref`] to the keys that are currently pressed.
253	/// **You must [`drop`] this reference either explicitly or by
254	/// ending the current scope before `.await`ing something**. The
255	/// program will crash otherwise.
256	pub fn list_keys(&self) -> Ref<Vec<Key>> {
257		self.inner.keys.borrow()
258	}
259}
260
261/// A stream of [`KeyEvent`]s. Use [`KeypadListener::stream`] to get one.
262///
263/// # Example
264/// ```
265/// use ndless_async::StreamExt;
266/// use ndless_async::keypad::KeyState::*;
267///
268/// let mut keypad = listeners.keypad();
269/// while let Some(event) = keypad.next().await {
270///     println!(
271///         "Key {:?} was {}",
272///         event.key,
273///         if event.state == Released { "released" } else { "pressed" }
274///     );
275/// }
276/// ```
277pub struct KeyStream {
278	queue: Rc<SharedKeyQueue>,
279	interval: Rc<RefCell<dyn Future<Output = ()> + Unpin>>,
280}
281
282impl Stream for KeyStream {
283	type Item = KeyEvent;
284
285	fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
286		let mut interval = self.interval.borrow_mut();
287		let _ = Pin::new(&mut *interval).poll(cx);
288		self.queue.waker.register(cx.waker());
289		if let Ok(key) = self.queue.queue.pop() {
290			Poll::Ready(Some(key))
291		} else {
292			Poll::Pending
293		}
294	}
295}