[Keyboard] add keymap beautifier for Ergodox EZ (#4393)
* add beautifier * add example * Update keyboards/ergodox_ez/util/keymap_beautifier.py Co-Authored-By: tsankuanglee <1425438+tsankuanglee@users.noreply.github.com> * Update keyboards/ergodox_ez/util/keymap_beautifier.py Co-Authored-By: tsankuanglee <1425438+tsankuanglee@users.noreply.github.com> * works for regular layout * all planned features implemented * add justification switch * docker support * doc and starting script * clean up the container after done
This commit is contained in:
parent
dcb2d63302
commit
8b832c494c
0
keyboards/ergodox_ez/util/compile_keymap.py
Normal file → Executable file
0
keyboards/ergodox_ez/util/compile_keymap.py
Normal file → Executable file
8
keyboards/ergodox_ez/util/keymap_beautifier/Dockerfile
Normal file
8
keyboards/ergodox_ez/util/keymap_beautifier/Dockerfile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
FROM python:3.7.4-alpine3.10
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
COPY requirements.txt ./
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
COPY ./KeymapBeautifier.py ./KeymapBeautifier.py
|
||||||
|
|
||||||
|
CMD [ "python", "./KeymapBeautifier.py", "-h" ]
|
399
keyboards/ergodox_ez/util/keymap_beautifier/KeymapBeautifier.py
Executable file
399
keyboards/ergodox_ez/util/keymap_beautifier/KeymapBeautifier.py
Executable file
@ -0,0 +1,399 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import pycparser
|
||||||
|
import re
|
||||||
|
|
||||||
|
class KeymapBeautifier:
|
||||||
|
justify_toward_center = False
|
||||||
|
filename_in = None
|
||||||
|
filename_out = None
|
||||||
|
output_layout = None
|
||||||
|
output = None
|
||||||
|
|
||||||
|
column_max_widths = {}
|
||||||
|
|
||||||
|
KEY_ALIASES = {
|
||||||
|
"KC_TRANSPARENT": "_______",
|
||||||
|
"KC_TRNS": "_______",
|
||||||
|
"KC_NO": "XXXXXXX",
|
||||||
|
}
|
||||||
|
KEYMAP_START = 'const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {\n'
|
||||||
|
KEYMAP_END = '};\n'
|
||||||
|
KEYMAP_START_REPLACEMENT = "const int keymaps[]={\n"
|
||||||
|
KEY_CHART = """
|
||||||
|
/*
|
||||||
|
* ,--------------------------------------------------. ,--------------------------------------------------.
|
||||||
|
* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
|
||||||
|
* |--------+------+------+------+------+------+------| |------+------+------+------+------+------+--------|
|
||||||
|
* | 7 | 8 | 9 | 10 | 11 | 12 | 13 | | 45 | 46 | 47 | 48 | 49 | 50 | 51 |
|
||||||
|
* |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
|
||||||
|
* | 14 | 15 | 16 | 17 | 18 | 19 |------| |------| 52 | 53 | 54 | 55 | 56 | 57 |
|
||||||
|
* |--------+------+------+------+------+------| 26 | | 58 |------+------+------+------+------+--------|
|
||||||
|
* | 20 | 21 | 22 | 23 | 24 | 25 | | | | 59 | 60 | 61 | 62 | 63 | 64 |
|
||||||
|
* `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
|
||||||
|
* | 27 | 28 | 29 | 30 | 31 | | 65 | 66 | 67 | 68 | 69 |
|
||||||
|
* `----------------------------------' `----------------------------------'
|
||||||
|
* ,-------------. ,-------------.
|
||||||
|
* | 32 | 33 | | 70 | 71 |
|
||||||
|
* ,------+------+------| |------+------+------.
|
||||||
|
* | | | 34 | | 72 | | |
|
||||||
|
* | 35 | 36 |------| |------| 74 | 75 |
|
||||||
|
* | | | 37 | | 73 | | |
|
||||||
|
* `--------------------' `--------------------'
|
||||||
|
*/
|
||||||
|
"""
|
||||||
|
KEY_COORDINATES = {
|
||||||
|
'LAYOUT_ergodox': [
|
||||||
|
# left hand
|
||||||
|
(0,0), (0,1), (0,2), (0,3), (0,4), (0,5), (0,6),
|
||||||
|
(1,0), (1,1), (1,2), (1,3), (1,4), (1,5), (1,6),
|
||||||
|
(2,0), (2,1), (2,2), (2,3), (2,4), (2,5),
|
||||||
|
(3,0), (3,1), (3,2), (3,3), (3,4), (3,5), (3,6),
|
||||||
|
(4,0), (4,1), (4,2), (4,3), (4,4),
|
||||||
|
# left thumb
|
||||||
|
(5,5), (5,6),
|
||||||
|
(6,6),
|
||||||
|
(7,4), (7,5), (7,6),
|
||||||
|
# right hand
|
||||||
|
(8,0), (8,1), (8,2), (8,3), (8,4), (8,5), (8,6),
|
||||||
|
(9,0), (9,1), (9,2), (9,3), (9,4), (9,5), (9,6),
|
||||||
|
(10,1), (10,2), (10,3), (10,4), (10,5), (10,6),
|
||||||
|
(11,0), (11,1), (11,2), (11,3), (11,4), (11,5), (11,6),
|
||||||
|
(12,2), (12,3), (12,4), (12,5), (12,6),
|
||||||
|
# right thumb
|
||||||
|
(13,0), (13,1),
|
||||||
|
(14,0),
|
||||||
|
(15,0), (15,1), (15,2)
|
||||||
|
],
|
||||||
|
'LAYOUT_ergodox_pretty': [
|
||||||
|
# left hand and right hand
|
||||||
|
(0,0), (0,1), (0,2), (0,3), (0,4), (0,5), (0,6), (0,7), (0,8), (0,9), (0,10), (0,11), (0,12), (0,13),
|
||||||
|
(1,0), (1,1), (1,2), (1,3), (1,4), (1,5), (1,6), (1,7), (1,8), (1,9), (1,10), (1,11), (1,12), (1,13),
|
||||||
|
(2,0), (2,1), (2,2), (2,3), (2,4), (2,5), (2,8), (2,9), (2,10), (2,11), (2,12), (2,13),
|
||||||
|
(3,0), (3,1), (3,2), (3,3), (3,4), (3,5), (3,6), (3,7), (3,8), (3,9), (3,10), (3,11), (3,12), (3,13),
|
||||||
|
(4,0), (4,1), (4,2), (4,3), (4,4), (4,9), (4,10), (4,11), (4,12), (4,13),
|
||||||
|
|
||||||
|
# left thumb and right thumb
|
||||||
|
(5,5), (5,6), (5,7), (5,8),
|
||||||
|
(6,6), (6,7),
|
||||||
|
(7,4), (7,5), (7,6), (7,7), (7,8), (7,9)
|
||||||
|
],
|
||||||
|
}
|
||||||
|
current_converted_KEY_COORDINATES = []
|
||||||
|
|
||||||
|
# each column is aligned within each group (tuples of row indexes are inclusive)
|
||||||
|
KEY_ROW_GROUPS = {
|
||||||
|
'LAYOUT_ergodox': [(0,4),(5,7),(8,12),(13,15)],
|
||||||
|
'LAYOUT_ergodox_pretty': [(0,7)],
|
||||||
|
#'LAYOUT_ergodox_pretty': [(0,5),(6,7)],
|
||||||
|
#'LAYOUT_ergodox_pretty': [(0,3),(4,4),(5,7)],
|
||||||
|
#'LAYOUT_ergodox_pretty': [(0,4),(5,7)],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
INDEX_CONVERSTION_LAYOUT_ergodox_pretty_to_LAYOUT_ergodox = [
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 38,39,40,41,42,43,44,
|
||||||
|
7, 8, 9,10,11,12,13, 45,46,47,48,49,50,51,
|
||||||
|
14,15,16,17,18,19, 52,53,54,55,56,57,
|
||||||
|
20,21,22,23,24,25,26, 58,59,60,61,62,63,64,
|
||||||
|
27,28,29,30,31, 65,66,67,68,69,
|
||||||
|
32,33, 70,71,
|
||||||
|
34, 72,
|
||||||
|
35,36,37, 73,74,75,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def index_conversion_map_reversed(self, conversion_map):
|
||||||
|
return [conversion_map.index(i) for i in range(len(conversion_map))]
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, source_code = "", output_layout="LAYOUT_ergodox", justify_toward_center = False):
|
||||||
|
self.output_layout = output_layout
|
||||||
|
self.justify_toward_center = justify_toward_center
|
||||||
|
# determine the conversion map
|
||||||
|
#if input_layout == self.output_layout:
|
||||||
|
# conversion_map = [i for i in range(len(self.INDEX_CONVERSTION_LAYOUT_ergodox_pretty_to_LAYOUT_ergodox))]
|
||||||
|
#conversion_map = self.INDEX_CONVERSTION_LAYOUT_ergodox_pretty_to_LAYOUT_ergodox
|
||||||
|
if self.output_layout == "LAYOUT_ergodox_pretty":
|
||||||
|
index_conversion_map = self.index_conversion_map_reversed(self.INDEX_CONVERSTION_LAYOUT_ergodox_pretty_to_LAYOUT_ergodox)
|
||||||
|
else:
|
||||||
|
index_conversion_map = list(range(len(self.INDEX_CONVERSTION_LAYOUT_ergodox_pretty_to_LAYOUT_ergodox)))
|
||||||
|
self.current_converted_KEY_COORDINATES = [
|
||||||
|
self.KEY_COORDINATES[self.output_layout][index_conversion_map[i]]
|
||||||
|
for i in range(len(self.KEY_COORDINATES[self.output_layout]))
|
||||||
|
]
|
||||||
|
|
||||||
|
self.output = self.beautify_source_code(source_code)
|
||||||
|
|
||||||
|
def beautify_source_code(self, source_code):
|
||||||
|
# to keep it simple for the parser, we only use the parser to parse the key definition part
|
||||||
|
src = {
|
||||||
|
"before": [],
|
||||||
|
"keys": [],
|
||||||
|
"after": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
current_section = "before"
|
||||||
|
for line in source_code.splitlines(True):
|
||||||
|
if current_section == 'before' and line == self.KEYMAP_START:
|
||||||
|
src[current_section].append("\n")
|
||||||
|
current_section = 'keys'
|
||||||
|
src[current_section].append(self.KEYMAP_START_REPLACEMENT)
|
||||||
|
continue
|
||||||
|
elif current_section == 'keys' and line == self.KEYMAP_END:
|
||||||
|
src[current_section].append(self.KEYMAP_END)
|
||||||
|
current_section = 'after'
|
||||||
|
continue
|
||||||
|
src[current_section].append(line)
|
||||||
|
output_lines = src['before'] + self.beautify_keys_section("".join(src['keys'])) + src['after']
|
||||||
|
return "".join(output_lines)
|
||||||
|
|
||||||
|
def beautify_keys_section(self, src):
|
||||||
|
parsed = self.parser(src)
|
||||||
|
layer_output = []
|
||||||
|
|
||||||
|
keymap = parsed.children()[0]
|
||||||
|
layers = keymap[1]
|
||||||
|
for layer in layers.init.exprs:
|
||||||
|
input_layout = layer.expr.name.name
|
||||||
|
|
||||||
|
key_symbols = self.layer_expr(layer)
|
||||||
|
# re-order keys from input_layout to regular layout
|
||||||
|
if input_layout == "LAYOUT_ergodox_pretty":
|
||||||
|
key_symbols = [key_symbols[i] for i in self.index_conversion_map_reversed(self.INDEX_CONVERSTION_LAYOUT_ergodox_pretty_to_LAYOUT_ergodox)]
|
||||||
|
|
||||||
|
padded_key_symbols = self.pad_key_symbols(key_symbols, input_layout)
|
||||||
|
current_pretty_output_layer = self.pretty_output_layer(layer.name[0].value, padded_key_symbols)
|
||||||
|
# strip trailing spaces from padding
|
||||||
|
layer_output.append(re.sub(r" +\n", "\n", current_pretty_output_layer))
|
||||||
|
|
||||||
|
return [self.KEYMAP_START + "\n",
|
||||||
|
self.KEY_CHART + "\n",
|
||||||
|
",\n\n".join(layer_output) + "\n",
|
||||||
|
self.KEYMAP_END + "\n"]
|
||||||
|
|
||||||
|
def get_row_group(self, row):
|
||||||
|
for low, high in self.KEY_ROW_GROUPS[self.output_layout]:
|
||||||
|
if low <= row <= high:
|
||||||
|
return (low, high)
|
||||||
|
raise Exception("Cannot find row groups in KEY_ROW_GROUPS")
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_column_max_widths(self, key_symbols):
|
||||||
|
# calculate the max width for each column
|
||||||
|
self.column_max_widths = {}
|
||||||
|
for i in range(len(key_symbols)):
|
||||||
|
row_index, column_index = self.current_converted_KEY_COORDINATES[i]
|
||||||
|
row_group = self.get_row_group(row_index)
|
||||||
|
if (row_group, column_index) in self.column_max_widths:
|
||||||
|
self.column_max_widths[(row_group, column_index)] = max(self.column_max_widths[(row_group, column_index)], len(key_symbols[i]))
|
||||||
|
else:
|
||||||
|
self.column_max_widths[(row_group, column_index)] = len(key_symbols[i])
|
||||||
|
|
||||||
|
|
||||||
|
def pad_key_symbols(self, key_symbols, input_layout, just='left'):
|
||||||
|
self.calculate_column_max_widths(key_symbols)
|
||||||
|
|
||||||
|
padded_key_symbols = []
|
||||||
|
# pad each key symbol
|
||||||
|
for i in range(len(key_symbols)):
|
||||||
|
key = key_symbols[i]
|
||||||
|
# look up column coordinate to determine number of spaces to pad
|
||||||
|
row_index, column_index = self.current_converted_KEY_COORDINATES[i]
|
||||||
|
row_group = self.get_row_group(row_index)
|
||||||
|
if just == 'left':
|
||||||
|
padded_key_symbols.append(key.ljust(self.column_max_widths[(row_group, column_index)]))
|
||||||
|
else:
|
||||||
|
padded_key_symbols.append(key.rjust(self.column_max_widths[(row_group, column_index)]))
|
||||||
|
return padded_key_symbols
|
||||||
|
|
||||||
|
|
||||||
|
layer_keys_pointer = 0
|
||||||
|
layer_keys = None
|
||||||
|
def grab_next_n_columns(self, n_columns, input_layout, layer_keys = None, from_beginning = False):
|
||||||
|
if layer_keys:
|
||||||
|
self.layer_keys = layer_keys
|
||||||
|
if from_beginning:
|
||||||
|
self.layer_keys_pointer = 0
|
||||||
|
|
||||||
|
begin = self.layer_keys_pointer
|
||||||
|
end = begin + n_columns
|
||||||
|
return self.layer_keys[self.layer_keys_pointer-n_keys:self.layer_keys_pointer]
|
||||||
|
|
||||||
|
key_coordinates_counter = 0
|
||||||
|
def get_padded_line(self, source_keys, key_from, key_to, just="left"):
|
||||||
|
if just == "right":
|
||||||
|
keys = [k.strip().rjust(len(k)) for k in source_keys[key_from:key_to]]
|
||||||
|
else:
|
||||||
|
keys = [k for k in source_keys[key_from:key_to]]
|
||||||
|
|
||||||
|
from_row, from_column = self.KEY_COORDINATES[self.output_layout][self.key_coordinates_counter]
|
||||||
|
row_group = self.get_row_group(from_row)
|
||||||
|
self.key_coordinates_counter += key_to - key_from
|
||||||
|
columns_before_key_from = sorted([col for row, col in self.KEY_COORDINATES[self.output_layout] if row == from_row and col < from_column])
|
||||||
|
# figure out which columns in this row needs padding; only pad empty columns to the right of an existing column
|
||||||
|
columns_to_pad = { c: True for c in range(from_column) }
|
||||||
|
if columns_before_key_from:
|
||||||
|
for c in range(max(columns_before_key_from)+1):
|
||||||
|
columns_to_pad[c] = False
|
||||||
|
|
||||||
|
# for rows with fewer columns that don't start with column 0, we need to insert leading spaces
|
||||||
|
spaces = 0
|
||||||
|
for c, v in columns_to_pad.items():
|
||||||
|
if not v:
|
||||||
|
continue
|
||||||
|
if (row_group,c) in self.column_max_widths:
|
||||||
|
spaces += self.column_max_widths[(row_group,c)] + len(", ")
|
||||||
|
else:
|
||||||
|
spaces += 0
|
||||||
|
return " " * spaces + ", ".join(keys) + ","
|
||||||
|
|
||||||
|
def pretty_output_layer(self, layer, keys):
|
||||||
|
self.key_coordinates_counter = 0
|
||||||
|
if self.output_layout == "LAYOUT_ergodox":
|
||||||
|
formatted_key_symbols = """
|
||||||
|
// left hand
|
||||||
|
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
|
||||||
|
// left thumb
|
||||||
|
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
|
||||||
|
// right hand
|
||||||
|
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
|
||||||
|
// right thumb
|
||||||
|
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
{}
|
||||||
|
""".format(
|
||||||
|
# left hand
|
||||||
|
self.get_padded_line(keys, 0, 7, just="left"),
|
||||||
|
self.get_padded_line(keys, 7, 14, just="left"),
|
||||||
|
self.get_padded_line(keys, 14, 20, just="left"),
|
||||||
|
self.get_padded_line(keys, 20, 27, just="left"),
|
||||||
|
self.get_padded_line(keys, 27, 32, just="left"),
|
||||||
|
# left thumb
|
||||||
|
self.get_padded_line(keys, 32, 34, just="left"),
|
||||||
|
self.get_padded_line(keys, 34, 35, just="left"),
|
||||||
|
self.get_padded_line(keys, 35, 38, just="left"),
|
||||||
|
# right hand
|
||||||
|
self.get_padded_line(keys, 38, 45, just="left"),
|
||||||
|
self.get_padded_line(keys, 45, 52, just="left"),
|
||||||
|
self.get_padded_line(keys, 52, 58, just="left"),
|
||||||
|
self.get_padded_line(keys, 58, 65, just="left"),
|
||||||
|
self.get_padded_line(keys, 65, 70, just="left"),
|
||||||
|
# right thumb
|
||||||
|
self.get_padded_line(keys, 70, 72, just="left"),
|
||||||
|
self.get_padded_line(keys, 72, 73, just="left"),
|
||||||
|
self.get_padded_line(keys, 73, 76, just="left"),
|
||||||
|
)
|
||||||
|
elif self.output_layout == "LAYOUT_ergodox_pretty":
|
||||||
|
left_half_justification = "right" if self.justify_toward_center else "left"
|
||||||
|
formatted_key_symbols = """
|
||||||
|
{} {}
|
||||||
|
{} {}
|
||||||
|
{} {}
|
||||||
|
{} {}
|
||||||
|
{} {}
|
||||||
|
|
||||||
|
{} {}
|
||||||
|
{} {}
|
||||||
|
{} {}
|
||||||
|
""".format(
|
||||||
|
self.get_padded_line(keys, 0, 7, just=left_half_justification), self.get_padded_line(keys, 38, 45, just="left"),
|
||||||
|
self.get_padded_line(keys, 7, 14, just=left_half_justification), self.get_padded_line(keys, 45, 52, just="left"),
|
||||||
|
self.get_padded_line(keys, 14, 20, just=left_half_justification), self.get_padded_line(keys, 52, 58, just="left"),
|
||||||
|
self.get_padded_line(keys, 20, 27, just=left_half_justification), self.get_padded_line(keys, 58, 65, just="left"),
|
||||||
|
self.get_padded_line(keys, 27, 32, just=left_half_justification), self.get_padded_line(keys, 65, 70, just="left"),
|
||||||
|
|
||||||
|
self.get_padded_line(keys, 32, 34, just=left_half_justification), self.get_padded_line(keys, 70, 72, just="left"),
|
||||||
|
self.get_padded_line(keys, 34, 35, just=left_half_justification), self.get_padded_line(keys, 72, 73, just="left"),
|
||||||
|
self.get_padded_line(keys, 35, 38, just=left_half_justification), self.get_padded_line(keys, 73, 76, just="left"),
|
||||||
|
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
formatted_key_symbols = ""
|
||||||
|
|
||||||
|
# rid of the trailing comma
|
||||||
|
formatted_key_symbols = formatted_key_symbols[0:len(formatted_key_symbols)-2] + "\n"
|
||||||
|
s = "[{}] = {}({})".format(layer, self.output_layout, formatted_key_symbols)
|
||||||
|
return s
|
||||||
|
|
||||||
|
# helper functions for pycparser
|
||||||
|
def parser(self, src):
|
||||||
|
src = self.comment_remover(src)
|
||||||
|
return pycparser.CParser().parse(src)
|
||||||
|
def comment_remover(self, text):
|
||||||
|
# remove comments since pycparser cannot deal with them
|
||||||
|
# credit: https://stackoverflow.com/a/241506
|
||||||
|
def replacer(match):
|
||||||
|
s = match.group(0)
|
||||||
|
if s.startswith('/'):
|
||||||
|
return " " # note: a space and not an empty string
|
||||||
|
else:
|
||||||
|
return s
|
||||||
|
pattern = re.compile(
|
||||||
|
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
|
||||||
|
re.DOTALL | re.MULTILINE
|
||||||
|
)
|
||||||
|
return re.sub(pattern, replacer, text)
|
||||||
|
|
||||||
|
def function_expr(self, f):
|
||||||
|
name = f.name.name
|
||||||
|
args = []
|
||||||
|
for arg in f.args.exprs:
|
||||||
|
if type(arg) is pycparser.c_ast.Constant:
|
||||||
|
args.append(arg.value)
|
||||||
|
elif type(arg) is pycparser.c_ast.ID:
|
||||||
|
args.append(arg.name)
|
||||||
|
return "{}({})".format(name, ",".join(args))
|
||||||
|
|
||||||
|
def key_expr(self, raw):
|
||||||
|
if type(raw) is pycparser.c_ast.ID:
|
||||||
|
if raw.name in self.KEY_ALIASES:
|
||||||
|
return self.KEY_ALIASES[raw.name]
|
||||||
|
return raw.name
|
||||||
|
elif type(raw) is pycparser.c_ast.FuncCall:
|
||||||
|
return self.function_expr(raw)
|
||||||
|
|
||||||
|
def layer_expr(self, layer):
|
||||||
|
transformed = [self.key_expr(k) for k in layer.expr.args.exprs]
|
||||||
|
return transformed
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="Beautify keymap.c downloaded from ErgoDox-Ez Configurator for easier customization.")
|
||||||
|
parser.add_argument("input_filename", help="input file: c source code file that has the layer keymaps")
|
||||||
|
parser.add_argument("-o", "--output-filename", help="output file: beautified c filename. If not given, output to STDOUT.")
|
||||||
|
parser.add_argument("-p", "--pretty-output-layout", action="store_true", help="use LAYOUT_ergodox_pretty for output instead of LAYOUT_ergodox")
|
||||||
|
parser.add_argument("-c", "--justify-toward-center", action="store_true", help="for LAYOUT_ergodox_pretty, align right for the left half, and align left for the right half. Default is align left for both halves.")
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.pretty_output_layout:
|
||||||
|
output_layout="LAYOUT_ergodox_pretty"
|
||||||
|
else:
|
||||||
|
output_layout="LAYOUT_ergodox"
|
||||||
|
with open(args.input_filename) as f:
|
||||||
|
source_code = f.read()
|
||||||
|
result = KeymapBeautifier(source_code, output_layout=output_layout, justify_toward_center=args.justify_toward_center).output
|
||||||
|
if args.output_filename:
|
||||||
|
with open(args.output_filename, "w") as f:
|
||||||
|
f.write(result)
|
||||||
|
else:
|
||||||
|
print(result)
|
||||||
|
|
139
keyboards/ergodox_ez/util/keymap_beautifier/README.md
Normal file
139
keyboards/ergodox_ez/util/keymap_beautifier/README.md
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
# keymap_beautifier.py
|
||||||
|
|
||||||
|
## About
|
||||||
|
This Python 3 script, by [Tsan-Kuang Lee](https://github.com/tsankuanglee) takes the keymap.c downloaded from [ErgoDox EZ Configurator](https://configure.ergodox-ez.com/) and beautifies it for easier customization, allowing one to quickly draft a layout to build upon.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
For example, the original `keymap.c` looks like
|
||||||
|
|
||||||
|
```
|
||||||
|
[0] = LAYOUT_ergodox(KC_EQUAL,KC_1,KC_2,KC_3,KC_4,KC_5,LCTL(KC_MINUS),KC_DELETE,KC_Q,KC_W,KC_E,KC_R,KC_T,KC_LBRACKET,KC_BSPACE,KC_A,KC_S,KC_D,KC_F,KC_G,KC_LSPO,CTL_T(KC_Z),KC_X,KC_C,KC_V,KC_B,ALL_T(KC_NO),LT(1,KC_GRAVE),KC_QUOTE,LALT(KC_LSHIFT),KC_LEFT,KC_RIGHT,ALT_T(KC_APPLICATION),KC_LGUI,KC_HOME,KC_SPACE,KC_UNDS,KC_END,LCTL(KC_EQUAL),KC_6,KC_7,KC_8,KC_9,KC_0,KC_MINUS,KC_RBRACKET,KC_Y,KC_U,KC_I,KC_O,KC_P,KC_BSLASH,KC_H,ALT_T(KC_J),KC_K,KC_L,LT(2,KC_SCOLON),GUI_T(KC_QUOTE),MEH_T(KC_NO),KC_N,KC_M,KC_COMMA,KC_DOT,CTL_T(KC_SLASH),KC_RSPC,KC_UP,KC_DOWN,KC_LBRACKET,KC_RBRACKET,TT(1),KC_LALT,CTL_T(KC_ESCAPE),KC_PGUP,KC_PGDOWN,LT(1,KC_TAB),KC_ENTER),
|
||||||
|
```
|
||||||
|
|
||||||
|
The beautifier parses it and outputs:
|
||||||
|
|
||||||
|
```
|
||||||
|
[0] = LAYOUT_ergodox(
|
||||||
|
// left hand
|
||||||
|
|
||||||
|
KC_EQUAL , KC_1 , KC_2 , KC_3 , KC_4 , KC_5, LCTL(KC_MINUS),
|
||||||
|
KC_DELETE , KC_Q , KC_W , KC_E , KC_R , KC_T, KC_LBRACKET ,
|
||||||
|
KC_BSPACE , KC_A , KC_S , KC_D , KC_F , KC_G,
|
||||||
|
KC_LSPO , CTL_T(KC_Z), KC_X , KC_C , KC_V , KC_B, ALL_T(KC_NO) ,
|
||||||
|
LT(1,KC_GRAVE), KC_QUOTE , LALT(KC_LSHIFT), KC_LEFT, KC_RIGHT,
|
||||||
|
|
||||||
|
// left thumb
|
||||||
|
|
||||||
|
ALT_T(KC_APPLICATION), KC_LGUI,
|
||||||
|
KC_HOME,
|
||||||
|
KC_SPACE, KC_UNDS , KC_END ,
|
||||||
|
|
||||||
|
// right hand
|
||||||
|
|
||||||
|
LCTL(KC_EQUAL), KC_6, KC_7 , KC_8 , KC_9 , KC_0 , KC_MINUS ,
|
||||||
|
KC_RBRACKET , KC_Y, KC_U , KC_I , KC_O , KC_P , KC_BSLASH ,
|
||||||
|
KC_H, ALT_T(KC_J), KC_K , KC_L , LT(2,KC_SCOLON), GUI_T(KC_QUOTE),
|
||||||
|
MEH_T(KC_NO) , KC_N, KC_M , KC_COMMA, KC_DOT , CTL_T(KC_SLASH), KC_RSPC ,
|
||||||
|
KC_UP , KC_DOWN , KC_LBRACKET, KC_RBRACKET , TT(1) ,
|
||||||
|
|
||||||
|
// right thumb
|
||||||
|
|
||||||
|
KC_LALT , CTL_T(KC_ESCAPE),
|
||||||
|
KC_PGUP ,
|
||||||
|
KC_PGDOWN, LT(1,KC_TAB) , KC_ENTER
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Optionally, it can also render [LAYOUT_ergodox_pretty](https://github.com/qmk/qmk_firmware/blob/ee700b2e831067bdb7584425569b61bc6329247b/keyboards/ergodox_ez/keymaps/bpruitt-goddard/keymap.c#L49-L57):
|
||||||
|
```
|
||||||
|
[0] = LAYOUT_ergodox_pretty(
|
||||||
|
KC_ESCAPE, KC_1, KC_2, KC_3, KC_4, KC_5, KC_LEAD, KC_LEAD, KC_6 , KC_7 , KC_8 , KC_9 , KC_0 , KC_BSPACE ,
|
||||||
|
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_HYPR, KC_HYPR, KC_Y , KC_U , KC_I , KC_O , KC_P , KC_BSLASH ,
|
||||||
|
KC_LCTRL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H , KC_J , KC_K , KC_L , KC_SCOLON , KC_QUOTE ,
|
||||||
|
KC_LSHIFT, KC_Z, KC_X, KC_C, KC_V, KC_B, SH_MON, SH_MON , KC_N , KC_M , KC_COMMA , KC_DOT , KC_SLASH , KC_RSHIFT ,
|
||||||
|
LT(6,KC_NO), LT(7,KC_NO), KC_LCTRL, KC_LGUI, KC_LALT, ALGR_T(KC_MINUS), RGUI_T(KC_EQUAL), RCTL_T(KC_LBRACKET), LT(10,KC_RBRACKET), LT(6,KC_APPLICATION),
|
||||||
|
|
||||||
|
LT(6,KC_GRAVE), MEH_T(KC_NO), KC_LEFT, KC_RIGHT ,
|
||||||
|
LT(10,KC_DELETE), KC_UP ,
|
||||||
|
KC_SPACE, LT(8,KC_ENTER), LT(7,KC_BSPACE), KC_DOWN, LT(7,KC_SPACE), LT(8,KC_ENTER)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
We can also align everythng t othe left (easier editing in my opinon):
|
||||||
|
```
|
||||||
|
[0] = LAYOUT_ergodox_pretty(
|
||||||
|
KC_ESCAPE , KC_1 , KC_2 , KC_3 , KC_4 , KC_5 , KC_LEAD , KC_LEAD, KC_6 , KC_7 , KC_8 , KC_9 , KC_0 , KC_BSPACE ,
|
||||||
|
KC_TAB , KC_Q , KC_W , KC_E , KC_R , KC_T , KC_HYPR , KC_HYPR, KC_Y , KC_U , KC_I , KC_O , KC_P , KC_BSLASH ,
|
||||||
|
KC_LCTRL , KC_A , KC_S , KC_D , KC_F , KC_G , KC_H , KC_J , KC_K , KC_L , KC_SCOLON , KC_QUOTE ,
|
||||||
|
KC_LSHIFT , KC_Z , KC_X , KC_C , KC_V , KC_B , SH_MON , SH_MON , KC_N , KC_M , KC_COMMA , KC_DOT , KC_SLASH , KC_RSHIFT ,
|
||||||
|
LT(6,KC_NO), LT(7,KC_NO), KC_LCTRL, KC_LGUI, KC_LALT , ALGR_T(KC_MINUS), RGUI_T(KC_EQUAL), RCTL_T(KC_LBRACKET), LT(10,KC_RBRACKET), LT(6,KC_APPLICATION),
|
||||||
|
|
||||||
|
LT(6,KC_GRAVE), MEH_T(KC_NO) , KC_LEFT, KC_RIGHT ,
|
||||||
|
LT(10,KC_DELETE), KC_UP ,
|
||||||
|
KC_SPACE, LT(8,KC_ENTER), LT(7,KC_BSPACE) , KC_DOWN, LT(7,KC_SPACE), LT(8,KC_ENTER)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### With docker
|
||||||
|
This is the cleaner way. `Docker` is the only requirement. The program executes within a container that has all dependencies installed.
|
||||||
|
|
||||||
|
First build the images. (Run once)
|
||||||
|
```
|
||||||
|
cd QMK_GIT_REPO_dir/keyboards/ergodox_ez/util/keymap_beautifier
|
||||||
|
docker build -t keymapbeautifier:1.0 .
|
||||||
|
```
|
||||||
|
Run it
|
||||||
|
```
|
||||||
|
cd QMK_GIT_REPO_dir/keyboards/ergodox_ez/util/keymap_beautifier
|
||||||
|
cp PATH_TO_YOUR_C_SOURCE_FILE.c input.c
|
||||||
|
./docker_run.sh input.c -p -c -o output.c
|
||||||
|
```
|
||||||
|
The prettified file is written to `output.c`. See the section Tweaks for non-default settings.
|
||||||
|
|
||||||
|
### Without docker
|
||||||
|
Requirements:
|
||||||
|
* python3 (tested on 3.7.4)
|
||||||
|
* python module `pycparser` installed (with `pip install pycparser`)
|
||||||
|
|
||||||
|
To run:
|
||||||
|
```
|
||||||
|
cd QMK_GIT_REPO_dir/keyboards/ergodox_ez/util/keymap_beautifier
|
||||||
|
cp PATH_TO_YOUR_C_SOURCE_FILE.c input.c
|
||||||
|
./KeymapBeautifier.py input.c -p -c -o output.c
|
||||||
|
```
|
||||||
|
The prettified file is written to `output.c`. See the section Tweaks for non-default settings.
|
||||||
|
|
||||||
|
## Tweaks
|
||||||
|
```
|
||||||
|
usage: KeymapBeautifier.py [-h] [-o OUTPUT_FILENAME] [-p] [-c] input_filename
|
||||||
|
|
||||||
|
Beautify keymap.c downloaded from ErgoDox-Ez Configurator for easier
|
||||||
|
customization.
|
||||||
|
|
||||||
|
positional arguments:
|
||||||
|
input_filename input file: c source code file that has the layer
|
||||||
|
keymaps
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-o OUTPUT_FILENAME, --output-filename OUTPUT_FILENAME
|
||||||
|
output file: beautified c filename. If not given,
|
||||||
|
output to STDOUT.
|
||||||
|
-p, --pretty-output-layout
|
||||||
|
use LAYOUT_ergodox_pretty for output instead of
|
||||||
|
LAYOUT_ergodox
|
||||||
|
-c, --justify-toward-center
|
||||||
|
for LAYOUT_ergodox_pretty, align right for the left
|
||||||
|
half, and align left for the right half. Default is
|
||||||
|
align left for both halves.
|
||||||
|
```
|
||||||
|
For example,
|
||||||
|
```
|
||||||
|
./docker_run.sh input.c -p -c -o output.c
|
||||||
|
# or if you don't want to use docker:
|
||||||
|
#./KeymapBeautifier.py input.c -p -c -o output.c
|
||||||
|
```
|
||||||
|
will read `input.c`, and produce `output.c` with LAYOUT_ergodox_pretty, and have the key symbols gravitating toward the center.
|
||||||
|
|
3
keyboards/ergodox_ez/util/keymap_beautifier/docker_run.sh
Executable file
3
keyboards/ergodox_ez/util/keymap_beautifier/docker_run.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
docker run --mount type=bind,source="${PWD}",target=/usr/src/app --name keymapbeautifier --rm keymapbeautifier:1.0 ./KeymapBeautifier.py $*
|
@ -0,0 +1 @@
|
|||||||
|
pycparser
|
@ -1,3 +1,11 @@
|
|||||||
# ErgoDox EZ Utilities
|
# ErgoDox EZ Utilities
|
||||||
|
|
||||||
|
## compile_keymap.py
|
||||||
|
|
||||||
The Python script in this directory, by [mbarkhau](https://github.com/mbarkhau) allows you to write out a basic ErgoDox EZ keymap using Markdown notation, and then transpile it to C, which you can then compile. It's experimental, but if you're not comfortable using C, it's a nice option.
|
The Python script in this directory, by [mbarkhau](https://github.com/mbarkhau) allows you to write out a basic ErgoDox EZ keymap using Markdown notation, and then transpile it to C, which you can then compile. It's experimental, but if you're not comfortable using C, it's a nice option.
|
||||||
|
|
||||||
|
## keymap_beautifier.py
|
||||||
|
|
||||||
|
This Python 3 script, by [Tsan-Kuang Lee](https://github.com/tsankuanglee) takes the keymap.c downloaded from [ErgoDox EZ Configurator](https://configure.ergodox-ez.com/) and beautifies it for easier customization, allowing one to quickly draft a layout to build upon.
|
||||||
|
|
||||||
|
See [README.md](./keymap_beautifier/README.md) for this utility for more details.
|
||||||
|
Loading…
Reference in New Issue
Block a user