logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

keyboard_h.py (4510B)


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