Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,979 changes: 920 additions & 1,059 deletions ncl/keymap-codegen.ncl

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion rp2040-rtic-smart-keyboard/examples/pico42.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ mod app {
let backend = {
use smart_keymap::init;
use smart_keymap::keymap::Keymap;
let keymap = Keymap::new(init::KEY_DEFINITIONS, init::CONTEXT);
let keymap = Keymap::new(init::KEY_REFS, init::CONTEXT, init::SYSTEM);
KeyboardBackend::new(keymap)
};

Expand Down
2 changes: 1 addition & 1 deletion rp2040-rtic-smart-keyboard/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ mod app {
let mut backend = {
use smart_keymap::init;
use smart_keymap::keymap::Keymap;
let keymap = Keymap::new(init::KEY_DEFINITIONS, init::CONTEXT);
let keymap = Keymap::new(init::KEY_REFS, init::CONTEXT, init::SYSTEM);
KeyboardBackend::new(keymap)
};

Expand Down
2 changes: 1 addition & 1 deletion smart_keymap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ pub struct KeymapHidReport {
pub custom: [u8; 6],
}

static mut KEYMAP: init::Keymap = init::Keymap::new(init::KEY_DEFINITIONS, init::CONTEXT);
static mut KEYMAP: init::Keymap = init::Keymap::new(init::KEY_REFS, init::CONTEXT, init::SYSTEM);

/// Initialize the global keymap instance.
#[allow(static_mut_refs)]
Expand Down
2 changes: 0 additions & 2 deletions src/bin/sizes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ struct StructSizes {
key_keyboardmodifiers: usize,
key_composite_context: usize,
key_composite_event: usize,
key_composite_key: usize,
key_composite_pendingkeystate: usize,
key_composite_keystate: usize,
keymap_keymap: usize,
Expand All @@ -22,7 +21,6 @@ fn main() {
key_keyboardmodifiers: mem::size_of::<key::KeyboardModifiers>(),
key_composite_context: mem::size_of::<key::composite::Context>(),
key_composite_event: mem::size_of::<key::composite::Event>(),
key_composite_key: mem::size_of::<key::composite::Key>(),
key_composite_pendingkeystate: mem::size_of::<key::composite::PendingKeyState>(),
key_composite_keystate: mem::size_of::<key::composite::KeyState>(),
keymap_keymap: mem::size_of::<smart_keymap::init::Keymap>(),
Expand Down
32 changes: 9 additions & 23 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,46 +27,32 @@ pub enum Event {
},
}

/// A struct for associating a [crate::key::Key] with a [crate::key::KeyState].
/// A struct for associating a key ref with a [crate::key::KeyState].
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PressedKey<S> {
pub struct PressedKey<R, S> {
/// The index of the pressed key in some keymap.
pub keymap_index: u16,
/// The Ref to the key data of the key state.
pub key_ref: R,
/// The pressed key state.
pub key_state: S,
}

impl<Ctx, Ev, S: crate::key::KeyState<Context = Ctx, Event = Ev>> PressedKey<S> {
/// Convenience passthrough to key_state handle_event.
pub fn handle_event(
&mut self,
context: &Ctx,
event: crate::key::Event<Ev>,
) -> crate::key::KeyEvents<Ev> {
self.key_state
.handle_event(context, self.keymap_index, event)
}

/// Convenience passthrough to key_state key_output.
pub fn key_output(&self) -> Option<key::KeyOutput> {
self.key_state.key_output()
}
}

/// State resulting from [Event].
#[derive(Debug, Clone, Copy)]
pub enum PressedInput<PK> {
pub enum PressedInput<KR, KS> {
/// Physically pressed key.
Key(PressedKey<PK>),
Key(PressedKey<KR, KS>),
/// Virtually pressed key, and its keycode.
Virtual(key::KeyOutput),
}

impl<PK> PressedInput<PK> {
impl<KR, KS> PressedInput<KR, KS> {
/// Constructor for a [PressedInput::Key].
pub fn pressed_key(key_state: PK, keymap_index: u16) -> Self {
pub fn pressed_key(keymap_index: u16, key_ref: KR, key_state: KS) -> Self {
Self::Key(PressedKey {
keymap_index,
key_ref,
key_state,
})
}
Expand Down
169 changes: 68 additions & 101 deletions src/key.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use core::fmt::Debug;
use core::marker::PhantomData;

use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -27,39 +26,10 @@ pub mod tap_hold;
/// "Composite" keys; an aggregate type used for a common context and event.
pub mod composite;

/// The maximum number of key events that are emitted [Key] or [KeyState].
/// The maximum number of key events that are emitted by [crate::key::System] implementations.
pub const MAX_KEY_EVENTS: usize = 4;

/// The maximum length of a key path.
pub const MAX_KEY_PATH_LEN: usize = 4;

/// Sequence of indices into a key map.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KeyPath(heapless::Vec<u16, MAX_KEY_PATH_LEN>);

impl KeyPath {
/// Returns the keymap index (the first item in the path).
pub fn keymap_index(&self) -> u16 {
self.0[0]
}

/// Adds an item to the KeyPath.
pub fn append_path_item(&self, item: u16) -> KeyPath {
let mut kp = self.clone();
kp.0.push(item).unwrap();
kp
}
}

impl core::ops::Deref for KeyPath {
type Target = [u16];

fn deref(&self) -> &Self::Target {
&self.0
}
}

/// Events emitted when a [Key] is pressed.
/// Events emitted when a key is pressed.
#[derive(Debug, PartialEq, Eq)]
pub struct KeyEvents<E, const M: usize = { MAX_KEY_EVENTS }>(heapless::Vec<ScheduledEvent<E>, M>);

Expand Down Expand Up @@ -129,46 +99,47 @@ impl<E: Debug, const M: usize> IntoIterator for KeyEvents<E, M> {
}
}

/// Newtype for invoking new_pressed_key on the key at the given [KeyPath].
#[derive(Debug)]
pub enum NewPressedKey {
/// Invoke new_pressed_key on the key at the given [KeyPath].
Key(KeyPath),
/// Newtype for invoking new_pressed_key on the key for the given ref.
#[derive(Debug, PartialEq)]
pub enum NewPressedKey<R> {
/// Invoke new_pressed_key on the key at the given ref.
Key(R),
/// For keys which do nothing when pressed.
NoOp,
}

impl NewPressedKey {
impl<R> NewPressedKey<R> {
/// Constructs a NewPressedKey value.
pub fn key_path(key_path: KeyPath) -> Self {
NewPressedKey::Key(key_path)
pub fn key(key_ref: R) -> Self {
NewPressedKey::Key(key_ref)
}

/// Constructs a NoOp NewPressedKey value.
pub fn no_op() -> Self {
NewPressedKey::NoOp
}

/// Maps the NewPressedKey into a new type.
pub fn map<TR>(self, f: fn(R) -> TR) -> NewPressedKey<TR> {
match self {
NewPressedKey::Key(r) => NewPressedKey::Key(f(r)),
NewPressedKey::NoOp => NewPressedKey::NoOp,
}
}
}

/// Pressed Key which may be pending, or a resolved key state.
#[derive(Debug)]
pub enum PressedKeyResult<PKS, KS> {
#[derive(Debug, PartialEq)]
pub enum PressedKeyResult<R, PKS, KS> {
/// Unresolved key state. (e.g. tap-hold or chorded keys when first pressed).
Pending(KeyPath, PKS),
Pending(PKS),
/// Resolved as a new pressed key.
NewPressedKey(NewPressedKey),
NewPressedKey(NewPressedKey<R>),
/// Resolved key state.
Resolved(KS),
}

/// Constructs key path with the given keymap index.
pub fn key_path(keymap_index: u16) -> KeyPath {
let mut vec = heapless::Vec::new();
vec.push(keymap_index).unwrap();
KeyPath(vec)
}

impl<PKS, KS> PressedKeyResult<PKS, KS> {
impl<R, PKS, KS> PressedKeyResult<R, PKS, KS> {
/// Returns the Resolved variant, or else panics.
#[cfg(feature = "std")]
pub fn unwrap_resolved(self) -> KS {
Expand All @@ -178,26 +149,32 @@ impl<PKS, KS> PressedKeyResult<PKS, KS> {
}
}

/// Adds an item to the KeyPath if the pressed key result is pending.
pub fn append_path_item(self, item: u16) -> Self {
/// Maps the PressedKeyResult into a new type.
pub fn map<TPKS, TKS>(
self,
f: fn(PKS) -> TPKS,
g: fn(KS) -> TKS,
) -> PressedKeyResult<R, TPKS, TKS> {
match self {
PressedKeyResult::Pending(key_path, pks) => {
PressedKeyResult::Pending(key_path.append_path_item(item), pks)
}
pkr => pkr,
PressedKeyResult::Pending(pks) => PressedKeyResult::Pending(f(pks)),
PressedKeyResult::NewPressedKey(npk) => PressedKeyResult::NewPressedKey(npk),
PressedKeyResult::Resolved(ks) => PressedKeyResult::Resolved(g(ks)),
}
}
}

/// The interface for `Key` behaviour.
/// The interface for key `System` behaviour.
///
/// A `Key` has an associated [Context], `Event`, and [KeyState].
/// A `System` has an associated `Ref`, [Context], `Event`, and [KeyState].
///
/// The generic `PK` is used as the type of the `PressedKey` that the `Key`
/// produces.
/// (e.g. [layered::LayeredKey]'s pressed key state passes-through to
/// the keys of its layers).
pub trait Key: Debug {
pub trait System<R>: Debug {
/// Used to identify the key definition in the keymap.
type Ref: Copy;

/// The associated [Context] is used to provide state that
/// may affect behaviour when pressing the key.
/// (e.g. the behaviour of [layered::LayeredKey] depends on which
Expand All @@ -214,38 +191,46 @@ pub trait Key: Debug {
/// Associated key state type.
type KeyState;

/// [Key::new_pressed_key] produces a pressed key value, and may
/// Produces a pressed key value, and may
/// yield some [ScheduledEvent]s.
/// (e.g. [tap_hold::Key] schedules a [tap_hold::Event::TapHoldTimeout]
/// so that holding the key resolves as a hold).
fn new_pressed_key(
&self,
keymap_index: u16,
context: &Self::Context,
key_path: KeyPath,
key_ref: Self::Ref,
) -> (
PressedKeyResult<Self::PendingKeyState, Self::KeyState>,
PressedKeyResult<R, Self::PendingKeyState, Self::KeyState>,
KeyEvents<Self::Event>,
);

/// Update the given pending key state with the given impl.
fn handle_event(
fn update_pending_state(
&self,
pending_state: &mut Self::PendingKeyState,
keymap_index: u16,
context: &Self::Context,
key_path: KeyPath,
key_ref: Self::Ref,
event: Event<Self::Event>,
) -> (Option<NewPressedKey>, KeyEvents<Self::Event>);
) -> (Option<NewPressedKey<R>>, KeyEvents<Self::Event>);

/// Return a reference to the key for the given path.
fn lookup(
/// Used to update the [KeyState]'s state, and possibly yield event(s).
fn update_state(
&self,
path: &[u16],
) -> &dyn Key<
Context = Self::Context,
Event = Self::Event,
PendingKeyState = Self::PendingKeyState,
KeyState = Self::KeyState,
>;
_key_state: &mut Self::KeyState,
_ref: &Self::Ref,
_context: &Self::Context,
_keymap_index: u16,
_event: Event<Self::Event>,
) -> KeyEvents<Self::Event> {
KeyEvents::no_events()
}

/// Output for the pressed key state.
fn key_output(&self, _ref: &Self::Ref, _key_state: &Self::KeyState) -> Option<KeyOutput> {
None
}
}

/// Used to provide state that may affect behaviour when pressing the key.
Expand Down Expand Up @@ -528,25 +513,7 @@ pub trait KeyState: Debug {

/// A NoOp key state, for keys which do nothing when pressed.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NoOpKeyState<Ctx, Ev>(PhantomData<(Ctx, Ev)>);

impl<Ctx, Ev> NoOpKeyState<Ctx, Ev> {
/// Constructs a NoOpKeyState value.
pub const fn new() -> Self {
NoOpKeyState(PhantomData)
}
}

impl<Ctx: Debug, Ev: Copy + Debug> KeyState for NoOpKeyState<Ctx, Ev> {
type Context = Ctx;
type Event = Ev;
}

impl<Ctx, Ev> Default for NoOpKeyState<Ctx, Ev> {
fn default() -> Self {
Self::new()
}
}
pub struct NoOpKeyState;

/// Errors for [TryFrom] implementations.
#[allow(unused)]
Expand All @@ -560,27 +527,27 @@ pub enum EventError {
/// Convenience alias for a [Result] with an [EventError].
type EventResult<T> = Result<T, EventError>;

/// Events which are either input, or for a particular [Key::Event].
/// Events which are either input, or for a particular [System::Event].
///
/// It's useful for [Key] implementations to use [Event] with [Key::Event],
/// and map [Key::Event] to and partially from [composite::Event].
/// It's useful for key implementations to use [Event] with [System::Event],
/// and map [System::Event] to and partially from [composite::Event].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Event<T> {
/// Keymap input events, such as physical key presses.
Input(input::Event),
/// [Key] implementation specific events.
/// Key implementation specific events.
Key {
/// The keymap index the event was generated from.
keymap_index: u16,
/// A [Key::Event] event.
/// A [System::Event] event.
key_event: T,
},
/// Invoke a keymap callback
Keymap(crate::keymap::KeymapEvent),
}

impl<T: Copy> Event<T> {
/// Constructs an [Event] from an [Key::Event].
/// Constructs an [Event] from an [System::Event].
pub fn key_event(keymap_index: u16, key_event: T) -> Self {
Event::Key {
keymap_index,
Expand Down
Loading