Tidy up LAYOUT macro generation (#18262)

This commit is contained in:
Joel Challis 2022-09-19 01:35:46 +01:00 committed by GitHub
parent 07936d37b6
commit 20f142a772
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 117 deletions

View file

@ -241,21 +241,20 @@ endif
# #
# https://docs.qmk.fm/#/feature_layouts?id=tips-for-making-layouts-keyboard-agnostic # https://docs.qmk.fm/#/feature_layouts?id=tips-for-making-layouts-keyboard-agnostic
# #
QMK_KEYBOARD_H = $(KEYBOARD_OUTPUT)/src/default_keyboard.h
ifneq ("$(wildcard $(KEYBOARD_PATH_1)/$(KEYBOARD_FOLDER_1).h)","") ifneq ("$(wildcard $(KEYBOARD_PATH_1)/$(KEYBOARD_FOLDER_1).h)","")
QMK_KEYBOARD_H = $(KEYBOARD_FOLDER_1).h FOUND_KEYBOARD_H = $(KEYBOARD_FOLDER_1).h
endif endif
ifneq ("$(wildcard $(KEYBOARD_PATH_2)/$(KEYBOARD_FOLDER_2).h)","") ifneq ("$(wildcard $(KEYBOARD_PATH_2)/$(KEYBOARD_FOLDER_2).h)","")
QMK_KEYBOARD_H = $(KEYBOARD_FOLDER_2).h FOUND_KEYBOARD_H = $(KEYBOARD_FOLDER_2).h
endif endif
ifneq ("$(wildcard $(KEYBOARD_PATH_3)/$(KEYBOARD_FOLDER_3).h)","") ifneq ("$(wildcard $(KEYBOARD_PATH_3)/$(KEYBOARD_FOLDER_3).h)","")
QMK_KEYBOARD_H = $(KEYBOARD_FOLDER_3).h FOUND_KEYBOARD_H = $(KEYBOARD_FOLDER_3).h
endif endif
ifneq ("$(wildcard $(KEYBOARD_PATH_4)/$(KEYBOARD_FOLDER_4).h)","") ifneq ("$(wildcard $(KEYBOARD_PATH_4)/$(KEYBOARD_FOLDER_4).h)","")
QMK_KEYBOARD_H = $(KEYBOARD_FOLDER_4).h FOUND_KEYBOARD_H = $(KEYBOARD_FOLDER_4).h
endif endif
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/$(KEYBOARD_FOLDER_5).h)","") ifneq ("$(wildcard $(KEYBOARD_PATH_5)/$(KEYBOARD_FOLDER_5).h)","")
QMK_KEYBOARD_H = $(KEYBOARD_FOLDER_5).h FOUND_KEYBOARD_H = $(KEYBOARD_FOLDER_5).h
endif endif
# Determine and set parameters based on the keyboard's processor family. # Determine and set parameters based on the keyboard's processor family.
@ -329,7 +328,7 @@ ifneq ("$(wildcard $(KEYBOARD_PATH_5)/info.json)","")
INFO_JSON_FILES += $(KEYBOARD_PATH_5)/info.json INFO_JSON_FILES += $(KEYBOARD_PATH_5)/info.json
endif endif
CONFIG_H += $(KEYBOARD_OUTPUT)/src/info_config.h $(KEYBOARD_OUTPUT)/src/layouts.h CONFIG_H += $(KEYBOARD_OUTPUT)/src/info_config.h
KEYBOARD_SRC += $(KEYBOARD_OUTPUT)/src/default_keyboard.c KEYBOARD_SRC += $(KEYBOARD_OUTPUT)/src/default_keyboard.c
$(KEYBOARD_OUTPUT)/src/info_config.h: $(INFO_JSON_FILES) $(KEYBOARD_OUTPUT)/src/info_config.h: $(INFO_JSON_FILES)
@ -344,15 +343,10 @@ $(KEYBOARD_OUTPUT)/src/default_keyboard.c: $(INFO_JSON_FILES)
$(KEYBOARD_OUTPUT)/src/default_keyboard.h: $(INFO_JSON_FILES) $(KEYBOARD_OUTPUT)/src/default_keyboard.h: $(INFO_JSON_FILES)
@$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD) @$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD)
$(eval CMD=$(QMK_BIN) generate-keyboard-h --quiet --keyboard $(KEYBOARD) --output $(KEYBOARD_OUTPUT)/src/default_keyboard.h) $(eval CMD=$(QMK_BIN) generate-keyboard-h --quiet --keyboard $(KEYBOARD) --include $(FOUND_KEYBOARD_H) --output $(KEYBOARD_OUTPUT)/src/default_keyboard.h)
@$(BUILD_CMD) @$(BUILD_CMD)
$(KEYBOARD_OUTPUT)/src/layouts.h: $(INFO_JSON_FILES) generated-files: $(KEYBOARD_OUTPUT)/src/info_config.h $(KEYBOARD_OUTPUT)/src/default_keyboard.c $(KEYBOARD_OUTPUT)/src/default_keyboard.h
@$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD)
$(eval CMD=$(QMK_BIN) generate-layouts --quiet --keyboard $(KEYBOARD) --output $(KEYBOARD_OUTPUT)/src/layouts.h)
@$(BUILD_CMD)
generated-files: $(KEYBOARD_OUTPUT)/src/info_config.h $(KEYBOARD_OUTPUT)/src/default_keyboard.c $(KEYBOARD_OUTPUT)/src/default_keyboard.h $(KEYBOARD_OUTPUT)/src/layouts.h
.INTERMEDIATE : generated-files .INTERMEDIATE : generated-files
@ -471,7 +465,7 @@ ALL_CONFIGS := $(PROJECT_CONFIG) $(CONFIG_H)
OUTPUTS := $(KEYMAP_OUTPUT) $(KEYBOARD_OUTPUT) OUTPUTS := $(KEYMAP_OUTPUT) $(KEYBOARD_OUTPUT)
$(KEYMAP_OUTPUT)_SRC := $(SRC) $(KEYMAP_OUTPUT)_SRC := $(SRC)
$(KEYMAP_OUTPUT)_DEFS := $(OPT_DEFS) \ $(KEYMAP_OUTPUT)_DEFS := $(OPT_DEFS) \
-DQMK_KEYBOARD=\"$(KEYBOARD)\" -DQMK_KEYBOARD_H=\"$(QMK_KEYBOARD_H)\" \ -DQMK_KEYBOARD=\"$(KEYBOARD)\" -DQMK_KEYBOARD_H=\"$(KEYBOARD_OUTPUT)/src/default_keyboard.h\" \
-DQMK_KEYMAP=\"$(KEYMAP)\" -DQMK_KEYMAP_H=\"$(KEYMAP).h\" -DQMK_KEYMAP_CONFIG_H=\"$(KEYMAP_PATH)/config.h\" -DQMK_KEYMAP=\"$(KEYMAP)\" -DQMK_KEYMAP_H=\"$(KEYMAP).h\" -DQMK_KEYMAP_CONFIG_H=\"$(KEYMAP_PATH)/config.h\"
$(KEYMAP_OUTPUT)_INC := $(VPATH) $(EXTRAINCDIRS) $(KEYMAP_OUTPUT)_INC := $(VPATH) $(EXTRAINCDIRS)
$(KEYMAP_OUTPUT)_CONFIG := $(CONFIG_H) $(KEYMAP_OUTPUT)_CONFIG := $(CONFIG_H)

