diff options
Diffstat (limited to 'lib/python/qmk/keyboard.py')
| -rw-r--r-- | lib/python/qmk/keyboard.py | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/lib/python/qmk/keyboard.py b/lib/python/qmk/keyboard.py new file mode 100644 index 000000000..d1f2a301d --- /dev/null +++ b/lib/python/qmk/keyboard.py | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | """Functions that help us work with keyboards. | ||
| 2 | """ | ||
| 3 | from array import array | ||
| 4 | from math import ceil | ||
| 5 | from pathlib import Path | ||
| 6 | |||
| 7 | from qmk.c_parse import parse_config_h_file | ||
| 8 | from qmk.makefile import parse_rules_mk_file | ||
| 9 | |||
| 10 | |||
| 11 | def config_h(keyboard): | ||
| 12 | """Parses all the config.h files for a keyboard. | ||
| 13 | |||
| 14 | Args: | ||
| 15 | keyboard: name of the keyboard | ||
| 16 | |||
| 17 | Returns: | ||
| 18 | a dictionary representing the content of the entire config.h tree for a keyboard | ||
| 19 | """ | ||
| 20 | config = {} | ||
| 21 | cur_dir = Path('keyboards') | ||
| 22 | rules = rules_mk(keyboard) | ||
| 23 | keyboard = Path(rules['DEFAULT_FOLDER'] if 'DEFAULT_FOLDER' in rules else keyboard) | ||
| 24 | |||
| 25 | for dir in keyboard.parts: | ||
| 26 | cur_dir = cur_dir / dir | ||
| 27 | config = {**config, **parse_config_h_file(cur_dir / 'config.h')} | ||
| 28 | |||
| 29 | return config | ||
| 30 | |||
| 31 | |||
| 32 | def rules_mk(keyboard): | ||
| 33 | """Get a rules.mk for a keyboard | ||
| 34 | |||
| 35 | Args: | ||
| 36 | keyboard: name of the keyboard | ||
| 37 | |||
| 38 | Returns: | ||
| 39 | a dictionary representing the content of the entire rules.mk tree for a keyboard | ||
| 40 | """ | ||
| 41 | keyboard = Path(keyboard) | ||
| 42 | cur_dir = Path('keyboards') | ||
| 43 | rules = parse_rules_mk_file(cur_dir / keyboard / 'rules.mk') | ||
| 44 | |||
| 45 | if 'DEFAULT_FOLDER' in rules: | ||
| 46 | keyboard = Path(rules['DEFAULT_FOLDER']) | ||
| 47 | |||
| 48 | for i, dir in enumerate(keyboard.parts): | ||
| 49 | cur_dir = cur_dir / dir | ||
| 50 | rules = parse_rules_mk_file(cur_dir / 'rules.mk', rules) | ||
| 51 | |||
| 52 | return rules | ||
| 53 | |||
| 54 | |||
| 55 | def render_layout(layout_data, key_labels=None): | ||
| 56 | """Renders a single layout. | ||
| 57 | """ | ||
| 58 | textpad = [array('u', ' ' * 200) for x in range(50)] | ||
| 59 | |||
| 60 | for key in layout_data: | ||
| 61 | x = ceil(key.get('x', 0) * 4) | ||
| 62 | y = ceil(key.get('y', 0) * 3) | ||
| 63 | w = ceil(key.get('w', 1) * 4) | ||
| 64 | h = ceil(key.get('h', 1) * 3) | ||
| 65 | |||
| 66 | if key_labels: | ||
| 67 | label = key_labels.pop(0) | ||
| 68 | if label.startswith('KC_'): | ||
| 69 | label = label[3:] | ||
| 70 | else: | ||
| 71 | label = key.get('label', '') | ||
| 72 | |||
| 73 | label_len = w - 2 | ||
| 74 | label_leftover = label_len - len(label) | ||
| 75 | |||
| 76 | if len(label) > label_len: | ||
| 77 | label = label[:label_len] | ||
| 78 | |||
| 79 | label_blank = ' ' * label_len | ||
| 80 | label_border = '─' * label_len | ||
| 81 | label_middle = label + ' '*label_leftover # noqa: yapf insists there be no whitespace around * | ||
| 82 | |||
| 83 | top_line = array('u', '┌' + label_border + '┐') | ||
| 84 | lab_line = array('u', '│' + label_middle + '│') | ||
| 85 | mid_line = array('u', '│' + label_blank + '│') | ||
| 86 | bot_line = array('u', '└' + label_border + "┘") | ||
| 87 | |||
| 88 | textpad[y][x:x + w] = top_line | ||
| 89 | textpad[y + 1][x:x + w] = lab_line | ||
| 90 | for i in range(h - 3): | ||
| 91 | textpad[y + i + 2][x:x + w] = mid_line | ||
| 92 | textpad[y + h - 1][x:x + w] = bot_line | ||
| 93 | |||
| 94 | lines = [] | ||
| 95 | for line in textpad: | ||
| 96 | if line.tounicode().strip(): | ||
| 97 | lines.append(line.tounicode().rstrip()) | ||
| 98 | |||
| 99 | return '\n'.join(lines) | ||
| 100 | |||
| 101 | |||
| 102 | def render_layouts(info_json): | ||
| 103 | """Renders all the layouts from an `info_json` structure. | ||
| 104 | """ | ||
| 105 | layouts = {} | ||
| 106 | |||
| 107 | for layout in info_json['layouts']: | ||
| 108 | layout_data = info_json['layouts'][layout]['layout'] | ||
| 109 | layouts[layout] = render_layout(layout_data) | ||
| 110 | |||
| 111 | return layouts | ||
