-
Notifications
You must be signed in to change notification settings - Fork 81
Added support for Sequences (aka macros) #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
3a83060
6e5e068
b56de4f
7df7519
d65daac
6067648
95650fd
255c4d3
18fb401
37e6b31
b7a77d3
999b9f2
ab0bfe1
0785151
60b08b9
0d89989
0660d2b
f3ad3ff
3fe71e5
43ed3e5
f93d8ec
f0e7d65
a26a3b6
4604ec7
2585845
c990d9d
d93436d
8e2dfa9
883a2d1
5e67102
16be78a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| //! Layout management. | ||
|
|
||
| use crate::action::Action; | ||
| use crate::action::{Action, SequenceEvent}; | ||
| use crate::key_code::KeyCode; | ||
| use arraydeque::ArrayDeque; | ||
| use heapless::consts::U64; | ||
|
|
@@ -32,13 +32,18 @@ pub enum Event { | |
| Press(u8, u8), | ||
| /// Release event with coordinates (i, j). | ||
| Release(u8, u8), | ||
| /// Press event with just a keycode (for sequences) | ||
| SequencePress(KeyCode), | ||
| /// Release event with just a keycode (for sequences) | ||
| SequenceRelease(KeyCode), | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can't modify this enum. It's the public contract of events entering a layout. This enum is not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are breaking changes bad for keyboard firmware - I'm build and flash it all in one go so from my side I wouldn't be affected by a breaking change? - maybe we should break now, up the semver and make it non exhaustive at the same time?
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Breaking change will say that you don't to just do cargo update to update keyberon. I don't care of making breaking changes, but it must add something to the user. But here, the problem is more that implementation details leak in the public interface.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gilescope I think TeXitoi was just making a point (in a nice, technical way) that how I implemented this particular feature sucks, haha. He's right though! I've got a much better solution that I'm currently working on that should allow us to incorporate specific delays between keystrokes instead of just one universal delay that's the same for all I'm still new to Rust and his wisdom is appreciated 😄 . I'm currently struggling with writing code (a I actually got the code working to execute simple sequences but it currently doesn't work with modifiers or anything that needs to remain held during the sequence. Hopefully not much longer now! Aside: In the process of writing this I've learned a lot about how HID keyboards work, haha. Like how you can only have a maximum of six keys down at a time--even though there's no real technical reason behind this limitation. It's just that when folks were defining the USB HID spec they didn't say how many keycodes could be sent at once so vendors (e.g. Apple and Microsoft) limited it to six simultaneous keycodes in their implementations (or at least, that's how it was explained to me). No idea what happens if you try to send more but it's in my TODO list of things to play with =)
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The "usb keyboard boot protocol" has this 6 keys (+8 modifiers) limitation. There is alternative USB descriptor, but the one used in keyberon has this limitation (that I didn't find limiting, so I didn't try the "NKRO" descriptor support). |
||
| } | ||
| impl Event { | ||
| /// Returns the coordinates (i, j) of the event. | ||
| pub fn coord(self) -> (u8, u8) { | ||
| match self { | ||
| Event::Press(i, j) => (i, j), | ||
| Event::Release(i, j) => (i, j), | ||
| _ => (0, 0), // Need a NaN version of this or something | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -63,6 +68,13 @@ impl Event { | |
| let (i, j) = f(i, j); | ||
| Event::Release(i, j) | ||
| } | ||
| // Not really sure what (if anything) this needs to be. Just returning as-is | ||
| Event::SequencePress(k) => { | ||
| Event::SequencePress(k) | ||
| } | ||
| Event::SequenceRelease(k) => { | ||
| Event::SequenceRelease(k) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -71,11 +83,13 @@ impl Event { | |
| enum State { | ||
| NormalKey { keycode: KeyCode, coord: (u8, u8) }, | ||
| LayerModifier { value: usize, coord: (u8, u8) }, | ||
| SequenceKey { keycode: KeyCode }, | ||
|
riskable marked this conversation as resolved.
Outdated
|
||
| } | ||
| impl State { | ||
| fn keycode(&self) -> Option<KeyCode> { | ||
| match self { | ||
| NormalKey { keycode, .. } => Some(*keycode), | ||
| SequenceKey { keycode } => Some(*keycode), | ||
| _ => None, | ||
| } | ||
| } | ||
|
|
@@ -90,6 +104,12 @@ impl State { | |
| _ => Some(*self), | ||
| } | ||
| } | ||
| fn seq_release(&self, k: KeyCode) -> Option<Self> { | ||
| match *self { | ||
| SequenceKey { keycode, .. } if keycode == k => None, | ||
| _ => Some(*self), | ||
| } | ||
| } | ||
| fn get_layer(&self) -> Option<usize> { | ||
| match self { | ||
| LayerModifier { value, .. } => Some(*value), | ||
|
|
@@ -201,6 +221,16 @@ impl Layout { | |
| let action = self.press_as_action((i, j), self.current_layer()); | ||
| self.do_action(action, (i, j), stacked.since); | ||
| } | ||
| SequenceRelease(k) => { | ||
| self.states = self | ||
| .states | ||
| .iter() | ||
| .filter_map(|s| s.seq_release(k)) | ||
| .collect() | ||
| } | ||
| SequencePress(k) => { | ||
| let _ = self.states.push(SequenceKey { keycode: k }); | ||
| } | ||
| } | ||
| } | ||
| /// A key event. | ||
|
|
@@ -278,6 +308,36 @@ impl Layout { | |
| self.do_action(action, coord, delay); | ||
| } | ||
| } | ||
| Sequence { delay, actions } => { | ||
| for key_event in actions { | ||
| match *key_event { | ||
| SequenceEvent::Press(keycode) => { | ||
| self.stacked.push_back(Event::SequencePress(keycode).into()); | ||
|
riskable marked this conversation as resolved.
Outdated
|
||
| } | ||
| SequenceEvent::Release(keycode) => { | ||
| self.stacked.push_back(Event::SequenceRelease(keycode).into()); | ||
| } | ||
| SequenceEvent::Tap(keycode) => { | ||
| self.stacked.push_back(Event::SequencePress(keycode).into()); | ||
| self.stacked.push_back(Event::SequenceRelease(keycode).into()); | ||
| } | ||
| SequenceEvent::ReleaseAll() => { | ||
| // Can't figure out a good way to handle iterating over self.stacked | ||
| // ...without running into borrow checker problems. | ||
| // I basically don't know what I'm doing (yet) hehe | ||
| // TODO: | ||
| // for s in self.stacked.into_iter().collect() { | ||
| // match s.event { | ||
| // Event::SequencePress(keycode) => { | ||
| // self.stacked.push_back(Event::SequenceRelease(keycode.clone()).into()); | ||
| // } | ||
| // _ => { () } | ||
| // } | ||
| // } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Layer(value) => { | ||
| let _ = self.states.push(LayerModifier { value, coord }); | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.