kanata-keyberon 0.17.0

Pure Rust keyboard firmware. Fork intended for use with kanata.
Documentation
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
//! The different actions that can be executed via any given key.

use crate::key_code::KeyCode;
use crate::layout::{QueuedIter, WaitingAction};
use core::fmt::Debug;

/// The different types of actions we support for key sequences/macros
#[non_exhaustive]
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum SequenceEvent<'a, T: 'a> {
    /// No operation action: just do nothing (a placeholder).
    NoOp,
    /// A keypress/keydown
    Press(KeyCode),
    /// Key release/keyup
    Release(KeyCode),
    /// A shortcut for `Press(KeyCode), Release(KeyCode)`
    Tap(KeyCode),
    /// For sequences that need to wait a bit before continuing
    Delay {
        /// How long (in ticks) this Delay will last
        duration: u32, // NOTE: This isn't a u16 because that's only max ~65 seconds (assuming 1000 ticks/sec)
    },
    /// A marker that indicates there's more of the macro than would fit
    /// in the 'sequenced' ArrayDeque
    Continue {
        /// The current chunk
        index: usize,
        /// The full list of Sequence Events (that aren't Continue())
        events: &'a [SequenceEvent<'a, T>],
    },
    /// Custom event in sequence.
    Custom(&'a T),
    /// Cancels the running sequence and can be used to mark the end of a sequence
    /// instead of using a number of Release() events
    Complete,
}

impl<'a, T> Debug for SequenceEvent<'a, T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::NoOp => write!(f, "NoOp"),
            Self::Press(arg0) => f.debug_tuple("Press").field(arg0).finish(),
            Self::Release(arg0) => f.debug_tuple("Release").field(arg0).finish(),
            Self::Tap(arg0) => f.debug_tuple("Tap").field(arg0).finish(),
            Self::Delay { duration } => {
                f.debug_struct("Delay").field("duration", duration).finish()
            }
            Self::Continue { index, events } => f
                .debug_struct("Continue")
                .field("index", index)
                .field("events", events)
                .finish(),
            Self::Custom(_) => write!(f, "Custom"),
            Self::Complete => write!(f, "Complete"),
        }
    }
}

/// Behavior configuration of HoldTap.
#[non_exhaustive]
#[derive(Clone, Copy)]
pub enum HoldTapConfig<'a> {
    /// Only the timeout will determine between hold and tap action.
    ///
    /// This is a sane default.
    Default,
    /// If there is a key press, the hold action is activated.
    ///
    /// This behavior is interesting for a key which the tap action is
    /// not used in the flow of typing, like escape for example. If
    /// you are annoyed by accidental tap, you can try this behavior.
    HoldOnOtherKeyPress,
    /// If there is a press and release of another key, the hold
    /// action is activated.
    ///
    /// This behavior is interesting for fast typist: the different
    /// between hold and tap would more be based on the sequence of
    /// events than on timing. Be aware that doing the good succession
    /// of key might require some training.
    PermissiveHold,
    /// A custom configuration. Allows the behavior to be controlled by a caller
    /// supplied handler function.
    ///
    /// The input to the custom handler will be an iterator that returns
    /// [Stacked] [Events](Event). The order of the events matches the order the
    /// corresponding key was pressed/released, i.e. the first event is the
    /// event first received after the HoldTap action key is pressed.
    ///
    /// The return value should be the intended action that should be used. A
    /// [Some] value will cause one of: [WaitingAction::Tap] for the configured
    /// tap action, [WaitingAction::Hold] for the hold action, and
    /// [WaitingAction::NoOp] to drop handling of the key press. A [None]
    /// value will cause a fallback to the timeout-based approach. If the
    /// timeout is not triggered, the next tick will call the custom handler
    /// again.
    Custom(&'a (dyn Fn(QueuedIter) -> Option<WaitingAction> + Send + Sync)),
}

impl<'a> Debug for HoldTapConfig<'a> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            HoldTapConfig::Default => f.write_str("Default"),
            HoldTapConfig::HoldOnOtherKeyPress => f.write_str("HoldOnOtherKeyPress"),
            HoldTapConfig::PermissiveHold => f.write_str("PermissiveHold"),
            HoldTapConfig::Custom(_) => f.write_str("Custom"),
        }
    }
}

