diff --git a/lib/python/qmk/cli/generate/community_modules.py b/lib/python/qmk/cli/generate/community_modules.py index 5c72cd2455..96a1c1fc94 100644 --- a/lib/python/qmk/cli/generate/community_modules.py +++ b/lib/python/qmk/cli/generate/community_modules.py @@ -17,23 +17,23 @@ class ModuleAPI(AttrDict): MODULE_API_LIST = [ - ModuleAPI(ret_type='void', name='keyboard_pre_init', args='void', call_params='', ret_val=None, guard=None), - ModuleAPI(ret_type='void', name='keyboard_post_init', args='void', call_params='', ret_val=None, guard=None), - ModuleAPI(ret_type='bool', name='pre_process_record', args='uint16_t keycode, keyrecord_t *record', call_params='keycode, record', ret_val='true', guard=None), - ModuleAPI(ret_type='bool', name='process_record', args='uint16_t keycode, keyrecord_t *record', call_params='keycode, record', ret_val='true', guard=None), - ModuleAPI(ret_type='void', name='post_process_record', args='uint16_t keycode, keyrecord_t *record', call_params='keycode, record', ret_val=None, guard=None), - ModuleAPI(ret_type='void', name='housekeeping_task', args='void', call_params='', ret_val=None, guard=None), - ModuleAPI(ret_type='void', name='suspend_power_down', args='void', call_params='', ret_val=None, guard=None), - ModuleAPI(ret_type='void', name='suspend_wakeup_init', args='void', call_params='', ret_val=None, guard=None), - ModuleAPI(ret_type='bool', name='shutdown', args='bool jump_to_bootloader', call_params='jump_to_bootloader', ret_val='true', guard=None), - ModuleAPI(ret_type='bool', name='process_detected_host_os', args='os_variant_t os', call_params='os', ret_val='true', guard="defined(OS_DETECTION_ENABLE)"), + ModuleAPI(ret_type='void', name='keyboard_pre_init', args='void', call_params='', guard=None, header=None), + ModuleAPI(ret_type='void', name='keyboard_post_init', args='void', call_params='', guard=None, header=None), + ModuleAPI(ret_type='bool', name='pre_process_record', args='uint16_t keycode, keyrecord_t *record', call_params='keycode, record', guard=None, header=None), + ModuleAPI(ret_type='bool', name='process_record', args='uint16_t keycode, keyrecord_t *record', call_params='keycode, record', guard=None, header=None), + ModuleAPI(ret_type='void', name='post_process_record', args='uint16_t keycode, keyrecord_t *record', call_params='keycode, record', guard=None, header=None), + ModuleAPI(ret_type='void', name='housekeeping_task', args='void', call_params='', guard=None, header=None), + ModuleAPI(ret_type='void', name='suspend_power_down', args='void', call_params='', guard=None, header=None), + ModuleAPI(ret_type='void', name='suspend_wakeup_init', args='void', call_params='', guard=None, header=None), + ModuleAPI(ret_type='bool', name='shutdown', args='bool jump_to_bootloader', call_params='jump_to_bootloader', guard=None, header=None), + ModuleAPI(ret_type='bool', name='process_detected_host_os', args='os_variant_t os', call_params='os', guard="defined(OS_DETECTION_ENABLE)", header="os_detection.h"), ] MODULE_API_VERSION = '20250122' @contextlib.contextmanager -def api_guard(lines, api): +def _api_guard(lines, api): if api.guard: lines.append(f'#if {api.guard}') yield @@ -41,6 +41,78 @@ def api_guard(lines, api): lines.append(f'#endif // {api.guard}') +def _render_api_header(api): + lines = [] + if api.header: + lines.append('') + with _api_guard(lines, api): + lines.append(f'#include <{api.header}>') + return lines + + +def _render_api_declarations(api, module, user_kb=True): + lines = [] + lines.append('') + with _api_guard(lines, api): + if user_kb: + lines.append(f'{api.ret_type} {api.name}_{module}_user({api.args});') + lines.append(f'{api.ret_type} {api.name}_{module}_kb({api.args});') + lines.append(f'{api.ret_type} {api.name}_{module}({api.args});') + return lines + + +def _render_api_implementations(api, module): + lines = [] + lines.append('') + with _api_guard(lines, api): + # _user + lines.append(f'__attribute__((weak)) {api.ret_type} {api.name}_{module}_user({api.args}) {{') + if api.ret_type == 'bool': + lines.append(' return true;') + else: + pass + lines.append('}') + lines.append('') + + # _kb + lines.append(f'__attribute__((weak)) {api.ret_type} {api.name}_{module}_kb({api.args}) {{') + if api.ret_type == 'bool': + lines.append(f' if(!{api.name}_{module}_user({api.call_params})) {{ return false; }}') + lines.append(' return true;') + else: + lines.append(f' {api.name}_{module}_user({api.call_params});') + lines.append('}') + lines.append('') + + # module (non-suffixed) + lines.append(f'__attribute__((weak)) {api.ret_type} {api.name}_{module}({api.args}) {{') + if api.ret_type == 'bool': + lines.append(f' if(!{api.name}_{module}_kb({api.call_params})) {{ return false; }}') + lines.append(' return true;') + else: + lines.append(f' {api.name}_{module}_kb({api.call_params});') + lines.append('}') + return lines + + +def _render_core_implementation(api, keymap_json): + lines = [] + lines.append('') + with _api_guard(lines, api): + lines.append(f'{api.ret_type} {api.name}_modules({api.args}) {{') + if api.ret_type == 'bool': + lines.append(' return true') + for module in keymap_json['modules']: + if api.ret_type == 'bool': + lines.append(f' && {api.name}_{module}({api.call_params})') + else: + lines.append(f' {api.name}_{module}({api.call_params});') + if api.ret_type == 'bool': + lines.append(' ;') + lines.append('}') + return lines + + @cli.argument('-o', '--output', arg_only=True, type=qmk.path.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('filename', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file') @@ -61,28 +133,26 @@ def generate_community_modules_h(cli): f'#define COMMUNITY_MODULES_API_VERSION {MODULE_API_VERSION}', f'#define ASSERT_COMMUNITY_MODULES_MIN_API_VERSION(x) _Static_assert((x) <= COMMUNITY_MODULES_API_VERSION, "Community module requires higher version of QMK modules API -- needs: " #x ", current: {MODULE_API_VERSION}.")', '', - '#ifdef OS_DETECTION_ENABLE', - '#include "os_detection.h"', - '#endif // OS_DETECTION_ENABLE', + 'typedef struct keyrecord_t keyrecord_t; // forward declaration so we don\'t need to include quantum.h', '', - 'typedef struct keyrecord_t keyrecord_t;', ] keymap_json = parse_configurator_json(cli.args.filename) + for api in MODULE_API_LIST: + lines.extend(_render_api_header(api)) + if keymap_json and 'modules' in keymap_json: for module in keymap_json['modules']: lines.append('') lines.append(f'// From module: {module}') for api in MODULE_API_LIST: - with api_guard(lines, api): - lines.append(f'{api.ret_type} {api.name}_{module}({api.args});') + lines.extend(_render_api_declarations(api, module)) lines.append('') lines.append('// Core wrapper') for api in MODULE_API_LIST: - with api_guard(lines, api): - lines.append(f'{api.ret_type} {api.name}_modules({api.args});') + lines.extend(_render_api_declarations(api, 'modules', user_kb=False)) dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True) @@ -109,28 +179,10 @@ def generate_community_modules_c(cli): if keymap_json and 'modules' in keymap_json: for module in keymap_json['modules']: - lines.append('') for api in MODULE_API_LIST: - lines.append('') - with api_guard(lines, api): - lines.append(f'__attribute__((weak)) {api.ret_type} {api.name}_{module}({api.args}) {{') - if api.ret_val: - lines.append(f' return {api.ret_val};') - lines.append('}') + lines.extend(_render_api_implementations(api, module)) for api in MODULE_API_LIST: - lines.append('') - with api_guard(lines, api): - lines.append(f'{api.ret_type} {api.name}_modules({api.args}) {{') - if api.ret_type == 'bool': - lines.append(' return true') - for module in keymap_json['modules']: - if api.ret_type == 'bool': - lines.append(f' && {api.name}_{module}({api.call_params})') - else: - lines.append(f' {api.name}_{module}({api.call_params});') - if api.ret_type == 'bool': - lines.append(' ;') - lines.append('}') + lines.extend(_render_core_implementation(api, keymap_json)) dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True) diff --git a/modules/hello_world/hello_world.c b/modules/hello_world/hello_world.c index e46023cebf..0f02640cc4 100644 --- a/modules/hello_world/hello_world.c +++ b/modules/hello_world/hello_world.c @@ -7,10 +7,14 @@ ASSERT_COMMUNITY_MODULES_MIN_API_VERSION(20250122); static uint32_t init_timestamp = 0; void keyboard_post_init_hello_world(void) { + keyboard_post_init_hello_world_kb(); + init_timestamp = timer_read32(); } void housekeeping_task_hello_world(void) { + housekeeping_task_hello_world_kb(); + static bool welcomed = false; if(!welcomed && timer_elapsed32(init_timestamp) > 10000) { welcomed = true;