Via and Vial
Via provides you the ability to re-configure your keyboard using the Via app, instead of building and re-flashing your firmware. Via works by reading a JSON definition specific to your keyboard. In order for the Via app to support your keyboard, these definitions need to be submitted a repository, or sideloaded using Via’s Design tab.
Vial is an alternative, which aims to be decentralized. To support your keyboard, the JSON definitions are built into the firmware itself, and the Vial app will load the JSON data at runtime. This removes the need for JSON definitions to be uploaded to a central repository.
rumcake
provides you with the option of using Via, or Vial.
At this time, rumcake
implements:
- Via protocol version 12, which requires Via V3 definitions.
- Vial protocol version 6, which is based on Via V2.
Setup
Required Cargo features
You must enable the following rumcake
features:
via
orvial
(depending on what you want to use)storage
(optional, if you want to save changes you make in the Via/Vial app)
Required code
To set up Via and Vial support, you must add a new type to implement the ViaKeyboard
trait on.
Then, you can add via(id = <type>)
to your keyboard
macro invocation.
Certain Via features need to be configured manually as well:
- For macros, you need to implement
DYNAMIC_KEYMAP_MACRO_BUFFER_SIZE
andDYNAMIC_KEYMAP_MACRO_COUNT
- This can be done trivially with the
setup_macro_buffer
macro
- This can be done trivially with the
- If you are using some form of backlighting (
simple-backlight
,simple-backlight-matrix
orrgb-backlight-matrix
), you need to changeBACKLIGHT_TYPE
. This controls howQK_BACKLIGHT
keycodes get converted tokeyberon
actions. In other words, it controls the behaviour ofBL_
prefixed keycodes in the Via app.
For other configurable Via options, see the ViaKeyboard
trait.
use rumcake::keyboard;
#[keyboard( // somewhere in your keyboard macro invocation ... via( id = MyKeyboardVia ))]struct MyKeyboard;
impl KeyboardLayout for MyKeyboard { /* ... */}
// Via setupuse rumcake::via::{BacklightType, setup_macro_buffer, ViaKeyboard};struct MyKeyboardVia;impl ViaKeyboard for MyKeyboardVia { type Layout = MyKeyboard; // Must be a type that implements `KeyboardLayout`
// OPTIONAL, this example assumes you are using simple-backlight-matrix. const BACKLIGHT_TYPE: Option<BacklightType> = Some(BacklightType::SimpleBacklightMatrix)
// OPTIONAL, include this if you want to create macros using the Via app. setup_macro_buffer!(buffer_size: 512, macro_count: 16) // Max number of bytes that can be taken up by macros, followed by the max number of macros that can be created.}
If you are using Vial, you must also implement VialKeyboard
in addition to ViaKeyboard
.
Instead of using via
in your keyboard
macro invocation, you should use vial
.
The following code example shows how to implement the VialKeyboard
trait, and uses a build script to
implement KEYBOARD_DEFINITION
. Please follow the instructions in the Vial Definitions section.
For other configurable Vial options, see the VialKeyboard
trait
// GENERATED_KEYBOARD_DEFINITION comes from _generated.rs, which is made by the build.rs script.#[cfg(vial)]include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
#[keyboard( // somewhere in your keyboard macro invocation ... via( id = MyKeyboardVia ) vial( id = MyKeyboardVia ))]struct MyKeyboard;
// ...
// Via setupuse rumcake::via::{setup_macro_buffer, ViaKeyboard};impl ViaKeyboard for MyKeyboard { type Layout = MyKeyboard; // Must be a type that implements `KeyboardLayout`
// OPTIONAL, this example assumes you are using simple-backlight-matrix. const BACKLIGHT_TYPE: Option<BacklightType> = Some(BacklightType::SimpleBacklightMatrix)
// OPTIONAL, include this if you want to create macros using the Via app. setup_macro_buffer!(buffer_size: 512, macro_count: 16) // Max number of bytes that can be taken up by macros, followed by the max number of macros that can be created.}
use rumcake::vial::VialKeyboard;impl VialKeyboard for MyKeyboard { const VIAL_KEYBOARD_UID: [u8; 8] = [0; 8]; // Change this const VIAL_UNLOCK_COMBO: &'static [(u8, u8)] = &[(0, 1), (0, 0)]; // Matrix positions used to unlock VIAL (row, col), set it to whatever you want const KEYBOARD_DEFINITION: &'static [u8] = &GENERATED_KEYBOARD_DEFINITION;}
Compiling Vial Definitions
To compile your Vial definition into the firmware, you must minify and LZMA compress your JSON definition file, and
pass the raw bytes to KEYBOARD_DEFINITION
in the VialKeyboard
trait implementation.
The basic template shows how you can achieve this using a build script (build.rs
).
The build script does the following:
- The build script will search for and open the JSON definition file for your keyboard. Place it at
./src/definition.json
. - The build script will check for the
vial
feature flag, then minify and LZMA compress the JSON data. - The resulting bytes are written to a
GENERATED_KEYBOARD_DEFINITION
constant.
The GENERATED_KEYBOARD_DEFINITION
constant can be used in your VialKeyboard
trait implementation for KEYBOARD_DEFINITION
.
Check the code example shown previously to see how to use this constant.
Recommended Via V3 Custom UI Definitions
If you are using regular Via (non-Vial), it is recommended to use the provided Custom UI
menus below to interact with rumcake
’s extra features using Via. Feel free to choose
only the ones you need.
To add the menus you need, add the JSON directly to your "menus"
field in your keyboard definition file.
Underglow Menu
{ "name": "My Keyboard", "vendorId": "0xDEAD", "productId": "0xBEEF", // ... "menus": [ { "label": "Lighting", "content": [ { "label": "Underglow", "content": [ { "label": "Enabled", "type": "toggle", "content": [ "rumcake__via__protocol_12__ViaRGBLightValue__Enabled", 2, 5 ] }, { "showIf": "{rumcake__via__protocol_12__ViaRGBLightValue__Enabled} == 1", "label": "Brightness", "type": "range", "options": [0, 255], "content": [ "rumcake__via__protocol_12__ViaRGBLightValue__Brightness", 2, 1 ] }, { "showIf": "{rumcake__via__protocol_12__ViaRGBLightValue__Enabled} == 1", "label": "Color", "type": "color", "content": [ "rumcake__via__protocol_12__ViaRGBLightValue__Color", 2, 4 ] }, { "showIf": "{rumcake__via__protocol_12__ViaRGBLightValue__Enabled} == 1", "label": "Speed", "type": "range", "options": [0, 255], "content": [ "rumcake__via__protocol_12__ViaRGBLightValue__EffectSpeed", 2, 3 ] }, { "showIf": "{rumcake__via__protocol_12__ViaRGBLightValue__Enabled} == 1", "label": "Effect", "type": "dropdown", "options": [ "Solid", "Breathing", "Rainbow Mood", "Rainbow Swirl", "Snake", "Knight", "Christmas", "Static Gradient", "RGB Test", "Alternating", "Twinkle", "Reactive" ], "content": [ "rumcake__via__protocol_12__ViaRGBLightValue__Effect", 2, 2 ] } ] } ] } ] // ...}
Simple Backlight Menu
{ "name": "My Keyboard", "vendorId": "0xDEAD", "productId": "0xBEEF", // ... "menus": [ { "label": "Lighting", "content": [ { "label": "Backlight", "content": [ { "label": "Enabled", "type": "toggle", "content": [ "rumcake__via__protocol_12__ViaBacklightValue__Enabled", 1, 4 ] }, { "showIf": "{rumcake__via__protocol_12__ViaBacklightValue__Enabled} == 1", "label": "Brightness", "type": "range", "options": [0, 255], "content": [ "rumcake__via__protocol_12__ViaBacklightValue__Brightness", 1, 1 ] }, { "showIf": "{rumcake__via__protocol_12__ViaBacklightValue__Enabled} == 1", "label": "Speed", "type": "range", "options": [0, 255], "content": [ "rumcake__via__protocol_12__ViaBacklightValue__EffectSpeed", 1, 3 ] }, { "showIf": "{rumcake__via__protocol_12__ViaBacklightValue__Enabled} == 1", "label": "Effect", "type": "dropdown", "options": ["Solid", "Breathing", "Reactive"], "content": [ "rumcake__via__protocol_12__ViaBacklightValue__Effect", 1, 2 ] } ] } ] } ] // ...}
Simple Backlight Matrix Menu
{ "name": "My Keyboard", "vendorId": "0xDEAD", "productId": "0xBEEF", // ... "menus": [ { "label": "Lighting", "content": [ { "label": "Backlight", "content": [ { "label": "Enabled", "type": "toggle", "content": [ "rumcake__via__protocol_12__ViaLEDMatrixValue__Enabled", 5, 4 ] }, { "showIf": "{rumcake__via__protocol_12__ViaLEDMatrixValue__Enabled} == 1", "label": "Brightness", "type": "range", "options": [0, 255], "content": [ "rumcake__via__protocol_12__ViaLEDMatrixValue__Brightness", 5, 1 ] }, { "showIf": "{rumcake__via__protocol_12__ViaLEDMatrixValue__Enabled} == 1", "label": "Speed", "type": "range", "options": [0, 255], "content": [ "rumcake__via__protocol_12__ViaLEDMatrixValue__EffectSpeed", 5, 3 ] }, { "showIf": "{rumcake__via__protocol_12__ViaLEDMatrixValue__Enabled} == 1", "label": "Effect", "type": "dropdown", "options": [ "Solid", "Alphas Mods", "Gradient Up Down", "Gradient Left Right", "Breathing", "Band", "Band Pin Wheel", "Band Spiral", "Cycle Left Right", "Cycle Up Down", "Cycle Out In", "Raindrops", "Dual Beacon", "Wave Left Right", "Wave Up Down", "Reactive", "Reactive Wide", "Reactive Cross", "Reactive Nexus", "Reactive Splash" ], "content": [ "rumcake__via__protocol_12__ViaLEDMatrixValue__Effect", 5, 2 ] } ] } ] } ] // ...}
Keycode support
rumcake
does not support all the keycodes that Via/Vial shows in the app. Currently, the following keycodes are functional:
- Basic keycodes (Basic tab in Via/Vial, or those available in HID keyboard reports)
- Lighting keycodes, except for
QK_BACKLIGHT_TOGGLE_BREATHING
. RGB keycodes only work for underglow, not an RGB backlight matrix. - Momentary layers (
MO(x)
) - Default layers (
DF(x)
) - Toggle layers (
TG(x)
) - One-shot layers (
OSL(x)
) - Macro keycodes (
M0
,M1
,M2
…) - Custom keycodes (
customKeycodes
in your JSON definition) - Certain media keycodes. Support for this must be enabled manually. Check the “Media Keys” doc
- QK_OUTPUT_BLUETOOTH and QK_OUTPUT_USB
You can assume that any keycodes not listed above are not supported.
Attempts to use unsupported keycodes will not result in any changes to your layout. It may show in the Via app briefly, but reloading the app will revert the keycodes back to their previous state.
For more information on how these keycodes get converted into keyberon
actions, see rumcake/src/via/protocol_12/keycodes.rs
Limitations
For the keycodes that are supported, there are still some limitations that apply. Usually these limitations
are due to memory constraints, while still allowing for the flexibility that keyberon
’s actions provide.
It’s recommended to compile any non-basic actions directly into your firmware as opposed to assigning them through Via.
- One-shot Layer keycodes assigned through Via only works for layers 0 to 15.
- One-shot actions that are already compiled into your
keyberon
layout can still work with greater layer numbers.
- One-shot actions that are already compiled into your
- Sequence actions compiled into your
keyberon
layout will not show up in the Via app, it will show up as0xFFFF
. - For Vial, using delay events and tap/press/release events with non-basic keycodes (higher than 0x00FF) in macros will not work. Using them will abort the macro when the event is executed.
- For backlighting keycodes to work, you need to modify the
BACKLIGHT_TYPE
constant in yourViaKeyboard
implementation. This defines how the backlighting keycodes get converted. - RGB keycodes only work for underglow, not an RGB backlight matrix.
To-do List
- Tap-toggle, one shot mod keycodes (and other keycodes in the “Layers” submenu)
- QMK settings (Vial)
- Dynamic keymap tap dance, combo, key overrides (Vial)
- Vial macro support (delays and non-basic keycodes)