93 lines
3.5 KiB
Python
93 lines
3.5 KiB
Python
import os
|
|
|
|
from pathlib import Path
|
|
|
|
from milc.attrdict import AttrDict
|
|
|
|
from qmk.json_schema import json_load, validate
|
|
from qmk.util import truthy
|
|
from qmk.constants import QMK_FIRMWARE, QMK_USERSPACE, HAS_QMK_USERSPACE
|
|
from qmk.path import under_qmk_firmware, under_qmk_userspace
|
|
|
|
COMMUNITY_MODULE_JSON_FILENAME = 'qmk_module.json'
|
|
|
|
|
|
class ModuleAPI(AttrDict):
|
|
def __init__(self, **kwargs):
|
|
super().__init__()
|
|
for key, value in kwargs.items():
|
|
self[key] = value
|
|
|
|
|
|
MODULE_API_LIST = [
|
|
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'
|
|
|
|
|
|
def find_available_module_paths():
|
|
"""Find all available modules.
|
|
"""
|
|
search_dirs = []
|
|
if HAS_QMK_USERSPACE:
|
|
search_dirs.append(QMK_USERSPACE / 'modules')
|
|
search_dirs.append(QMK_FIRMWARE / 'modules')
|
|
|
|
modules = []
|
|
for search_dir in search_dirs:
|
|
for module_json_path in search_dir.rglob(COMMUNITY_MODULE_JSON_FILENAME):
|
|
modules.append(module_json_path.parent)
|
|
return modules
|
|
|
|
|
|
def find_module_path(module):
|
|
"""Find a module by name.
|
|
"""
|
|
for module_path in find_available_module_paths():
|
|
# Ensure the module directory is under QMK Firmware or QMK Userspace
|
|
relative_path = under_qmk_firmware(module_path)
|
|
if not relative_path:
|
|
relative_path = under_qmk_userspace(module_path)
|
|
if not relative_path:
|
|
continue
|
|
|
|
lhs = str(relative_path.as_posix())[len('modules/'):]
|
|
rhs = str(Path(module).as_posix())
|
|
|
|
if relative_path and lhs == rhs:
|
|
return module_path
|
|
return None
|
|
|
|
|
|
def load_module_json(module):
|
|
"""Load a module JSON file.
|
|
"""
|
|
module_path = find_module_path(module)
|
|
if not module_path:
|
|
raise FileNotFoundError(f'Module not found: {module}')
|
|
|
|
module_json = json_load(module_path / COMMUNITY_MODULE_JSON_FILENAME)
|
|
|
|
if not truthy(os.environ.get('SKIP_SCHEMA_VALIDATION'), False):
|
|
validate(module_json, 'qmk.community_module.v1')
|
|
|
|
module_json['module'] = module
|
|
module_json['module_path'] = module_path
|
|
|
|
return module_json
|
|
|
|
|
|
def load_module_jsons(modules):
|
|
"""Load the module JSON files, matching the specified order.
|
|
"""
|
|
return list(map(load_module_json, modules))
|