KeyBard is a companion software to the Svalboard (https://svalboard.com)
With KeyBard, you can:
This started as a pure javascript version of vial-gui, at https://get.vial.today
It is currently targeted at Svalboard users, so probably misses some features other Vial users might be accustomed to having. As with any project, we welcome PRs, and suggestions =).
Pull information from keyboard:
Both instant and queued changes.
View and modify keymap for all available layers.
Sample keyboards
Macros and Tap Dances
Combos and Key Overrides
QMK Settings (under MENU) - Change somewhat obscure QMK values.
.vil and .svl support.
Sample keyboards: For selecting your keys.
Sample layers you can apply.
Below is for anyone interested in contributing to KeyBard.
Vial and QMK overload various terms. I'm trying to keep them separate for this project.
Keymap: Physical keys to key strings.
KeyLayout: How to render the board's keys - this lays out the Svalboard clusters and thumb keys in the correct location and size.
kbinfo: The JS object containing all information I have about a given keyboard. For more information, look at pages/js/kbinfo.js
These are two separate values, defined in kbinfo.js.
BASE_KBINFO is the connected device, or the initially uploaded file if no device is connected. It is the 'static' version.
KBINFO is considered the 'current' and editable kbinfo - change keys, add macros, etc. Unless you have 'instant' on, this will differ from BASE_KBINFO.
If you want to make mass changes, then perform the changes on KBINFO, and call updateAllChanges().
On commit, BASE_KBINFO and KBINFO will be identical.
All downloads are of KBINFO. All uploads replace KBINFO. Only if 'instant' is enabled will it also immediately update BASE_KBINFO.
A 'sample board' is one that goes along the bottom half. e.g: "QWERTY", "International->AZERTY", "QMK Keys", etc.
To add a new sample board:
1) Add the board as html/kcs/(name).html (You probably want to use another board as a template.)
2) Add the container and tab to html/allboards.html
I try and keep most javascript compartmentalized. Not all .js files are such, either for convenience or because they could use a little refactoring.
I do not use a framework at present. Since better than 90% of the code revolves around keys and editing them, I feel frameworks would only slightly improve the other 10%, while making the 90% a bit more complicated to fit in.
I do try and keep most sections of the code fairly well documented.
util.js defines most of the intended globals, as well as the DOM-manipulating
functions and element creation. It also adds a major function that most other
files use: addInitializer()
.
Most of the UI code that is independent of others is wrapped in an addInitializer(). There are (at time of writing) two times initializers are called: on load, and on connect. They can optionally choose an order to be loaded in. addInitializer(type, callback, order). For more information, see util.js
addInitializer('load', () => {})
will call when page is fully loaded.
addInitializer('connected', () => {})
will call when a device is connected,
or a .kbinfo or .vil is uploaded for editing.
Majority of UI code is wrapped in either initializer.
const GLOBAL = {};
addInitializer('load', () => {
function DoSomething() {...}
const localValue = [];
GLOBAL.something = () => {
DoSomething(localValue);
}
});
For actions, I use a concept of selectors and callbacks. There is no per-element binding (Though you may choose to do that for your own elements). Instead, document.onclick() checks its target and its parents (working up the tree) until an element matching a selector is found. This lets us have hundreds of keys with only a few callbacks, depending on type of key.
ACTION.onclick('selector', callback) will call
callbackwith the element matching 'selector'. There is no need to add individual onclick callbacks to every single element that matches
selector`.
ACTION.on(name, cb(...args))
and ACTION.trigger(name, ...args)
work together. Only one callback may be registered per name.
For example - at time of writing, there is a 'bind' event, which
is called whenever a bind-able key is clicked.
All the UI stuff is in kbui/
They are fairly well encapsulated. e.g: If you
remove kbui/combo.js
from html/scripts.html
, the only thing you need to
change is updateAll
calling their update. (Only globally accessible feature
combo.js has)
kbui/sampleboards.js
is responsible for populating dynamic sample boards, such
as macro, layers, and the like.
All the raw USB code is in usbhid.js
, but in vial/
you'll find
Vial-specific behavior to communicate with the keyboard. These encapsulate in a
bit of a different way, but could use a bit of a refactor to match the rest of
the site.
This is pulled directly from QMK's settings.json. The only change I make is
to add const QMK_SETTINGS =
at the start to turn it into .js
This is generated by rebuild_keys.py
(or just run make keys
). It's a little
odd in its approach to make Vial aliases our default, but also make QMK aliases
available for use.