use alloc::rc::{Rc, Weak};
use core::cell::{Ref, RefCell};
use core::future::Future;
use core::mem;
use core::pin::Pin;
use core::task::{Context, Poll};
use core::time::Duration;
use crossbeam_queue::ArrayQueue;
use futures_util::{stream::Stream, task::AtomicWaker, StreamExt};
use ignore_result::Ignore;
use ndless::input::{iter_keys, Key};
use ndless::prelude::*;
use ndless::timer::{get_ticks, Ticks, TICKS_PER_SECOND};
use crate::timer::TimerListener;
#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)]
pub enum KeyState {
Pressed,
Released,
}
#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)]
pub struct KeyEvent {
pub key: Key,
pub state: KeyState,
pub tick_at: u32,
}
struct SharedKeyQueue {
queue: ArrayQueue<KeyEvent>,
waker: AtomicWaker,
}
#[derive(Default)]
struct KeypadListenerInner {
queues: RefCell<Vec<Rc<SharedKeyQueue>>>,
keys: RefCell<Vec<Key>>,
}
impl KeypadListenerInner {
fn poll(&self) {
let mut queues = self.queues.borrow_mut();
queues.retain(|queue| Rc::strong_count(queue) > 1);
if queues.is_empty() {
return;
}
let mut keys = self.keys.borrow_mut();
let mut retain_i = 0;
let mut change = false;
iter_keys().for_each(|key| {
if let Some((i, _)) = keys.iter().enumerate().find(|(_, other)| key == **other) {
if i > retain_i {
let (beginning, end) = keys.split_at_mut(i);
mem::swap(&mut beginning[retain_i], &mut end[0]);
}
retain_i += 1;
} else {
change = true;
keys.push(key);
let tick_at = get_ticks();
queues.iter_mut().for_each(|queue| {
queue
.queue
.push(KeyEvent {
key,
state: KeyState::Pressed,
tick_at,
})
.ignore()
});
if keys.len() > retain_i + 1 {
let (last, beginning) = keys.split_last_mut().unwrap();
mem::swap(&mut beginning[retain_i], last);
}
retain_i += 1;
}
});
let tick_at = get_ticks();
for _ in retain_i..keys.len() {
change = true;
let key = keys.pop().unwrap();
queues.iter_mut().for_each(|queue| {
queue
.queue
.push(KeyEvent {
key,
state: KeyState::Released,
tick_at,
})
.ignore()
});
}
if change {
queues.iter_mut().for_each(|queue| queue.waker.wake());
}
}
}
pub struct KeypadListener<'a> {
timer_listener: Option<&'a TimerListener>,
rate: u32,
interval: RefCell<Weak<RefCell<dyn Future<Output = ()> + Unpin>>>,
inner: Rc<KeypadListenerInner>,
}
impl<'a> KeypadListener<'a> {
pub fn new(timer_listener: &'a TimerListener) -> Self {
Self::new_with_hz(timer_listener, 30)
}
pub fn new_with_hz(timer_listener: &'a TimerListener, hz: u32) -> Self {
Self::new_with_ticks(timer_listener, TICKS_PER_SECOND / hz)
}
pub fn new_with_ms(timer_listener: &'a TimerListener, dur: u32) -> Self {
Self::new_with_rate(timer_listener, Duration::from_millis(dur as u64))
}
pub fn new_with_rate(timer_listener: &'a TimerListener, dur: Duration) -> Self {
Self::new_with_ticks(timer_listener, dur.as_ticks())
}
pub fn new_with_ticks(timer_listener: &'a TimerListener, ticks: u32) -> Self {
Self {
timer_listener: Some(timer_listener),
rate: ticks,
interval: RefCell::new(Weak::<RefCell<futures_util::future::Ready<()>>>::new()),
inner: Default::default(),
}
}
pub fn new_manually_polled() -> Self {
Self {
timer_listener: None,
rate: 0,
interval: RefCell::new(Weak::<RefCell<futures_util::future::Ready<()>>>::new()),
inner: Rc::new(Default::default()),
}
}
fn interval(&self) -> Rc<RefCell<dyn Future<Output = ()> + Unpin>> {
if let Some(interval) = self.interval.borrow().upgrade() {
return interval;
}
let listener = self.inner.clone();
let interval: Rc<RefCell<dyn Future<Output = ()> + Unpin>> =
if let Some(timer_listener) = self.timer_listener {
Rc::new(RefCell::new(
timer_listener.every_ticks(self.rate).for_each(move |_| {
listener.poll();
futures_util::future::ready(())
}),
))
} else {
Rc::new(RefCell::new(futures_util::future::pending()))
};
self.interval.replace(Rc::downgrade(&interval));
interval
}
pub fn poll(&self) {
self.inner.poll();
}
pub fn stream(&self) -> KeyStream {
let mut queues = self.inner.queues.borrow_mut();
let queue = Rc::new(SharedKeyQueue {
queue: ArrayQueue::new(100),
waker: AtomicWaker::new(),
});
queues.push(queue.clone());
KeyStream {
queue,
interval: self.interval(),
}
}
pub fn stream_with_buffer(&self, size: usize) -> KeyStream {
let mut queues = self.inner.queues.borrow_mut();
let queue = Rc::new(SharedKeyQueue {
queue: ArrayQueue::new(size),
waker: AtomicWaker::new(),
});
queues.push(queue.clone());
KeyStream {
queue,
interval: self.interval(),
}
}
pub fn list_keys(&self) -> Ref<Vec<Key>> {
self.inner.keys.borrow()
}
}
pub struct KeyStream {
queue: Rc<SharedKeyQueue>,
interval: Rc<RefCell<dyn Future<Output = ()> + Unpin>>,
}
impl Stream for KeyStream {
type Item = KeyEvent;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let mut interval = self.interval.borrow_mut();
let _ = Pin::new(&mut *interval).poll(cx);
self.queue.waker.register(cx.waker());
if let Ok(key) = self.queue.queue.pop() {
Poll::Ready(Some(key))
} else {
Poll::Pending
}
}
}