impl<'a> PartialEq for HoldTapConfig<'a> {
    fn eq(&self, other: &Self) -> bool {
        #[allow(clippy::match_like_matches_macro)]
        match (self, other) {
            (HoldTapConfig::Default, HoldTapConfig::Default)
            | (HoldTapConfig::HoldOnOtherKeyPress, HoldTapConfig::HoldOnOtherKeyPress)
            | (HoldTapConfig::PermissiveHold, HoldTapConfig::PermissiveHold) => true,
            _ => false,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// A state that that can be released from the active states via the ReleaseState action.
pub enum ReleasableState {
    /// Release an active keycode
    KeyCode(KeyCode),
    /// Release an active layer
    Layer(usize),
}

/// Perform different actions on key hold/tap.
///
/// If the key is held more than `timeout` ticks (usually
/// milliseconds), performs the `hold` action, else performs the
/// `tap` action.  Mostly used with a modifier for the hold action
/// and a normal key on the tap action. Any action can be
/// performed, but using a `HoldTap` in a `HoldTap` is not
/// specified (but guaranteed to not crash).
///
/// Different behaviors can be configured using the config field,
/// but whatever the configuration is, if the key is pressed more
/// than `timeout`, the hold action is activated (if no other
/// action was determined before).
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct HoldTapAction<'a, T>
where
    T: 'a,
{
    /// The duration, in ticks (usually milliseconds) giving the
    /// difference between a hold and a tap.
    pub timeout: u16,
    /// The hold action.
    pub hold: Action<'a, T>,
    /// The tap action.
    pub tap: Action<'a, T>,
    /// The timeout action
    pub timeout_action: Action<'a, T>,
    /// Behavior configuration.
    pub config: HoldTapConfig<'a>,
    /// Configuration of the tap and hold holds the tap action.
    ///
    /// If you press and release the key in such a way that the tap
    /// action is performed, and then press it again in less than
    /// `tap_hold_interval` ticks, the tap action will
    /// be held. This allows the tap action to be held by
    /// pressing, releasing and holding the key, allowing the computer
    /// to auto repeat the tap behavior. The timeout starts on the
    /// first press of the key, NOT on the release.
    ///
    /// Pressing a different key in between will not result in the
    /// behaviour described above; the HoldTap key must be pressed twice
    /// in a row.
    ///
    /// To deactivate the functionality, set this to 0.
    pub tap_hold_interval: u16,
}

/// Define one shot key behaviour.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct OneShot<'a, T = core::convert::Infallible>
where
    T: 'a,
{
    /// Action to activate until timeout expires or exactly one non-one-shot key is activated.
    pub action: &'a Action<'a, T>,
    /// Timeout after which one shot will expire. Note: timeout will be overwritten if another
    /// one shot key is pressed.
    pub timeout: u16,
    /// Configuration of one shot end behaviour. Note: this will be overwritten if another one shot
    /// key is pressed. Consider keeping this consistent between all your one shot keys to prevent
    /// surprising behaviour.
    pub end_config: OneShotEndConfig,
}

/// Determine the ending behaviour of the one shot key.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum OneShotEndConfig {
    /// End one shot activation on first non-one-shot key press.
    EndOnFirstPress,
    /// End one shot activation on first non-one-shot key press or a repress of an already-pressed
    /// one-shot key.
    EndOnFirstPressOrRepress,
    /// End one shot activation on first non-one-shot key release.
    EndOnFirstRelease,
    /// End one shot activation on first non-one-shot key release or a repress of an already-pressed
    /// one-shot key.
    EndOnFirstReleaseOrRepress,
}

/// Defines the maximum number of one shot keys that can be combined.
pub const ONE_SHOT_MAX_ACTIVE: usize = 16;

/// Define tap dance behaviour.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TapDance<'a, T = core::convert::Infallible>
where
    T: 'a,
{
    /// List of actions that activate based on number of taps. Only one of the actions will
    /// activate. Tapping the tap-dance key once will activate the action in index 0, three
    /// times will activate the action in index 2.
    pub actions: &'a [&'a Action<'a, T>],
    /// Timeout after which a tap will expire and become an action. A new tap for the same
    /// tap-dance key will reset this timeout.
    pub timeout: u16,
    /// Determine behaviour of tap dance. Eager evaluation will activate every action in the
    /// sequence as keys are pressed. Lazy will activate only a single action, decided by the
    /// number of taps in the sequence.
    pub config: TapDanceConfig,
}

/// Determines the behaviour for a `TapDance`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TapDanceConfig {
    Lazy,
    Eager,
}

/// A group of chords (actions mapped to a combination of multiple physical keys pressed together).
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ChordsGroup<'a, T = core::convert::Infallible>
where
    T: 'a,
{
    /// List of key coordinates participating in this chord group, each with the corresponding [ChordKeys] they map to.
    pub coords: &'a [((u8, u16), ChordKeys)],
    /// Map of chords to actions they execute.
    pub chords: &'a [(ChordKeys, &'a Action<'a, T>)],
    /// Timeout after which a chord will expire and either trigger its action or be discarded if there is no corresponding action.
    /// A chord may trigger its action even before this timeout expires, if a chord key is released, a non-chord key is pressed or the pressed chord is already uniquely identifyable.
    pub timeout: u16,
}

impl<'a, T> ChordsGroup<'a, T> {
    /// Gets the chord keys corresponding to the given key coordinates.
    pub fn get_keys(&self, coord: (u8, u16)) -> Option<ChordKeys> {
        self.coords.iter().find(|c| c.0 == coord).map(|c| c.1)
    }

