Giter Site home page Giter Site logo

zmkfirmware / zmk Goto Github PK

View Code? Open in Web Editor NEW
2.5K 48.0 2.6K 22.61 MB

ZMK Firmware Repository

Home Page: https://zmk.dev/

License: MIT License

CMake 3.01% C 96.17% Shell 0.54% Dockerfile 0.01% Python 0.27% JavaScript 0.01%
zmk mechanical-keyboard zephyr bluetooth wireless hacktoberfest keyboard keyboard-firmware

zmk's Introduction

Zephyr™ Mechanical Keyboard (ZMK) Firmware

Discord Build Contributor Covenant

ZMK Firmware is an open source (MIT) keyboard firmware built on the Zephyr™ Project Real Time Operating System (RTOS). ZMK's goal is to provide a modern, wireless, and powerful firmware free of licensing issues.

Check out the website to learn more: https://zmk.dev/.

You can also come join our ZMK Discord Server.

To review features, check out the feature overview. ZMK is under active development, and new features are listed with the enhancement label in GitHub. Please feel free to add 👍 to the issue description of any requests to upvote the feature.

zmk's People

Contributors

andrewjrae avatar bcat avatar bortoz avatar brainwart avatar caksoylar avatar careyk007 avatar chenkevinh avatar chrisandreae avatar clicketysplit avatar crossr avatar davidphilipbarr avatar dependabot[bot] avatar dxmh avatar filterpaper avatar idan avatar innovaker avatar joelspadin avatar kurtis-lew avatar lesshonor avatar lownightsnack avatar megamind4089 avatar na-cly avatar nicell avatar okke-formsma avatar petejohanson avatar refil avatar theol0403 avatar tsquash avatar xudongzheng avatar zhiayang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zmk's Issues

RFC: Left/right hand support

Before we can implement split transports, we need each side of a left/right hand split keyboard to know which hand they are.

In particular, in order to send the correct column values for KSCAN events passed over the split transport, a right hand board needs to translate the column by a certain offset before sending the row/column/pressed state over the transport.

Proposal

"Left/Right" detection can be implemented as separate DT overlay files that are included for a separate build/flash cycle for each side of the keyboard. Doing so would allow the following:

  1. Differences in hardware present on each side of the split can be account for at build time, not runtime, allowing for preserving space not needed on a given side, and more importantly not trying to access devices over i2c for example, that are not present.
  2. Offsets for KSCAN events can be properly set at build time, and don't need to be set via runtime detection.

Alternative

The left/right hand is set via EEPROM, NVS, or Zephyr settings API, which matches how QMK implements this.

Keymap processes/management needs finalization

We need to settle on the process for end users to create their own keymaps, and how those are managed.

Core question: Do we put all keymaps in ZMK directory, or support external keymaps?

External Keymaps

Pros

  • External keymaps keeps ZMK core "cleaner"
  • Users do not need to fork ZMK, so they can track "upstream" ZMK without Git hoops.
  • No need for ZMK maintainers to spend time on PRs for keymap changes (!)

Cons

  • API compatibility between ZMK and external keymaps becomes more of an issue.
  • "out of tree" keymaps, are less discoverable by others.
  • Need to decide which keymaps are in tree and out of tree.
    • Is there just the default keymap in the tree?
    • Do we also have a zmk-keymaps-contrib repository for everyone to share various keymaps? We can eventually have community reviewers there, in addition to core members, etc.

This is likely closely related to keyboard definitions/support, where we may want a "incubator" for keyboard definitions "out of tree" also.

Feature: Consuming "LED status" state from HID hosts.

HID hosts will write to a USB device that supports and advertises in the report descriptor the status of the caps lock, etc. LEDs so they can enable/disable those for display on the device.

For folks that have keyboards with those lights, or who want to show that in the OLEDs, we need to add support for that to our HID layer.

Feature: Encoder support

Need to add encoder support that is nicely integrated into ZMK. There are already a couple rotary encoder drivers in Zephyr via the sensor API, but there does not appear to be one for standard "EC11" type ALPS (or clone) encoders.

Layer deactivation with held key position leads to incorrect key code release

