A small shell script for applying colouring rules to KLE files.
When paired with keycov
, it makes it much easier to make any insane colourway-pattern compatible with a diverse range of keyboards.
This script can also be used to create a single source of truth for colourising information.
You’ll need a working installation of python3 and its package manager pip3.
Download and unzip kle-colouriser.zip
from the latest release then open up a terminal and type the following commands.
(These assume that the archive was unzipped in ~/Downloads/kle-colouriser/
.)
cd ~/Downloads/kle-colouriser/
pip3 install -r requirements.txt
python3 kle-colouriser.py --help
This last step should print out the usage information for kle-colouriser
.
Before running, kle-colouriser
will require two things:
- A colour-map file to apply (this guide assumes
examples/colour-map.yml
) - A folderful of kle files to generate (we’ll call this
keebs/
)
To run kle-colouriser
, open a terminal and type the following (assuming that the latest release was unzipped to ~/Downloads/kle-colouriser/
.)
cd ~/Downloads/kle-colouriser/
python3 kle-colouriser.py examples/colour-map.yml examples/keebs/ colourised-keebs/
This will apply the example colour-map to the example layouts and output the results in the (new) colourised-keebs/
directory.
If running on Linux or macOS, it is possible to make the python3
command above somewhat shorter by downloading the kle-colouriser
binary from the latest release and replacing the python3 kle_colouriser.py
above with ./kle-colouriser
.
The file ./kle-colouriser
is just a zip archive of the source which can be run by python anywhere (assuming it can access its dependencies).
Colour-maps are just a list of simple condition-action rules written in the quite specific (and fairly common) markup language, yaml. Each colour-map rule specifies: its name, a colour to apply to caps, a colour to apply to legends and a set of conditions which must be satisfied in order to apply the rule. Each keycap in a KLE layout is then checked against the colour-map rules and the first with all conditions satisfied is then applied to that cap. (That is, if two rules have satisfied conditions, that which appears higher in the colour-map file is used.)
A detailed account of kle-colouriser
’s decisions can be found by increasing the verbosity level.
Passing --verbosity=1
will show the rule chosen for each key in each layout.
Passing --verbosity=2
will show the results of evaluating each condition within each rule for each key in each layout (there’s a lot of output).
The following is an example colour-map.
- name: specials
cap-colour: 'ffff00'
glyph-style: '#ff8000'
key-name:
- Esc
- Enter
- name: alphas
cap-colour: '00ff00'
glyph-style: '#ff0000;'
key-pos: x + y <= 15
key-name:
- .-.+
- '[^+/*-]'
- ''
- F[1-49][0-2]?
- name: something-else
cap-colour: '123456'
glyph-style: '123456'
key-pos: 2 * x + 3 * y >= 10
- name: mods
cap-colour: 'ff0000'
glyph-style: '00ff00'
key-name:
- .*
It is possible to make the colour of the key depend on its position in a given layout.
For this, a mathematical condition may be specified.
Note that as per the KLE standard, the value of x
increases to the right, and the value of y
downwards.
Conditions are constructed as follows, closely following Python+C syntax.
- Numbers and the variables
x
andy
are valid expressions - The negation of an expression is also an expression
- A pair of expressions can be compared by any of the following binary operations.
^^
power*
, multiplication/
, division, e.g.3 / 2 = 1.5
//
, integer division, e.g.3 // 2 = 1
%
, modulo, remainder of integer division, e.g.3 % 2 = 1
+
, addition-
, subtraction
- A pair of expressions may be compared to form a condition
<
less-than<=
, less-than-or-equal>
, greater-than>=
, greater-than-or-equal=
, equal==
, equal!=
, not equal
- A pair of conditions may be used in logical operations; this is also a condition:
!
logical negation (true
iff its input isfalse
)&
logical conjunction (true
iff both inputs aretrue
)|
logical disjunction (true
iff either input istrue
)^
exclusive or (true
iff either but not both inputs istrue
)=>
logical implication (true
iff either the left is false, or both are true)<=>
logical equivalence (true
iff both inputs have the same value)
If a conditional operator is omitted, a value of true
is returned if and only if the numerical value resolved is not equal to zero.
Note that as only binary operations are considered (exactly two inputs), multiple comparisons can have unexpected results, such as the following.
0.3 < 0.1 < 0.2
= (0.3 < 0.1) < 0.2
= False < 0.2
= 0 < 0.2
= True
Use the &
operator instead: a < b < c
should be expanded to a < b & b < c
.
It is possible for the legend text of a key to be used to constrain colour-application.
The contents of the key-name
field is either a string, or a list of strings, each of which represents a regular expression.
If the keycap legend matches any of the regular expressions specified, then the condition is true
.
Any new-line characters present in the keycap legend are replaced by dashes, for example !\n1
becomes !-1
.
It’s not essential to know regular expressions, but a few basics such as those outlined below can make things a little more streamlined. The cheatsheet and playground on regexr may be helpful.
Consider the example regular expression .*
.
This comprises of .
, which means match any one character, and *
which means repeat zero or more of the regular expression to its left.
Hence .*
just means that anything, including the empty string, is matched.
Similarly, the regex [0-9]
specifies a character class which means match any one of the characters specified inside it.
Here a range from 0
to 9
is specified, hence this will match any single digit.
In the example colour-map, this concept is used in conjunction with the ?
operator which matches either zero or one_ of the regular expression to its left.
This was used in the expression F[1-49][0-2]?
, which when applied to a 100% keyboard will match keys F1 to F4 and F9 to F12.
It is possible to apply the same rule differently depending on the layout file to which it is applied.
This is done using regular expressions in the same way as the key-name
condition.
If this is required, some diligent naming if input files may be useful.
For example, orthogonal layouts might have the word ortho
as a part of their name, which would be matched by .*ortho.*
.
Takes a set of conditions as specified in this readme.
Returns true
iff every single one of its sub-conditions are true
.
Takes a set of conditions as specified in this readme.
Returns true
iff at least one of its sub-conditions are true
.
Takes a set of conditions as specified in this readme.
Negation of the all
condition, returns true
iff at least one of its sub-conditions is false
.
Takes a set of conditions as specified in this readme.
Negation of the any
condition, returns true
iff none of its sub-conditions is true
.
Please note that given the quite organic nature of many keyboard layouts, some colour-map rules may be applicable to some but not others, and as such a human touch may occasionally be required.
For example, a 1u-wide stripe of colour at a 30° angle may work well for a 100% keyboard, but for an orthogonal one, a 45° angle may be required for the same visual effect due to aliasing (kle-colouriser
will not support anti-aliasing).
To some extent it may be possible to adapt the colour-map rules slightly e.g. by using different rules with layout-file-name
conditions to react differently to problematic layout files.
The decision of whether to perfect already-good colour-map files or to simply amend problems by hand will entirely depend on the user’s workflow. In the latter case, assuming reasonable colour-maps, the amount of work to fix these issues is likely less than that required to colourise the inputted layouts entirely manually.
This code was written by Ed Jones (Discord @kcza#4691
).