View file

@ -4,7 +4,6 @@
#pragma once #pragma once
#include "quantum.h" #include "quantum.h"
#include "layouts.h" // Ensure access to info.json layouts
// This file only exists to pull in.... // This file only exists to pull in....
#include "ergodox_compat.h" #include "ergodox_compat.h"

View file

@ -56,7 +56,6 @@ subcommands = [
'qmk.cli.generate.info_json', 'qmk.cli.generate.info_json',
'qmk.cli.generate.keyboard_c', 'qmk.cli.generate.keyboard_c',
'qmk.cli.generate.keyboard_h', 'qmk.cli.generate.keyboard_h',
'qmk.cli.generate.layouts',
'qmk.cli.generate.rgb_breathe_table', 'qmk.cli.generate.rgb_breathe_table',
'qmk.cli.generate.rules_mk', 'qmk.cli.generate.rules_mk',
'qmk.cli.generate.version_h', 'qmk.cli.generate.version_h',

View file

@ -1,33 +1,72 @@
"""Used by the make system to generate keyboard.h from info.json. """Used by the make system to generate keyboard.h from info.json.
""" """
from pathlib import Path
from milc import cli from milc import cli
from qmk.path import normpath
from qmk.info import info_json from qmk.info import info_json
from qmk.commands import dump_lines from qmk.commands import dump_lines
from qmk.keyboard import keyboard_completer, keyboard_folder from qmk.keyboard import keyboard_completer, keyboard_folder
from qmk.path import normpath from qmk.constants import COL_LETTERS, ROW_LETTERS, GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
def would_populate_layout_h(keyboard): def _generate_layouts(keyboard):
"""Detect if a given keyboard is doing data driven layouts """Generates the layouts.h file.
""" """
# Build the info.json file # Build the info.json file
kb_info_json = info_json(keyboard) kb_info_json = info_json(keyboard)
if 'matrix_size' not in kb_info_json:
cli.log.error(f'{keyboard}: Invalid matrix config.')
return []
col_num = kb_info_json['matrix_size']['cols']
row_num = kb_info_json['matrix_size']['rows']
lines = []
for layout_name in kb_info_json['layouts']: for layout_name in kb_info_json['layouts']:
if kb_info_json['layouts'][layout_name]['c_macro']: if kb_info_json['layouts'][layout_name]['c_macro']:
continue continue
if 'matrix' not in kb_info_json['layouts'][layout_name]['layout'][0]: if 'matrix' not in kb_info_json['layouts'][layout_name]['layout'][0]:
cli.log.debug('%s/%s: No matrix data!', keyboard, layout_name) cli.log.debug(f'{keyboard}/{layout_name}: No matrix data!')
continue continue
return True layout_keys = []
layout_matrix = [['KC_NO' for i in range(col_num)] for i in range(row_num)]
return False for i, key in enumerate(kb_info_json['layouts'][layout_name]['layout']):
row = key['matrix'][0]
col = key['matrix'][1]
identifier = 'k%s%s' % (ROW_LETTERS[row], COL_LETTERS[col])
try:
layout_matrix[row][col] = identifier
layout_keys.append(identifier)
except IndexError:
key_name = key.get('label', identifier)
cli.log.error(f'Matrix data out of bounds for layout {layout_name} at index {i} ({key_name}): [{row}, {col}]')
return []
lines.append('')
lines.append('#define %s(%s) {\\' % (layout_name, ', '.join(layout_keys)))
rows = ', \\\n'.join(['\t {' + ', '.join(row) + '}' for row in layout_matrix])
rows += ' \\'
lines.append(rows)
lines.append('}')
for alias, target in kb_info_json.get('layout_aliases', {}).items():
lines.append('')
lines.append(f'#ifndef {alias}')
lines.append(f'# define {alias} {target}')
lines.append('#endif')
return lines
@cli.argument('-i', '--include', nargs='?', arg_only=True, help='Optional file to include')
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, required=True, help='Keyboard to generate keyboard.h for.') @cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, required=True, help='Keyboard to generate keyboard.h for.')
@ -35,13 +74,23 @@ def would_populate_layout_h(keyboard):
def generate_keyboard_h(cli): def generate_keyboard_h(cli):
"""Generates the keyboard.h file. """Generates the keyboard.h file.
""" """
has_layout_h = would_populate_layout_h(cli.args.keyboard) keyboard_h = cli.args.include
dd_layouts = _generate_layouts(cli.args.keyboard)
valid_config = dd_layouts or keyboard_h
# Build the layouts.h file. # Build the layouts.h file.
keyboard_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', '#include "quantum.h"'] keyboard_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', '#include "quantum.h"']
if not has_layout_h: keyboard_h_lines.append('')
keyboard_h_lines.append('#error("<keyboard>.h is only optional for data driven keyboards - kb.h == bad times")') keyboard_h_lines.append('// Layout content')
if dd_layouts:
keyboard_h_lines.extend(dd_layouts)
if keyboard_h:
keyboard_h_lines.append(f'#include "{Path(keyboard_h).name}"')
# Protect against poorly configured keyboards
if not valid_config:
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")')
# Show the results # Show the results
dump_lines(cli.args.output, keyboard_h_lines, cli.args.quiet) dump_lines(cli.args.output, keyboard_h_lines, cli.args.quiet)

