texitoi / keyberon Goto Github PK
View Code? Open in Web Editor NEWA rust crate to create a pure rust keyboard firmware.
License: MIT License
A rust crate to create a pure rust keyboard firmware.
License: MIT License
The layers design takes a lot of work to keep looking neat. Lots of tabbing to make sure it alligns nicely in a grid.
Wondering if there's a nicer way... I think there's some nice ideas here:
https://github.com/qmk/qmk_firmware/blob/master/layouts/community/ortho_5x14/yet-another-developer/keymap.c
but wrapped all into one. Half of me thinks that ideally rustfmt could do a better job with arrays ( rust-lang/rustfmt#4710 ) but half of me thinks some macro magic might be the answer...
#![deny(missing_docs)]
must be possible.
Implement something similar to Mod/Tap, i.e. some keys when hold, some others keys when tapped.
Related to #33 it would also be useful to be able to ignore certain keys when using holdtap
This is primarily useful when using holdtap on alphas, such as with homerow mods, where it helps to ignore keys adjacent to mods for reliability. Personally I would like to ignore all keys on the same half of my board so that mods are always pressed with the opposite hand.
Note: there is no built-in support for this in QMK as far as I know, so people implement this manually, such as here
The field is present in the config (to let the option to release 0.2 without implementing this feature).
We can add a tap_hold_interval corresponding to the maximal time within if you tap and hold the key, it will do the tap action, and stay holded, to allow holding the tapping behavior.
The continuation of #33
Hi, I want to build a keyboard and I want to use Rust instead of QMK. I have some Teensy LC lying around I want to use for the build.
Does this firmware support Teensy LC?
Regards and merry Christmas
Hi, I'm new to keyberon and would like to know whether it is optimized for latency (scan rate, debouncing, ...) as per https://danluu.com/keyboard-latency/ ?
I want to build a keyboard like the Ferris and I want to be able to use keyberon and QMK as firmware. As far as I know the Ferris has QMK support.
The Ferris 2.0 uses a MCP23017 IO expander. Is this supported by keyberon? The only split keyboard with keyberon support is keyseebee, but this has no QMK support as far as I know.
heapless 0.7 is nice, would you mind pushing a new release for 0.2.0?
Mostly out of curiosity I tried to run keyberon on a STM32F042F6P6 (it has enough flash and built-in USB), but the device does not enumerate and UsbDevice.poll always returns false. I constructed a minimal example:
#![no_std]
#![no_main]
extern crate panic_halt;
use cortex_m_rt::entry;
use stm32f0xx_hal as hal;
use hal::prelude::*;
use usb_device::class::UsbClass;
use usb_device::bus::UsbBusAllocator;
use hal::usb;
#[entry]
fn main() -> ! {
let mut p = hal::pac::Peripherals::take().unwrap();
static mut USB_BUS: Option<UsbBusAllocator<hal::usb::UsbBusType>> = None;
let mut rcc = p
.RCC
.configure()
.hsi48()
.enable_crs(p.CRS)
.sysclk(48.mhz())
.pclk(24.mhz())
.freeze(&mut p.FLASH);
let gpioa = p.GPIOA.split(&mut rcc);
let usb = usb::Peripheral {
usb: p.USB,
pin_dm: gpioa.pa11,
pin_dp: gpioa.pa12,
};
let usb_bus = unsafe {
USB_BUS = Some(stm32f0xx_hal::usb::UsbBusType::new(usb));
USB_BUS.as_ref().unwrap()
};
let mut usb_class = keyberon::new_class(usb_bus, ());
let mut usb_dev = keyberon::new_device(usb_bus);
loop {
if usb_dev.poll(&mut [&mut usb_class]) {
// This is never reached
usb_class.poll();
}
}
}
This code depends directly on the master branch of keyberon. Dmesg -w always shows
new full-speed USB device number 55 using xhci_hcd
Device not responding to setup address.
Device not responding to setup address.
device not accepting address 55, error -71
I am guessing I am not the only one to want to try this. Specifically I would like to try it on shift as that is the most commonly used modifier.
Maybe the easist way to do this is detect if a shift is pressed and relesed but no other key strokes have occured in the meantime. That would not require any timings. If that was detected we could wrap the next keystroke down with a shift down before and a shift up immediately after. no need I would think to wait till the pressed key had arrisen.
Thoughts?
see title
My keyboard has two function keys ("Fun" and "More Fun"). I have defined these keys as l(1)
and l(2)
. I've also configured "Fun-More Fun" and "More Fun-Fun" (both held at once) to invoke l(3)
: Layer 1 has "More Fun" set to l(3)
and layer 2 has "Fun" set to l(3)
so if both keys are held down (regardless of order) it should invoke layer 3 but that's not what's happening. Instead of invoking layer 3, pressing both "Fun" and "More Fun" invokes layer 4.
I believe this is because of how Layout.current_layer()
(https://github.com/TeXitoi/keyberon/blob/master/src/layout.rs#L396) is defined:
fn current_layer(&self) -> usize {
let mut iter = self.states.iter().filter_map(State::get_layer);
let mut layer = match iter.next() {
None => self.default_layer,
Some(l) => l,
};
for l in iter {
layer += l;
}
layer
}
Rather than looking at the layer number specified by Action::Layer()
it is merely adding the current layer number (say, 1
) to the layer defined for that key (say, 3
which would result in 4
). The test case I've come up with is this:
l(1)
and one as l(2)
.l(3)
when the other is pressed.l(4)
instead of l(3)
.I haven't figured out how to fix this yet otherwise I'd submit a PR ๐
BTW: I discovered this when I was trying to define "LAlt-Fun-Up" (LAlt configured as l(4)
in layer 1) to send a thumbs up sequence (๐) on layer 4 while having "RAlt-More Fun-Up" (LAlt configured as l(5)
in layer 2) send a top arrow (๐) on layer 5. It just wasn't working right.
Hey there,
I'm currently making a rubberducky clone (https://hak5.org/products/usb-rubber-ducky-deluxe) with some Rust firmware and was wondering how good this crate would be to send arbitrary inputs via usb (similar to native keyboard macros maybe?) or if I should manually implement it instead. Any thoughts?
Thanks :)
Hi,
i try to implement a new keyboard in keyberon is a 5x13 with an encoder and few led and a strip.
At the moment all is working in qmk.
here is what I did
https://github.com/m-lego/m65
it is practically a copy paste clean from keyberon-f4
now questions I have.
now issues i have... I did not test extensively my keyberon firmware but one issue I noticed is
fn key_codes
can panic because it does array access without checking bounds. If there is no element in the layout, just do nothing instead of panicking.
Having realised on matrix keyboards that one can press two keys down fairly easily with one finger by aiming in between them I think that opens up opportunities that should be exlored as if you pick the rigth key combos the false positive rate would be rare.
I'm raising this issue as something that I'd like to see done - I'm not expecting anyone to else to do it (but feel free if the urge takes you). I might get around to doing it soon but am juggling a few things at the moment - not least of which is trying to learn 'hands down' as a keyboard layout.
Would be cool if we could accept multiple actions
At the moment Keyberon has support for key codes in the Generic Desktop Ctrls usage page. This includes the key codes up to and including RGui
which has value 0xE7
.
There is support in the HID spec for some more controls that might be useful to add that are in the Consumer Control
page.
These could include pulled from QMK:
// 15.5 Display Controls
SNAPSHOT = 0x065,
BRIGHTNESS_UP = 0x06F, // https://www.usb.org/sites/default/files/hutrr41_0.pdf
BRIGHTNESS_DOWN = 0x070,
// 15.7 Transport Controls
TRANSPORT_RECORD = 0x0B2,
TRANSPORT_FAST_FORWARD = 0x0B3,
TRANSPORT_REWIND = 0x0B4,
TRANSPORT_NEXT_TRACK = 0x0B5,
TRANSPORT_PREV_TRACK = 0x0B6,
TRANSPORT_STOP = 0x0B7,
TRANSPORT_EJECT = 0x0B8,
TRANSPORT_RANDOM_PLAY = 0x0B9,
TRANSPORT_STOP_EJECT = 0x0CC,
TRANSPORT_PLAY_PAUSE = 0x0CD,
// 15.9.1 Audio Controls - Volume
AUDIO_MUTE = 0x0E2,
AUDIO_VOL_UP = 0x0E9,
AUDIO_VOL_DOWN = 0x0EA,
// 15.15 Application Launch Buttons
AL_CC_CONFIG = 0x183,
AL_EMAIL = 0x18A,
AL_CALCULATOR = 0x192,
AL_LOCAL_BROWSER = 0x194,
AL_LOCK = 0x19E,
AL_CONTROL_PANEL = 0x19F,
AL_ASSISTANT = 0x1CB,
AL_KEYBOARD_LAYOUT = 0x1AE,
// 15.16 Generic GUI Application Controls
AC_MINIMIZE = 0x206,
AC_SEARCH = 0x221,
AC_HOME = 0x223,
AC_BACK = 0x224,
AC_FORWARD = 0x225,
AC_STOP = 0x226,
AC_REFRESH = 0x227,
AC_BOOKMARKS = 0x22A
I'm opening this issue to start a discussion on if/how this could be implemented.
In order to implement this, the report descriptor would need to be updated to include a second report on the Consumer Control page. This would mean that report IDs would need to be introduced and key codes routed to the correct report and multiple reports would need to be sent via the usb class.
I was thinking that KbHidReport could be extended to store two reports internally and then write one or two reports as bytes depending on what keys have been pressed.
What do you think?
Hey it is possible to use the Cols as Output instead of inputs?
Keen to hear others thoughts on debouncing. I have good days and bad days for debouncing. I think switching it from 5 to 7 helps.
But I'm also curious if there's other algorythms we could try. Typically it's always that I get two of the same letter. Happy to try some stuff, just not quite sure what else to try.
First of all thanks for the code, I love my DIY keyboard with own keybindings,
my question is now is there a why so simulate the mouse.
So that I have mouse-like with arrow keys.
Or is that in plan?
I have a Drop Ctrl keyboard and want to implement the custom key codes like how it is defined in QMK here: https://github.com/qmk/qmk_firmware/blob/master/keyboards/massdrop/ctrl/keymaps/default_md/keymap.c#L3-L22.
Would it be possible to do something like this or should I adjust my approach?
I'm getting this with latest rust:
cortex_m_rt::HardFault_ (ef=0x20004e08) at C:\Users\giles.cargo\registry\src\github.com-1ecc6299db9ec823\cortex-m-rt-0.6.12\src\lib.rs:552
1.47 is fine. Will binary chop.
Hi! I'm trying to get my keyboard based on a SAM21 MCU up and running on keyberon. When declaring Pins I've run into an issue with the impl_heterogenous_array
macro as it seems to expect exactly the pin declaration as implemented in the stm32f0xx_hal. When I do a pin declaration as it's possible with the atsamd_hal:
pub struct Cols(
Pin<v2::PA02,Input<PullUp>>,
Pin<v2::PA04,Input<PullUp>>,
Pin<v2::PA10,Input<PullUp>>,
Pin<v2::PA11,Input<PullUp>>,
Pin<v2::PA09,Input<PullUp>>,
);
The macro doesn't work for that. The errors that are thrown tell me that some traits are not implemented:
error[E0277]: the trait bound atsamd_hal::gpio::v2::Pin<PA02, atsamd_hal::gpio::v2::Input<atsamd_hal::gpio::v2::PullUp>>: _embedded_hal_digital_InputPin is not satisfied
Strangely it works with the implementation of the rows which is exactly the same:
pub struct Rows(
Pin<v2::PA06,Output<PushPull>>,
Pin<v2::PA05,Output<PushPull>>,
Pin<v2::PA07,Output<PushPull>>,
Pin<v2::PA08,Output<PushPull>>,
);
impl_heterogenous_array! {
Rows,
dyn OutputPin<Error = Infallible>,
U4,
[0, 1, 2, 3]
}
This is very confusing for me and I'd appreciate some help with it. I'm really new with rust and I cannot for the life of me figure out how to change my declarations to be accepted by the macro. If there's another method to do the same that the macro does just for my use case but without the macro that would be enough already, too.
Thanks in advance
Without going all the way to Morse code style beats it'd be nice to extend the HoldTap (or have another action type) to have double/triple click style actions.
An example usecase for that is:
k(PScreen)
k(ScrollLock)
k(Menu)
l(1)
Hi, I want to make a keyboard PCB and I want to use keyberon as firmware. I have some questions to select a MCU.
What is the minimal required MCU for keyberon?
How much flash, RAM, clock frequency?
Is EEPROM useful or not supported at all?
Is a Cortex-M0 enough?
Happy new year
Implement, when typing on a key, multiple keys are sends (as if all the keys are pressed at the same time.
Sometimes it's handy to be able to control the mouse from your keyboard, for example when not at a desk
For the moment, we only support Error = Void
, which is quite limiting. Matrix::get
should return a Result
with the error. We will force that the errors on InputPin and OutputPin are of the same type.
Is there any example of using Keyberon without RTIC?
I am trying to put together a keypad using a Longan Nano board which features a RISC-V MCU.
RTIC at the moment is not supported outside of cortex
MCUs, so I cannot use it.
In particular I am trying to figure out how to replace
fn send_report(iter: impl Iterator<Item = KeyCode>, usb_class: &mut resources::usb_class<'_>) {
use rtic::Mutex;
let report: KbHidReport = iter.collect();
if usb_class.lock(|k| k.device_mut().set_keyboard_report(report.clone())) {
while let Ok(0) = usb_class.lock(|k| k.write(report.as_bytes())) {}
}
}
The idea is to provide all you need to construct your keyboard. It will provide:
Hi, I want to build a keyboard and I want to use Rust instead of QMK. I have some Teensy LC lying around I want to use for the build.
Does this firmware support Teensy LC?
Regards and merry Christmas
To be able to use home row mods it's useful to able to tweak HoldTap
. For example like IGNORE_MOD_TAP_INTERRUPT and PERMISSIVE_HOLD in QMK.
@TeXitoi Proposition:
The different behaviors:
Also, we can add a tap_hold_duration
corresponding to the maximal time within if you tap and hold the key, it will do the tap action, and stay holded, to allow holding the tapping behavior. (moved in #37)
It can be modeled as:
pub enum HoldTapConfig {
Default,
HoldOnOtherKeyPress,
PermissiveHold,
}
pub enum Action {
// ...
HoldTap {
hold: &'static Action,
tap: &'static Action,
timeout: u16,
tap_hold_interval: u16,
config: HoldTapConfig,
},
}
That's a breaking change.
My use case is to have \
and /
on a single key.
To get a \
I want to press this key without shift.
To get a /
I want to press this key while holding shift.
/
is non-shifted on the US layout and thus this would require multiple actions:
/
keyLooking at the code, I think I need a new Action
which creates a CustomEvent::Release
? I am pretty lost though, due to my unfamiliarity with Rust. Happy to dig in deeper with your guidance, though.
alt - f1
I have an alt key that also puts me in layer 2. if I then press a key to get to layer 3 as well then when I press the F1 key I get what's in layer 2 for that not what's in layer 3.
If instead I press layer 3 and then press alt (which in this case is a plain alt and not messing with layers) and then press the F1 key it all works fine. Would be great if both roads lead to the same place. Is this possible?
I am having difficulty getting my keyboard to wakeup my computer from an S3 suspend.
I am running Linux Kernel 5.10 and have a custom STM32F072 keyboard and can enter sleep with the MediaSleep
keycode, but cannot seem to wake my computer with a button press. QMK on the same keyboard does wake up my machine, so I do not believe it is a hardware issue. I also tested with the Keyseebee firmware after just changing the pins, and still was unable to wake my machine.
Has anyone else had this issue? I looked into the stm32-usbd repository for suspend
and resume
but am not sure if those are even the correct functions to call.
BTW amazing library! I love the new CustomAction functionality for entering DFU.
Implement an action that correspond to a succession of key, i.e. one keypress to write a sentence.
This isn't a bug in keyberon, but a call for help :).
I'm hacking a firmware based on keyberon and a library
called keytokey (unreleased...) that turns key-streams into usb key outputs,
and is supposed to abstract away from the keyboard firmware and allows
unit testing of arbitrary keyboard inputs. That part is mostly done, and should
support most of what QMK offers in this regard.
My issue is with the USB-Hid stuff -
I'm getting the computer to read the first report, but as soon as I want to send another one (be it empty or another key press), my firmware hangs and the computers autorepeat keeps repeating that first keypress.
Perhaps you might have run into a similar problem?
Code is at https://github.com/TyberiusPrime/stm32f103_k2k/tree/master/src
guess you,d want to look into usbout first.
Thank you so very much for getting HID working on Rust+Stm32!
What is the best way the keyberon "community" can keep track of keyboard firmware that has been put together for common keyboards?
If the designer of the keyboard supports QMK, but someone else writes a keyberon firmware for the board, it would be nice to keep track of this.
It seems like most popular keyboards running a Arm Cortex-M MCU could be running keyberon, and it would be nice to share this work with newcomers.
I see the readme starts to do this, but that could get really unwieldy.
Hi, I have a split keyboard with a WeAct Mini F4, where the switches are connected directly to the pins of the controller. It currently runs on QMK, but I'm planning on switching to keyberon. I took a brief look at the codebase, and it seems that there's currently no support for something like "DIRECT_PIN" from QMK.
I guess using a "ghost pin" (such as the A13/A14 pin used for serial debugging/flashing the MCU) would be the best bet for the firmware as it currently is? Breakout board's pinout. I use DFU for flashing, so it won't bother me to use those pins.
But that approach would not work if there are no free pins available on the controller, so in the meantime I guess I would also be interested in exploring a similar feature for keyberon. Would you be willing to entertain a PR for the same? (I currently have no clue as to how it will integrate in the existing code, but that's for later ๐ )
KiCAD schematic for one half of the keyboard (the "other" side is the same)
In case someone is looking at this issue and does not know what is DIRECT_PIN, here's a very short explanation: A switch is connected to (say) pin P1 on the MCU, with the other terminal of the switch being connected to GND. Pin P1 is set internally as "pull-up high". Then, whenever the switch is pressed, P1 gets pulled low. Its actually pretty much the same as the current matrix implementation: just that there is no "row" --> it's always GND.
The get function from matrix.rs would then become:
pub fn get<E>(&mut self) -> Result<PressedKeys<CS, RS>, E>
where
C: InputPin<Error = E>,
R: OutputPin<Error = E>,
{
let mut keys = PressedKeys::default();
// for (ri, row) in (&mut self.rows).iter_mut().enumerate() {
// row.set_low()?;
for (ci, col) in (&self.cols).iter().enumerate() {
keys.0[ri][ci] = col.is_low()?;
}
// row.set_high()?;
// }
Ok(keys)
}
The above code will obviously not work with the current implementation ;) .
Please let me know if I missed mentioning something!
The macro impl_heterogenous_map is quite ugly to use, improve that.
Hi! Great project.
Would custom bootloaders like stm32f103-keyboard-bootloader work with Keyberon? If not, which changes would be necessary?
Is it possible to create home row mods? What I mean is alt, Ctrl, GUI and shift on asdf and jkl;
I know that tap-hold is supported, but that doesn't work for home row mods. Just like in qmk you need to add some special funktions to make it work.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.