    /// Gets the chord action assigned to the given chord keys.
    pub fn get_chord(&self, keys: ChordKeys) -> Option<&'a Action<'a, T>> {
        self.chords
            .iter()
            .find(|(chord_keys, _)| *chord_keys == keys)
            .map(|(_, action)| *action)
    }

    /// Gets the chord action assigned to the given chord keys if they are already unambigous (i.e. there is no key that could still be pressed that would result in a different chord).
    pub fn get_chord_if_unambiguous(&self, keys: ChordKeys) -> Option<&'a Action<'a, T>> {
        self.chords
            .iter()
            .try_fold(None, |res, &(chord_keys, action)| {
                if chord_keys == keys {
                    Ok(Some(action))
                } else if chord_keys | keys == chord_keys {
                    // The given keys are a subset of this chord but not an exact match
                    // -> ambiguity
                    Err(())
                } else {
                    Ok(res)
                }
            })
            .unwrap_or_default()
    }
}

/// A set of virtual keys (represented as a bit mask) pressed together.
/// The keys do not directly correspond to physical keys. They are unique to a given [ChordGroup] and their mapping from physical keys is definied in [ChordGroup.coords].
/// As such, each chord group can effectively have at most 32 different keys (though multiple physical keys may be mapped to the same virtual key).
pub type ChordKeys = u32;

/// Defines the maximum number of (virtual) keys that can be used in a single chords group.
pub const MAX_CHORD_KEYS: usize = ChordKeys::BITS as usize;

/// An action that can do one of two actions. The `left` action is the default. The `right` action
/// will trigger if any of the key codes in `right_triggers` are active in the current layout
/// state.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ForkConfig<'a, T> {
    pub left: Action<'a, T>,
    pub right: Action<'a, T>,
    pub right_triggers: &'a [KeyCode],
}

