Created
April 7, 2021 08:50
-
-
Save brunomlopes/7592e34c6037651d1563cda7a6c11994 to your computer and use it in GitHub Desktop.
A quick parser for qmk keymap.c files, and via layouts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# %% | |
import json,math,itertools | |
input_file_path = r"C:\Users\bruno\OneDrive\Documents\QMK Via Layouts\sofle bl 2.4.json" | |
with open(input_file_path) as input: | |
exported_via_configuration = json.load(input) | |
layers = exported_via_configuration["layers"] | |
macros = exported_via_configuration["macros"] | |
# %% | |
# %% | |
def from_ix(ix): | |
def _(layout): | |
return layout[ix] | |
return _ | |
def split_spacer(n): | |
def _(layout): | |
return " "*n | |
return _ | |
def e(layout): return "" | |
sofle_layout_from_via = ( | |
(from_ix(0) , from_ix(1) , from_ix(2) , from_ix(3) , from_ix(4) , from_ix(5) , e , split_spacer(2), e , from_ix(35) , from_ix(34) , from_ix(33) , from_ix(32) , from_ix(31) , from_ix(30)), | |
(from_ix(6) , from_ix(7) , from_ix(8) , from_ix(9) , from_ix(10) , from_ix(11) , e , split_spacer(2), e , from_ix(41) , from_ix(40) , from_ix(39) , from_ix(38) , from_ix(37) , from_ix(36)), | |
(from_ix(12) , from_ix(13) , from_ix(14) , from_ix(15) , from_ix(16) , from_ix(17) , e , split_spacer(2), e , from_ix(47) , from_ix(46) , from_ix(45) , from_ix(44) , from_ix(43) , from_ix(42)), | |
(from_ix(18) , from_ix(19) , from_ix(20) , from_ix(21) , from_ix(22) , from_ix(23) , from_ix(29) , split_spacer(2), from_ix(59) , from_ix(53) , from_ix(52) , from_ix(51) , from_ix(50) , from_ix(49) , from_ix(48)), | |
(e , e , from_ix(24) , from_ix(25) , from_ix(26) , from_ix(27) , from_ix(28) , split_spacer(2), from_ix(58) , from_ix(57) , from_ix(56) , from_ix(55) , from_ix(54) , e , e, ), | |
) | |
sofle_layout_from_keymap = ( | |
(from_ix(0) , from_ix(1) , from_ix(2) , from_ix(3) , from_ix(4) , from_ix(5) , e , split_spacer(2), e , from_ix(6) , from_ix(7) , from_ix(8) , from_ix(9) , from_ix(10) , from_ix(11)), | |
(from_ix(12) , from_ix(13) , from_ix(14) , from_ix(15) , from_ix(16) , from_ix(17) , e , split_spacer(2), e , from_ix(18) , from_ix(19) , from_ix(20) , from_ix(21) , from_ix(22) , from_ix(23)), | |
(from_ix(24) , from_ix(25) , from_ix(26) , from_ix(27) , from_ix(28) , from_ix(29) , e , split_spacer(2), e , from_ix(30) , from_ix(31) , from_ix(32) , from_ix(33) , from_ix(34) , from_ix(35)), | |
(from_ix(36) , from_ix(37) , from_ix(38) , from_ix(39) , from_ix(40) , from_ix(41) , from_ix(42) , split_spacer(2), from_ix(43) , from_ix(44) , from_ix(45) , from_ix(46) , from_ix(47) , from_ix(48) , from_ix(49)), | |
(e , e , from_ix(50) , from_ix(51) , from_ix(52) , from_ix(53) , from_ix(54) , split_spacer(2), from_ix(55) , from_ix(56) , from_ix(57) , from_ix(58) , from_ix(59) , e , e, ), | |
) | |
sofle_layer_names = ( | |
"_BASE", | |
"_COLEMAK", | |
"_LOWER", | |
"_NAV", | |
"_SYMBOL", | |
"_NUMPAD" | |
) | |
layer_names = sofle_layer_names | |
board_layout = sofle_layout_from_keymap | |
import re | |
def replace_with_layer_symbol(key_label): | |
layer_call_regexps = ( | |
re.compile("LT\((?P<layer>\d+),[\w_]+\)"), | |
re.compile("TT\((?P<layer>\d+)\)"), | |
re.compile("MO\((?P<layer>\d+)\)"), | |
re.compile("TG\((?P<layer>\d+)\)"), | |
re.compile("OSL\((?P<layer>\d+)\)"), | |
) | |
for r in layer_call_regexps: | |
match = r.match(key_label) | |
if match: | |
layer = match.groupdict()["layer"] | |
return key_label.replace(layer, layer_names[int(layer)]) | |
return key_label | |
def common_replacements(key_label): | |
replacements = { | |
"KC_TRNS":"_______", | |
"SPC_FN3":"LT(3,KC_SPC)", | |
"SPC_FN2":"LT(2,KC_SPC)", | |
} | |
if key_label in replacements.keys(): | |
return replacements[key_label] | |
return key_label | |
def run_replacements(key_label): | |
return replace_with_layer_symbol(common_replacements(key_label)) | |
# %% | |
def print_keymaps(layers, board_layout): | |
print("enum layers {") | |
for layer_name in layer_names: | |
print(f"\t{layer_name},") | |
print("};\n\n") | |
min_padding = 1 | |
matrix_shape = (len(board_layout), max(len(l) for l in board_layout)) | |
print("const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {") | |
for i,layer in enumerate(layers[:]): | |
matrix = [[None]*matrix_shape[1] for line in range(matrix_shape[0])] | |
for line_no,line_content in enumerate(board_layout): | |
for col_no,col in enumerate(line_content): | |
key_label = col(layer).strip() | |
key_label = run_replacements(key_label) | |
matrix[line_no][col_no] = key_label | |
print(f"[{layer_names[i]}] = LAYOUT(") | |
for line_no, line in enumerate(matrix): | |
print(" ", end="") | |
for col_no,key in enumerate(line): | |
longest_key_definition_length = max(len((k or "")) for k in (l[col_no] for l in matrix)) + min_padding | |
right_padding = " " * ( longest_key_definition_length - len((key or "")) ) | |
left_padding = " " | |
suffix = "," | |
# this key is just padding for the layout to appear ok, do not emit a , | |
if not key or key.strip() == "": | |
suffix = " " | |
# last key which is not padding does not emit a , | |
if line_no == len(matrix)-1 and col_no == len([c for i,c in enumerate(line) if i<col_no or c.strip() != ""])-1: | |
suffix = "" | |
print(f"{left_padding}{key or ''}{right_padding}{suffix}",end="") | |
print() | |
print("),") | |
print("};") | |
# %% | |
# get layers from keymap.c | |
keymap_c_file_path = r"D:\documents\dev\qmk_firmware\keyboards\sofle\keymaps\bml-via\keymap.c" | |
with open(keymap_c_file_path) as input: | |
keymap_c_content = input.readlines() | |
def read_layouts_from_keymap(content, layout_def_start_marker = "LAYOUT("): | |
content_reader = iter(content) | |
try: | |
while True: | |
line = next(content_reader) | |
while layout_def_start_marker not in line: | |
line = next(content_reader) | |
line = next(content_reader) | |
lines = [] | |
while line.strip() != "),": | |
lines.append(line) | |
line = next(content_reader) | |
yield [label.strip() for label in re.split("[,](?!\w+\))","".join(lines))] | |
except StopIteration: | |
pass | |
layers = list(read_layouts_from_keymap(keymap_c_content)) | |
board_layout = sofle_layout_from_keymap | |
print_keymaps(layers, sofle_layout_from_keymap) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment