at master 130 lines 4.5 kB view raw
1"""Used by the make system to generate keyboard.h from info.json. 2""" 3from pathlib import Path 4 5from milc import cli 6 7from qmk.path import normpath 8from qmk.info import info_json 9from qmk.commands import dump_lines 10from qmk.keyboard import keyboard_completer, keyboard_folder 11from qmk.constants import COL_LETTERS, ROW_LETTERS, GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE 12 13 14def _generate_layouts(keyboard, kb_info_json): 15 """Generates the layouts macros. 16 """ 17 if 'matrix_size' not in kb_info_json: 18 cli.log.error(f'{keyboard}: Invalid matrix config.') 19 return [] 20 21 col_num = kb_info_json['matrix_size']['cols'] 22 row_num = kb_info_json['matrix_size']['rows'] 23 24 lines = [] 25 lines.append('') 26 lines.append('// Layout content') 27 lines.append('') 28 lines.append('#define XXX KC_NO') 29 30 for layout_name, layout_data in kb_info_json['layouts'].items(): 31 if layout_data['c_macro']: 32 continue 33 34 if not all('matrix' in key_data for key_data in layout_data['layout']): 35 cli.log.debug(f'{keyboard}/{layout_name}: No or incomplete matrix data!') 36 continue 37 38 layout_keys = [] 39 layout_matrix = [['XXX'] * col_num for _ in range(row_num)] 40 41 for key_data in layout_data['layout']: 42 row, col = key_data['matrix'] 43 identifier = f'k{ROW_LETTERS[row]}{COL_LETTERS[col]}' 44 if row >= row_num or col >= col_num: 45 cli.log.error(f'Skipping layouts due to {layout_name} containing invalid matrix values') 46 return [] 47 48 layout_matrix[row][col] = identifier 49 layout_keys.append(identifier) 50 51 lines.append('') 52 lines.append(f'#define {layout_name}({", ".join(layout_keys)}) {{ \\') 53 54 rows = ', \\\n'.join([' { ' + ', '.join(row) + ' }' for row in layout_matrix]) 55 rows += ' \\' 56 lines.append(rows) 57 lines.append('}') 58 59 for alias, target in kb_info_json.get('layout_aliases', {}).items(): 60 lines.append('') 61 lines.append(f'#ifndef {alias}') 62 lines.append(f'# define {alias} {target}') 63 lines.append('#endif') 64 65 return lines 66 67 68def _generate_keycodes(kb_info_json): 69 """Generates keyboard level keycodes. 70 """ 71 if 'keycodes' not in kb_info_json: 72 return [] 73 74 lines = [] 75 lines.append('') 76 lines.append('// Keycode content') 77 lines.append('') 78 lines.append('enum keyboard_keycodes {') 79 80 for index, item in enumerate(kb_info_json.get('keycodes')): 81 key = item["key"] 82 if index == 0: 83 lines.append(f' {key} = QK_KB_0,') 84 else: 85 lines.append(f' {key},') 86 87 lines.append('};') 88 89 for item in kb_info_json.get('keycodes', []): 90 key = item["key"] 91 for alias in item.get("aliases", []): 92 lines.append(f'#define {alias} {key}') 93 94 return lines 95 96 97@cli.argument('-i', '--include', nargs='?', arg_only=True, help='Optional file to include') 98@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') 99@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") 100@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, required=True, help='Keyboard to generate keyboard.h for.') 101@cli.subcommand('Used by the make system to generate keyboard.h from info.json', hidden=True) 102def generate_keyboard_h(cli): 103 """Generates the keyboard.h file. 104 """ 105 # Build the info.json file 106 kb_info_json = info_json(cli.args.keyboard) 107 108 keyboard_h = cli.args.include 109 dd_layouts = _generate_layouts(cli.args.keyboard, kb_info_json) 110 dd_keycodes = _generate_keycodes(kb_info_json) 111 valid_config = dd_layouts or keyboard_h 112 113 # Build the layouts.h file. 114 keyboard_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', '', '#include "quantum.h"'] 115 116 if dd_layouts: 117 keyboard_h_lines.extend(dd_layouts) 118 119 if keyboard_h: 120 keyboard_h_lines.append(f'#include "{Path(keyboard_h).name}"') 121 122 if dd_keycodes: 123 keyboard_h_lines.extend(dd_keycodes) 124 125 # Protect against poorly configured keyboards 126 if not valid_config: 127 keyboard_h_lines.append('#error("<keyboard>.h is required unless your keyboard uses data-driven configuration. Please rename your keyboard\'s header file to <keyboard>.h")') 128 129 # Show the results 130 dump_lines(cli.args.output, keyboard_h_lines, cli.args.quiet)