/// The different actions that can be done.
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Action<'a, T = core::convert::Infallible>
where
    T: 'a,
{
    /// No operation action: just do nothing.
    NoOp,
    /// Transparent, i.e. get the action from the default layer. On
    /// the default layer, it is equivalent to `NoOp`.
    Trans,
    /// A key code, i.e. a classic key.
    KeyCode(KeyCode),
    /// Multiple key codes sent at the same time, as if these keys
    /// were pressed at the same time. Useful to send a shifted key,
    /// or complex shortcuts like Ctrl+Alt+Del in a single key press.
    MultipleKeyCodes(&'a &'a [KeyCode]),
    /// Multiple actions sent at the same time.
    MultipleActions(&'a &'a [Action<'a, T>]),
    /// While pressed, change the current layer. That's the classic
    /// Fn key. If several layer actions are hold at the same time,
    /// the last pressed defines the current layer.
    Layer(usize),
    /// Change the default layer.
    DefaultLayer(usize),

    /// A sequence of SequenceEvents
    Sequence {
        /// An array of SequenceEvents that will be triggered (in order)
        events: &'a &'a [SequenceEvent<'a, T>],
    },
    /// A sequence of SequenceEvents, which will be repeated so long as the key is held.
    RepeatableSequence {
        /// An array of SequenceEvents that will be triggered (in order)
        events: &'a &'a [SequenceEvent<'a, T>],
    },
    /// Cancels any running sequences
    CancelSequences,
    /// Action to release either a keycode state or a layer state.
    ReleaseState(ReleasableState),

    /// Perform different actions on key hold/tap (see [`HoldTapAction`]).
    HoldTap(&'a HoldTapAction<'a, T>),
    /// Custom action.
    ///
    /// Define a user defined action. This enum can be anything you
    /// want, as long as it has the `'a` lifetime. It can be used
    /// to drive any non keyboard related actions that you might
    /// manage with key events.
    Custom(T),
    /// One shot key. Also known as "sticky key". See `struct OneShot` for configuration info.
    /// Activates `action` until a single other key that is not also a one shot key is used. For
    /// example, a one shot key can be used to activate shift for exactly one keypress or switch to
    /// another layer for exactly one keypress. Holding a one shot key will be treated as a normal
    /// held keypress.
    ///
    /// If you use one shot outside of its intended use cases (modifier key action or layer
    /// action) then you will likely have undesired behaviour. E.g. one shot with the space
    /// key will hold space until either another key is pressed or the timeout occurs, which will
    /// probably send many undesired space characters to your active application.
    OneShot(&'a OneShot<'a, T>),
    /// Tap-dance key. When tapping the key N times in quck succession, activates the N'th action
    /// in `actions`. The action will activate in the following conditions:
    ///
    /// - a different key is pressed
    /// - `timeout` ticks elapse since the last tap of the same tap-dance key
    /// - the number of taps is equal to the length of `actions`.
    TapDance(&'a TapDance<'a, T>),
    /// Chord key. Enters chording mode where multiple keys may be pressed together to active
    /// different actions depending on the specific combination ("chord") pressed.
    /// See `struct ChordGroup` for configuration info.
    ///
    /// Keys participating in chording mode are listed in `coords`.
    /// Chording mode ends when a non-participating key is pressed, a participating key is released,
    /// the timeout expires, or when the pressed chord uniquely identifies an action (i.e. there are
    /// no more keys you could press to change the result).
    Chords(&'a ChordsGroup<'a, T>),
    /// Repeat the previous action.
    Repeat,
    /// Fork action that can activate one of two potential actions depending on what keys are
    /// currently active.
    Fork(&'a ForkConfig<'a, T>),
}

impl<'a, T> Action<'a, T> {
    /// Gets the layer number if the action is the `Layer` action.
    pub fn layer(self) -> Option<usize> {
        match self {
            Action::Layer(l) => Some(l),
            _ => None,
        }
    }
    /// Returns an iterator on the `KeyCode` corresponding to the action.
    pub fn key_codes(&self) -> impl Iterator<Item = KeyCode> + '_ {
        match self {
            Action::KeyCode(kc) => core::slice::from_ref(kc).iter().cloned(),
            Action::MultipleKeyCodes(kcs) => kcs.iter().cloned(),
            _ => [].iter().cloned(),
        }
    }
}

/// A shortcut to create a `Action::KeyCode`, useful to create compact
/// layout.
pub const fn k<T>(kc: KeyCode) -> Action<'static, T> {
    Action::KeyCode(kc)
}

/// A shortcut to create a `Action::Layer`, useful to create compact
/// layout.
pub const fn l<T>(layer: usize) -> Action<'static, T> {
    Action::Layer(layer)
}

/// A shortcut to create a `Action::DefaultLayer`, useful to create compact
/// layout.
pub const fn d<T>(layer: usize) -> Action<'static, T> {
    Action::DefaultLayer(layer)
}