147 lines
4.8 KiB
Python
Executable File
147 lines
4.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Copyright 2020-2022 Pierre Viseu Chevalier, Michael McCoyd (@pierrechevalier83, @mmccoyd)
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
"""Pretty print keymap json in more readable row/side organized format, based on ROW_SIZES."""
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
from typing import NamedTuple
|
|
|
|
"""Print keymap json in row and side format, though as still re-readable json.
|
|
|
|
For example, for one layer:
|
|
|
|
["KC_TAB" , "KC_Q" , "KC_W" , "KC_E" , "KC_R" , "KC_T",
|
|
"KC_Y" , "KC_U" , "KC_I" , "KC_O" , "KC_P" , "KC_BSPC",
|
|
|
|
"KC_LCTL", "KC_A" , "KC_S" , "KC_D" , "KC_F" , "KC_G",
|
|
"KC_H" , "KC_J" , "KC_K" , "KC_L" , "KC_SCLN", "KC_QUOT",
|
|
|
|
"KC_LSFT", "KC_Z" , "KC_X" , "KC_C" , "KC_V" , "KC_B" , "KC_GRV",
|
|
"KC_ESC" , "KC_N" , "KC_M" , "KC_COMM", "KC_DOT" , "KC_SLSH", "KC_RSFT",
|
|
|
|
"KC_ENT" , "KC_LGUI", "KC_LALT", "MO(5)" , "MO(3)",
|
|
"MO(4)" , "KC_SPC" , "KC_LALT", "KC_RGUI", "KC_APP"
|
|
],
|
|
"""
|
|
|
|
# The structure of the keymap. Tuples describing row sizes.
|
|
# (<Keys upto and including (one-indexed) keycount x> <are in half rows of y>)
|
|
ROW_SIZES = [(24, 6),
|
|
(38, 7),
|
|
(48, 5),
|
|
]
|
|
|
|
###
|
|
### Below here should not need to changed for different keyboards
|
|
###
|
|
|
|
LAST_KEY = ROW_SIZES[-1][0] - 1
|
|
|
|
indent_level=4 # number of spaces of initial indent per output line
|
|
|
|
def parse_cli():
|
|
parser = argparse.ArgumentParser(description='Hillside keymap formatter')
|
|
parser.add_argument("--input", type=argparse.FileType('r'),
|
|
default=sys.stdin, help="Input keymap "
|
|
"(json file produced by qmk configurator)")
|
|
return parser.parse_args()
|
|
|
|
class Column(NamedTuple):
|
|
"""Column number within keymap side, if it ends side, and ends row.
|
|
|
|
Position within a keyboard row runs from 0 to n and again 0 to n"""
|
|
num: int
|
|
ends_side: bool
|
|
ends_row: bool
|
|
|
|
def get_col(key_index):
|
|
"""Return Column for key_index."""
|
|
index_prior = 0 # index of last key in rows of the prior size
|
|
for keys_upto, num_cols in ROW_SIZES: # For row sizes from top
|
|
if key_index < keys_upto: # Find range key_index is in
|
|
col_num = (key_index - index_prior) % num_cols
|
|
return Column(col_num, # Return column plus side and row ends flags
|
|
ends_side=col_num == num_cols - 1,
|
|
ends_row=(keys_upto - 1 - key_index) %
|
|
(2 * num_cols) == 0)
|
|
index_prior = keys_upto # Big O: row ranges * keys, but range is small
|
|
|
|
def format_layers(layers):
|
|
formatted = indent_level * " " + "\"layers\": [\n"
|
|
|
|
# Find max key length per column
|
|
max_key_length = {}
|
|
for layer in layers:
|
|
for (index, keycode) in enumerate(layer):
|
|
col = get_col(index)
|
|
max_length = max_key_length.get(col.num)
|
|
if (not max_length) or len(keycode) > max_length:
|
|
max_key_length.update({col.num: len(keycode)})
|
|
# Format each layer
|
|
for (layer_index, layer) in enumerate(layers):
|
|
# Opening [
|
|
formatted += 2 * indent_level * " "
|
|
formatted += "["
|
|
|
|
# Split keys into pairs of left and right rows by key row length
|
|
for (index, keycode) in enumerate(layer):
|
|
col = get_col(index)
|
|
|
|
# Indent for rows past first
|
|
if col.num == 0 and index != 0:
|
|
formatted += (1 + 2 * indent_level) * " "
|
|
|
|
# Print key
|
|
formatted += json.dumps(keycode)
|
|
|
|
# End layer, or end side, or space to next key
|
|
if index == LAST_KEY:
|
|
formatted += "\n"
|
|
elif col.ends_side:
|
|
formatted += ",\n"
|
|
else:
|
|
n_spaces = max_key_length[get_col(index).num] - len(keycode)
|
|
formatted += n_spaces * " "
|
|
formatted += ", "
|
|
|
|
# Split groups of row sides
|
|
if col.ends_row:
|
|
formatted += "\n"
|
|
|
|
# Closing ] with , or without
|
|
formatted += 2 * indent_level * " "
|
|
if layer_index < len(layers) - 1:
|
|
formatted += "],\n"
|
|
else:
|
|
formatted += "]\n"
|
|
|
|
formatted += indent_level * " "
|
|
formatted += "]"
|
|
|
|
return formatted
|
|
|
|
def format_keymap(keymap_json):
|
|
formatted = "{"
|
|
for (index, k) in enumerate(keymap_json):
|
|
if k == "layers":
|
|
formatted += format_layers(keymap_json[k])
|
|
else:
|
|
formatted += f"{indent_level * ' '}{json.dumps(k)}: {json.dumps(keymap_json[k])}"
|
|
if index < len(keymap_json) - 1:
|
|
formatted += ","
|
|
formatted += "\n"
|
|
formatted += "}"
|
|
return formatted
|
|
|
|
def main():
|
|
args=parse_cli()
|
|
keymap_json = json.loads(args.input.read())
|
|
print(format_keymap(keymap_json))
|
|
|
|
if __name__ == "__main__":
|
|
main()
|