View file

@ -1,84 +0,0 @@
"""Used by the make system to generate layouts.h from info.json.
"""
from milc import cli
from qmk.constants import COL_LETTERS, ROW_LETTERS, GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
from qmk.decorators import automagic_keyboard, automagic_keymap
from qmk.info import info_json
from qmk.keyboard import keyboard_completer, keyboard_folder
from qmk.path import is_keyboard, normpath
from qmk.commands import dump_lines
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate config.h for.')
@cli.subcommand('Used by the make system to generate layouts.h from info.json', hidden=True)
@automagic_keyboard
@automagic_keymap
def generate_layouts(cli):
"""Generates the layouts.h file.
"""
# Determine our keyboard(s)
if not cli.config.generate_layouts.keyboard:
cli.log.error('Missing parameter: --keyboard')
cli.subcommands['info'].print_help()
return False
if not is_keyboard(cli.config.generate_layouts.keyboard):
cli.log.error('Invalid keyboard: "%s"', cli.config.generate_layouts.keyboard)
return False
# Build the info.json file
kb_info_json = info_json(cli.config.generate_layouts.keyboard)
# Build the layouts.h file.
layouts_h_lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once']
if 'matrix_size' not in kb_info_json:
cli.log.error('%s: Invalid matrix config.', cli.config.generate_layouts.keyboard)
return False
col_num = kb_info_json['matrix_size']['cols']
row_num = kb_info_json['matrix_size']['rows']
for layout_name in kb_info_json['layouts']:
if kb_info_json['layouts'][layout_name]['c_macro']:
continue
if 'matrix' not in kb_info_json['layouts'][layout_name]['layout'][0]:
cli.log.debug('%s/%s: No matrix data!', cli.config.generate_layouts.keyboard, layout_name)
continue
layout_keys = []
layout_matrix = [['KC_NO' for i in range(col_num)] for i in range(row_num)]
for i, key in enumerate(kb_info_json['layouts'][layout_name]['layout']):
row = key['matrix'][0]
col = key['matrix'][1]
identifier = 'k%s%s' % (ROW_LETTERS[row], COL_LETTERS[col])
try:
layout_matrix[row][col] = identifier
layout_keys.append(identifier)
except IndexError:
key_name = key.get('label', identifier)
cli.log.error('Matrix data out of bounds for layout %s at index %s (%s): %s, %s', layout_name, i, key_name, row, col)
return False
layouts_h_lines.append('')
layouts_h_lines.append('#define %s(%s) {\\' % (layout_name, ', '.join(layout_keys)))
rows = ', \\\n'.join(['\t {' + ', '.join(row) + '}' for row in layout_matrix])
rows += ' \\'
layouts_h_lines.append(rows)
layouts_h_lines.append('}')
for alias, target in kb_info_json.get('layout_aliases', {}).items():
layouts_h_lines.append('')
layouts_h_lines.append(f'#ifndef {alias}')
layouts_h_lines.append(f'# define {alias} {target}')
layouts_h_lines.append('#endif')
# Show the results
dump_lines(cli.args.output, layouts_h_lines, cli.args.quiet)

View file

@ -288,12 +288,6 @@ def test_generate_version_h():
assert '#define QMK_VERSION' in result.stdout assert '#define QMK_VERSION' in result.stdout
def test_generate_layouts():
result = check_subcommand('generate-layouts', '-kb', 'handwired/pytest/basic')
check_returncode(result)
assert '#define LAYOUT_custom(k0A) {' in result.stdout
def test_format_json_keyboard(): def test_format_json_keyboard():
result = check_subcommand('format-json', '--format', 'keyboard', 'lib/python/qmk/tests/minimal_info.json') result = check_subcommand('format-json', '--format', 'keyboard', 'lib/python/qmk/tests/minimal_info.json')
check_returncode(result) check_returncode(result)