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
//! # Keyboard Service
//!
//! This module defines a generic service for modeling keyboard drivers. This
//! service can be implemented by drivers for specific keyboards, or by a generic
//! ["keyboard multiplexer" service](self::mux::KeyboardMuxService) type in the
//! [`mux`] submodule. The latter is useful for systems that have multiple
//! keyboards, as it allows clients which consume keyboard input to subscribe to
//! events from *all* hardware keyboard drivers, rather than a single keyboard.
//!
//! The [`key_event`] submodule defines a generic representation of keyboard
//! events, which is, admittedly, a bit overly complex. It's intended to model
//! as many different types of keyboard as possible. Not all keyboards will
//! provide all of the available keyboard event types, based on what keys
//! actually exist on the keyboard.
use uuid::Uuid;
use crate::{
comms::{
kchannel::{self, KChannel},
oneshot,
},
registry::{self, known_uuids, RegisteredDriver},
Kernel,
};
pub mod key_event;
pub mod mux;
////////////////////////////////////////////////////////////////////////////////
// Service Definition
////////////////////////////////////////////////////////////////////////////////
pub struct KeyboardService;
impl RegisteredDriver for KeyboardService {
type Request = Subscribe;
type Response = Subscribed;
type Error = KeyboardError;
type Hello = ();
type ConnectError = core::convert::Infallible;
const UUID: Uuid = known_uuids::kernel::KEYBOARD;
}
////////////////////////////////////////////////////////////////////////////////
// Message and Error Types
////////////////////////////////////////////////////////////////////////////////
pub use self::key_event::KeyEvent;
#[derive(Copy, Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Subscribe {
buffer_capacity: usize,
}
pub struct Subscribed {
rx: kchannel::KConsumer<KeyEvent>,
}
#[derive(Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum KeyboardError {
NoKeyboards,
TooManySubscriptions,
}
#[derive(Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum KeyClientError {
NoKeyboardService,
}
impl Default for Subscribe {
fn default() -> Self {
Self {
buffer_capacity: Self::DEFAULT_BUFFER_CAPACITY,
}
}
}
impl Subscribe {
pub const DEFAULT_BUFFER_CAPACITY: usize = 32;
pub fn with_buffer_capacity(self, buffer_capacity: usize) -> Self {
Self { buffer_capacity }
}
}
impl Subscribed {
pub fn new(Subscribe { buffer_capacity }: Subscribe) -> (kchannel::KProducer<KeyEvent>, Self) {
let (tx, rx) = KChannel::new(buffer_capacity).split();
(tx, Self { rx })
}
}
////////////////////////////////////////////////////////////////////////////////
// Client types
////////////////////////////////////////////////////////////////////////////////
/// A client that receives [`KeyEvent`]s from a [`KeyboardService`].
pub struct KeyClient {
rx: kchannel::KConsumer<KeyEvent>,
}
#[derive(Debug)]
pub enum FromRegistryError {
Connect(registry::ConnectError<KeyboardService>),
Service(KeyboardError),
Request(registry::OneshotRequestError),
}
impl KeyClient {
/// Obtain a `KeyClient`
///
/// If the [`KeyboardService`] hasn't been registered yet, we will retry until it
/// has been registered.
pub async fn from_registry(
kernel: &'static Kernel,
subscribe: Subscribe,
) -> Result<Self, FromRegistryError> {
let handle = kernel
.registry()
.connect::<KeyboardService>(())
.await
.map_err(FromRegistryError::Connect)?;
Self::from_handle(subscribe, handle).await
}
/// Obtain an `KeyClient`
///
/// Does NOT attempt to get an [`KeyboardService`] handle more than once.
///
/// Prefer [`KeyClient::from_registry`] unless you will not be spawning one
/// around the same time as obtaining a client.
pub async fn from_registry_no_retry(
kernel: &'static Kernel,
subscribe: Subscribe,
) -> Result<Self, FromRegistryError> {
let handle = kernel
.registry()
.try_connect::<KeyboardService>(())
.await
.map_err(FromRegistryError::Connect)?;
Self::from_handle(subscribe, handle).await
}
async fn from_handle(
subscribe: Subscribe,
mut handle: registry::KernelHandle<KeyboardService>,
) -> Result<Self, FromRegistryError> {
let reply = oneshot::Reusable::new_async().await;
let Subscribed { rx } = handle
.request_oneshot(subscribe, &reply)
.await
.map_err(FromRegistryError::Request)?
.body
.map_err(FromRegistryError::Service)?;
Ok(Self { rx })
}
/// Returns the next [`KeyEvent`] received from the [`KeyboardService`].
///
/// # Returns
///
/// - [`Ok`]`(`[`KeyEvent`]`)` when a keyboard event is received.
/// - [`Err`]`(`[`KeyClientError`]`)` if the [`KeyboardService`] is no
/// longer available.
pub async fn next(&mut self) -> Result<KeyEvent, KeyClientError> {
self.rx
.dequeue_async()
.await
.map_err(|_| KeyClientError::NoKeyboardService)
}
/// Returns the next Unicode [`char`] received from the [`KeyboardService`].
///
/// Any [`KeyEvent`]s which are not Unicode [`char`]s are skipped. This
/// method is equivalent to calling [`KeyEvent::into_char`] on the
/// [`KeyEvent`] returned by [`KeyClient::next`].
///
/// # Returns
///
/// - [`Ok`]`(`[`char`]`)` if a keyboard event is received and the keyboard
/// event corresponds to a Unicode [`char`]
/// - [`Err`]`(`[`KeyClientError`]`)` if the [`KeyboardService`] is no
/// longer available.
pub async fn next_char(&mut self) -> Result<char, KeyClientError> {
loop {
// if the key subscription stream has ended, return `None`.
let key = self.next().await?;
// if the next event is a char, return it. otherwise, keep
// waiting for the next event
if let Some(c) = key.into_char() {
return Ok(c);
}
}
}
}