As reported by @Nicell, the following sequence does not work as expected.

  1. Activate layer (e.g. by pressing a key position bound to &mo 1.
  2. Activate a different key position bound with a behavior (e.g. &kp ESC) on that newly activated layer.
  3. Deactivate the layer (e.g. by releasing the key position bound to &mo 1).
  4. Release the key position activated in step #2

On the last step, because layer 1 is no longer active, then the behavior that was triggered for the activation is not triggered for the deactivation. Usually, this leads to sending a "key code release" of the key bound on the lower layer instead.

The proposed fix would be something like:

  • Whenever a behavior's behavior_keymap_binding_pressed returns 0, that indicates that the behaviour has "handled" the key position activation, and processing should not continue to lower layers.
  • When this happens, we should record the layer that "handled" that press. (e.g. u8_t key_position_pressed_layer_handler[ZMK_KEYMAP_LEN]
  • When we receive a key position released event, the key map should include that recorded layer in the "stack" of layers it checks for behaviors to invoke, even if that layer isn't in the current active layer set.

Onboarding: Missing bzip Dependency

While setting up a brand new Fedora based development environment based on the included documentation, I noticed a failure in the Zephyr SDK installation step related to a missing bzip executable.

[vagrant@fedora32 ~]$ sh "zephyr-toolchain-arm-${ZSDK_VERSION}-setup.run" --quiet -- -d ~/.local/zephyr-sdk-${ZSDK_VERSION}
Installing SDK to /home/vagrant/.local/zephyr-sdk-0.11.2
Creating directory /home/vagrant/.local/zephyr-sdk-0.11.2
Success
 [|] Installing arm tools...tar (child): bzip2: Cannot exec: No such file or directory
tar (child): Error is not recoverable: exiting now
tar: Child returned status 2
tar: Error is not recoverable: exiting no

I was able to resolve the issue by installing bzip manually and after following the rest of the documentation I can successfully build firmware with the west command.

This is obviously a trivial issue but I find that a seamless dev onboarding makes for a more welcoming experience for potential contributors

MVP Requirements for "Go Live"

There's some truly required items necessary before broader marketing/publishing of the ZMK effort. Based on lots of Discord chats, we should at least get these items in place:

  • Code of Conduct
  • FAQ page
  • One fully working standalone board, and board + shield as build examples/PoC
  • Better organized toplevel README.md file
  • Documentation on use of boards, shields, and keymaps

Feature: OLED displays for BLE SC numeric comparison display

On devices that contain OLEDs, we have the opportunity to do even more security "numeric comparison" when pairing/bonding with SC to actually display the BLE pairing "numeric comparison" value for verification before prompting a user to hit enter after verifying.

Feature: combo behavior

We need to implement a combo behavior, allowing key combos to trigger additional behavior in addition to standard single key presses.

Proton-C template won't build

Latest template configuration generated with setup.sh won't get built properly by github actions.
This is the step that actually fails.

  - name: Rename zmk.uf2
    run: cp build/zephyr/zmk.uf2 SHIELD_NAME_left_BOARD_NAME.uf2

Because only an elf file is generated in the previous step.

FAQs (initial version)

Initiail version of FAQs. Required by #7.

Currently a realtime work-in-progress on Google Docs. Please contact me on Discord if you need the link to contribute.

Feature: tap dance

Keymap feature to be implemented: tap dance, allowing different behavior depending on the number of taps of a certain key.

ZMK CLI

  • A CLI tool that serves as the main point of entry for most users.
  • Probably written in Python and published as zmk.
  • Wraps up git, west and other tooling.
    • Similar to how west wraps around git, cmake, ninja, etc.
  • Encapsulates multiplatform support.
  • Provides sanity checks on parameters.
    • e.g. checks the board, shield, keymap etc. and invalid combinations of them.
  • Provides rudimentary error handling.
    • Provides useful feedback for common errors.
    • Points users to ZMK help for unexpected errors.
  • Perhaps provides an interactive prompt/menu for commands and parameters.
  • Perhaps caches parameters.
  • Perhaps wrap flashing as well?
  • Perhaps setting up dev environments?

From:

Keymaps need logical to physical mapping support

Keyboards with irregular matrixes (e.g nice60), or with locations in the matrix without keys/pads (e.g. Kyria) need to be able to have keymaps specified with logical order/location in the keymap DT file, and have that mapped to the proper physical location.

Probably needs something like a chosen node if type zmk,keymap-transform which points to a transform node that defined the map from a keymap location to a physical location.

We can have conditional code on the presence of such a chosen node, so it only happens for those keyboards.

Standardize Keys

  • Revisit/refactor current dt-bindings/zmk/keys.h
  • Include any useful values for USB or HOGP from HID Usage Tables v1.12:
    https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
  • Consider values and naming conventions found in existing KB firmware, Linux, Windows, Android, etc.
  • Decide upon any conventions for ZMK.
  • Open up consultation with the ZMK contributor community before finalizing.

Development Basic Setup on Raspberry Pi OS (Buster)

Good job on the instructions!

To confirm, my distribution should be up to date.

sudo apt update
Hit:1 http://archive.raspberrypi.org/debian buster InRelease
Get:2 http://raspbian.raspberrypi.org/raspbian buster InRelease [15.0 kB]
Fetched 15.0 kB in 1s (15.9 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
All packages are up to date.

I've encountered two issues so far.

Install Dependencies

Running

sudo apt install -y

it complained that gcc-multilib wasn't available which I bypassed by removing it from the command.

Install Zephyr Python Dependencies

Running

pip3 install --user -r zephyr/scripts/requirements.txt

it complained

Collecting cmsis-pack-manager>=0.2.7 (from pyocd>=0.24.0->-r zephyr/scripts/requirements-run-test.txt (line 9))
  Downloading https://files.pythonhosted.org/packages/c9/2b/1ac9b85b5ba535ba386467cb9a897e3f460c04f34a305e02b22f86b65367/cmsis-pack-manager-0.2.10.tar.gz (45kB)
    100% |████████████████████████████████| 51kB 2.4MB/s
    Complete output from command python setup.py egg_info:
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    c/_cffi_backend.c:15:10: fatal error: ffi.h: No such file or directory
     #include <ffi.h>
              ^~~~~~~
    compilation terminated.
 ...
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-e44et2su/cmsis-pack-manager/

so I installed libffi-dev

sudo apt-get install libffi-dev

and then reran

pip3 install --user -r zephyr/scripts/requirements.txt

it then complained

  Downloading https://files.pythonhosted.org/packages/ae/e7/d9c3a176ca4b02024debf82342dab36efadfc5776f9c8db077e8f6e71821/pycparser-2.20-py2.py3-none-any.whl (112kB)
    100% |████████████████████████████████| 112kB 1.9MB/s
Building wheels for collected packages: cmsis-pack-manager
  Running setup.py bdist_wheel for cmsis-pack-manager ... error
  Complete output from command /usr/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-install-45ylt83v/cmsis-pack-manager/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" bdist_wheel -d /tmp/pip-wheel-bglvsvky --python-tag cp37:
  running bdist_wheel
  running build
  running build_py
  creating build/lib
  creating build/lib/cmsis_pack_manager
  copying cmsis_pack_manager/__init__.py -> build/lib/cmsis_pack_manager
  copying cmsis_pack_manager/pack_manager.py -> build/lib/cmsis_pack_manager
  copying cmsis_pack_manager/_native__ffi.py -> build/lib/cmsis_pack_manager
  copying cmsis_pack_manager/_version.py -> build/lib/cmsis_pack_manager
  copying cmsis_pack_manager/_native.py -> build/lib/cmsis_pack_manager
  error: [Errno 2] No such file or directory: 'cargo': 'cargo'

  ----------------------------------------
  Failed building wheel for cmsis-pack-manager

which I thought was due to an older version of pip, according to pyocd/cmsis-pack-manager#137
So I upgraded pip:

python3 -m pip install --upgrade pip

but it didn't help the cmsis/cargo error.

I'm still looking into this. Any thoughts please?

Feature: "Shifted Keycodes", e.g. assigning `!` to a key press or mod-tap behavior.

Potential fix/idea:

  • Use upper bits of the first parameter to key_press, etc to have the enum flag of the mods included. UGH, but not sure how to avoid this if we want this to also work w/ things like mod-tap, where the other parameter is already used.
  • Add defines to keys.h that are + , e.g. something like #define BANG (NUM_1 + HELD_MODS(MOD_LSFT))
  • Updated "key code state changed" event to include mods expected with that keycode.
  • Handling in the endpoint logic to inspect the mods and handle accordingly. Need to be careful w/ handling mod state, so we don't release mods early, etc.

USB HID events sometimes dropped, missing key releases, etc.

The Zephyr USB stack doesn't implement any queue-ing of endpoint writes, so if ZMK attempts to send any HID updates while there's an active write occurring, it may fail. There is a small "retry" tried, but no real queue that is saved while waiting for the write to complete.

Implementing this will help be sure no USB updates are dropped.

Feature: Utilize status LED for different BLE actions

Most board replacements have a status LED on them that we can use to notify the user when the board is advertising, when it bonds, and when bonds are cleared. (switching profiles could be a feature in the future too). This would give much better feedback as to what's happening for troubleshooting and just in general.

Feature: Shell over BLE/USB

Zephyr has a built in feature called Shell that allows issues commands to manipulate the running system. There's an open issue zephyrproject-rtos/zephyr#26122 about enabling this over USB.

We could theoretically should be able to do this over BLE as well if we implement something like Nordic UART Service (NUS) and then a small client utility to connect to the UART and create a virtual TTY for the shell session.

Glossary / Terminology

We're continually trying to define (+remember!) terms for concepts commonly used in ZMK related discussions. Moreover, reuse of terms from existing firmware or software has led to some conceptual misunderstandings. This will only compound itself when more contributors and developers join the party.

Let's collate, coalesce and document the language we'd like to use for ZMK. Using pictures where necessary.

Please use this issue for collation and debate of each term.

Board+Shield SPI definitions are problematic

The SPI definition from the nice!nano should be removed because the pins defined there are low drive rated pins by Nordic. This means that you shouldn't run these pins above 10kHz otherwise you may have interference/degraded performance with the antenna. This is somewhat a design flaw of the nice!nano, however, I don't think it's a big deal.

While the Pro Micro pinout defines SPI, no AVR keyboard uses SPI from my understanding. Instead, bit-banging is used. In fact, it seems many keyboards don't even use those SPI pins for bit-banging (which is good news for the nice!nano). They utilize seemingly random pins because they use bit-banging.

Currently the main use of SPI will be addressable RGB lighting (until something else is found). This becomes a bit awkward because of how led_strip (see here) is defined in the DT. When using SPI, it builds off of an existing SPI definition. However, for each shield, there will most likely be a different pin for RGB. Because of this we can't define inside of the nice!nano or Proton C an SPI output. This compounds with the fact that SPI can't be put on any pin with the Proton C (stm32 architecture limitation), and the nice!nano can't have SPI on any pin without degrading the antenna.

The solution for board + shield duos using SPI peripherals is for the shield to define the SPI. Once again though, we can't assume every pro micro compatible board is capable of having SPI on the pins defined in the shield. Is it possible to make different definitions for each board? If not, shields should probably utilize the bit-banged version of led_strip.

Bit-banging will theoretically work on any board, but there's still a couple issues. First, the bit-banged version of the WS2812 driver isn't implemented for every architecture. Second is that still you can't bit-bang on low drive rated pins without degrading wireless performance. There still probably needs per-board definitions for shields to adjust the led_strip definition.

Feature: improve mod-tap behavior

I've done some investigations on what good mod-tap behavior could be.

This is a complex matter, as other firmwares like QMK often have many configuration options for the behavior of the mod-taps.

The configuration options exist to make mod-taps work for multiple scenarios, of which homerow mods are one example and things like 'escape-ctrl' on the capslock position another. ZMK needs options to configure the mod-taps, but we should try to keep this as simple as possible.

The modtap proposal for ZMK contains three possible behaviors.

  • The MOD-preferred behavior (left in pdf) works great for thing like escape-ctrl, where the user wants to have the key trigger as 'control' whenever another key is pressed shortly after. This behavior gives the user the quickest response after key presses, which makes it a good candidate as a default behavior.

  • In the middle, the balanced option. This behavior is probably good for homerow mods, as it will not active the mods on 'key rolls'. The downside of this behavior is that it needs to wait for keyup or tapping_term, making it a little less responsive than the MOD-preferred behavior.

  • The tap-preferred behavior (right in pdf) shows what the most extreme option is when taps are preferred. This behavior would only pick the 'mod' when the 'tapping_term' timer has expired. This may be a preferred option for some people using homerow or layer mods. The downside of this option is that the user ALWAYS has to wait for the timer to expire before a mod kicks in, which may be too slow for mod-tap shift and friends.

Conclusion;

  • Let's implement the mod-preferred behavior as default because it's responsive and a good bet for beginning users.
  • Let's implement the balanced option so homerow mod users can use ZMK. This is typically a more advanced crowd who can find configuration settings.
  • Let's see if we actually need the tap-preferred option before implementing it.

Feature Request: Send mouse scroll events from encoder rotations, instead of page up/down

Sending page up/down on encoder rotation only supports scrolling the actively focused content on most OSes. If we instead were to expose a HID mouse/trackpad, and send vertical scroll events, the experience may be improved for many scenarios.

  1. Add an additional HID report to the descriptor for mouse events.
  2. Add API to send mouse report updates.
  3. Hook those to a new behavior you could bind to the encoder sensor location.

Keypress on the same "input pin" as an already pressed key are not recognized

Our current interrupt code for the matrix scanner has a bug where we do not detect key presses of additional keys on the same "input pin" as an already pressed key.

Sequence:

  1. Key pressed on input pin input1.
  2. Interrupt triggers based on the "edge both" interrupt settings for the input1 GPIO pin.
  3. Matrix is read, and position pressed event is raised, propogated, etc.
  4. Second key is pressed that in a different output pin, but the same input pin of input1.
  5. Since the input1 pin is already active, no new interrupt is triggered, so new new "read the matrix" is executed.

Suggested fix: Once a key is pressed/held in the matrix, we should start a timer to start polling the matrix, to check for state changes, so that any additional key presses on other row/column pairs are detected and raised.

Once all the pressed keys are released, we then should stop the timer again, to conserve on power.

Configured device name is not displayed on macOS

Tested on both Catalina 10.15.6 and Big Sur Public Beta 5.

Device connects but is not advertised as a keyboard (icon does not indicate keyboard) and is only shown as a MAC address.

When connected, it works and behaves fine, so this appears to be a minor graphical issue.

Bluetooth Preference Pane:
image

System Information bluetooth:
image

Split BLE follow up work

There are some outstanding items in the implementation of the split BLE support that need to be work on:

  • Fix BT pairing from host once halves are paired.
  • Restore BT_SETTINGS usage to ensure pairing is saved, avoid future MiTMs.
  • Peripheral side should stop advertising after the central hub is properly connected and subscribed, and resume advertising when disconnected
  • Initial connection between central and peripheral is not always working, and is timing dependent on when each side starts. Need investigation
  • We have occasional timing issues with keypress being sent "out of order" between central and peripheral side. Need to possibly add a delay of (intervalMin + intervalMax) / 2 / 2 on the central to give peripheral key press events to have time to process.
  • Use a dynamic length data for the key press state attribute/notifications from peripheral to central hub, to reduce BLE payload size.
  • Low Priority: Add "dynamic central/peripheral role" support, instead of fixed role for left/right sides.

Feature: Leader Key

We should have a leader key behavior that allows you to add custom actions implemented for a certain sequence of keys pressed after the leader key behavior is triggered.

QMK Docs: https://docs.qmk.fm/#/feature_leader_key

I would imagine there would be something like:

&leader

In your keymap, and you would customize the leader behavior registration itself, elsewhere in the keymap, e.g.:

&leader {
  sequence_pi {
    keycodes = <P I>;
    action = <&not_sure_what_goes_here>;
  };

  sequence_foo {
    keycodes = <F O>;
    action = <&whatever_it_does>;
};

Feature: layer-tap behavior

Keymap feature that needs implementing: layer-tap.

A behavior that binds a key to momentary layer when held, or taps a key when tapped independently.

RGB Underglow improvements

Here are a list of improvements still to be made to RGB underglow:

  • Add Kconfig options for underglow state defaults
  • Add settings support for underglow state to persist between resets
  • Add Kconfig options to enable/disable each effect to save on storage space
  • Work towards split support of syncing RGB effects and animations
  • Add support for a "layer" effect that can trigger a underglow color if a specific layer is active
  • Add support for using RGB underglow behavior actions through rotary encoders
  • Convert hsb_to_rgb to use integers instead of floats to improve performance(?)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.