1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
//! This module defines input events of a terminal.
mod reactor;
use crate::coord::Vec2;
use std::sync::Mutex;
use tokio::sync::Notify;
pub(crate) use reactor::Reactor;
/// Epoch integer for our channel's versions. Hopefully, it won't overflow.
pub type Epoch = u128;
/// A supported pressed key.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Key {
/// A regular, unicode character. E.g. `Key::Char('a')` or
/// `Key::Char('ç')`.
Char(char),
/// The up arrow key.
Up,
/// The down arrow key.
Down,
/// The left arrow key.
Left,
/// The right arrow key.
Right,
/// The escape key.
Esc,
/// The enter key. Preferred over `Char('\n')`.
Enter,
/// The backspace key
Backspace,
}
/// An event fired by a key pressed by the user.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct KeyEvent {
/// Key pressed by the user.
pub main_key: Key,
/// Whether control is modifiying the key (pressed).
pub ctrl: bool,
/// Whether alt is modifiying the key (pressed).
pub alt: bool,
/// Whether shift is modifiying the key (pressed).
pub shift: bool,
}
impl KeyEvent {
/// A dummy key event, with dummy data.
fn dummy() -> Self {
Self { main_key: Key::Esc, ctrl: false, alt: false, shift: false }
}
}
/// An event fired by a resize of the screen.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ResizeEvent {
/// New dimensions of the screen. If set to `None`, then the screen was
/// resized to an invalid size, and andiskaz's event reactor is taking care
/// of this (or andiskis event reactor if you will).
pub size: Option<Vec2>,
}
impl ResizeEvent {
/// A dummy resize event, with dummy data.
fn dummy() -> Self {
Self { size: None }
}
}
/// A generic event type.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Event {
/// User resized screen.
Resize(ResizeEvent),
/// User pressed key.
Key(KeyEvent),
}
impl From<ResizeEvent> for Event {
fn from(event: ResizeEvent) -> Self {
Event::Resize(event)
}
}
impl From<KeyEvent> for Event {
fn from(event: KeyEvent) -> Self {
Event::Key(event)
}
}
/// Snapshot of an event with a given epoch.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Snapshot<E> {
/// The event of this snapshot.
event: E,
/// Epoch count of this snapshot.
epoch: Epoch,
}
/// Channel's data that needs locking.
#[derive(Debug)]
struct ChannelData {
/// Last key event's snapshot.
key: Snapshot<KeyEvent>,
/// Last resize event's snapshot.
resize: Snapshot<ResizeEvent>,
}
impl Default for ChannelData {
fn default() -> Self {
Self {
key: Snapshot { event: KeyEvent::dummy(), epoch: 0 },
resize: Snapshot { event: ResizeEvent::dummy(), epoch: 0 },
}
}
}
impl ChannelData {
/// Selects maximum last epoch.
fn epoch(&self) -> Epoch {
self.key.epoch.max(self.resize.epoch)
}
/// Reads the correct lastest event, given the epoch where the caller is.
/// Uses the adequate event, i.e. resize event has precedence.
fn read(&self, epoch: Epoch) -> Option<(Epoch, Event)> {
if self.resize.epoch > epoch {
Some((self.resize.epoch, self.resize.event.into()))
} else if self.key.epoch > epoch {
Some((self.key.epoch, self.key.event.into()))
} else {
None
}
}
/// Writes an event into the channel. Advances current epoch.
fn write(&mut self, event: Event) {
let epoch = self.epoch();
match event {
Event::Key(event) => {
self.key = Snapshot { epoch: epoch + 1, event }
},
Event::Resize(event) => {
self.resize = Snapshot { epoch: epoch + 1, event }
},
}
}
}
/// Shared channel handle (for both senders and receivers).
#[derive(Debug)]
pub(crate) struct Channel {
/// Data that needs to be lock (the effective data of the channel).
data: Mutex<ChannelData>,
/// Notification handle of the channel.
notifier: Notify,
}
impl Default for Channel {
fn default() -> Self {
Channel {
data: Mutex::new(ChannelData::default()),
notifier: Notify::new(),
}
}
}
impl Channel {
/// Notifies all parties subscribed to the channel.
pub fn notify(&self) {
self.notifier.notify_waiters()
}
/// Subscribes to changes in this channel.
pub async fn subscribe(&self) {
self.notifier.notified().await
}
/// Selects maximum last epoch.
pub fn epoch(&self) -> Epoch {
self.data.lock().unwrap().epoch()
}
/// Reads the correct lastest event, given the epoch where the caller is.
/// Uses the adequate event, i.e. resize event has precedence.
pub fn read(&self, epoch: Epoch) -> Option<(Epoch, Event)> {
self.data.lock().unwrap().read(epoch)
}
/// Writes an event into the channel. Advances current epoch.
pub fn write(&self, event: Event) {
self.data.lock().unwrap().write(event)
}
}