From 9e1b8a710c4b3b8bc27bf0d501ffbe891795ecda Mon Sep 17 00:00:00 2001 From: zvecr Date: Wed, 12 Oct 2022 19:41:11 +0100 Subject: [PATCH] Refactor XAP keycode logic --- ...ycodes_0.0.1.json => keycodes_0.0.1.hjson} | 14 ++--- data/schemas/xap.jsonschema | 6 --- data/xap/xap_0.1.0.hjson | 4 -- data/xap/xap_0.3.0.hjson | 6 --- lib/python/qmk/cli/xap/xap.py | 17 ++++-- lib/python/qmk/keycodes.py | 54 +++++++++++++++++++ lib/python/qmk/xap/common.py | 16 +----- 7 files changed, 75 insertions(+), 42 deletions(-) rename data/constants/{keycodes_0.0.1.json => keycodes_0.0.1.hjson} (99%) create mode 100644 lib/python/qmk/keycodes.py diff --git a/data/constants/keycodes_0.0.1.json b/data/constants/keycodes_0.0.1.hjson similarity index 99% rename from data/constants/keycodes_0.0.1.json rename to data/constants/keycodes_0.0.1.hjson index f3ff0166e3c..72bed1ab233 100644 --- a/data/constants/keycodes_0.0.1.json +++ b/data/constants/keycodes_0.0.1.hjson @@ -817,7 +817,7 @@ "key": "KC_LOCKING_NUM_LOCK", "label": "Num Lock", "aliases": [ - "KC_LSCR" + "KC_LNUM" ] }, "0x0084": { @@ -825,7 +825,7 @@ "key": "KC_LOCKING_SCROLL_LOCK", "label": "Scroll Lock", "aliases": [ - "KC_LCAP" + "KC_LSCR" ] }, "0x0085": { @@ -1246,23 +1246,23 @@ "key": "KC_WWW_FAVORITES", "label": "Browser Favorites", "aliases": [ - "KC_WREF" + "KC_WFAV" ] }, "0x00bb": { "group": "media", "key": "KC_MEDIA_FAST_FORWARD", - "label": "Browser Favorites", + "label": "Next Track", "aliases": [ - "KC_WREF" + "KC_MFFD" ] }, "0x00bc": { "group": "media", "key": "KC_MEDIA_REWIND", - "label": "Browser Favorites", + "label": "Previous Track", "aliases": [ - "KC_WFAV" + "KC_MRWD" ] }, "0x00bd": { diff --git a/data/schemas/xap.jsonschema b/data/schemas/xap.jsonschema index 0e3189561f0..89000bb47f7 100644 --- a/data/schemas/xap.jsonschema +++ b/data/schemas/xap.jsonschema @@ -135,12 +135,6 @@ "define": { "$ref": "qmk.definitions.v1#/define" }, - "uses": { - "type": "object", - "additionalProperties": { - "$ref": "qmk.definitions.v1#/bcd_version" - } - }, "documentation": { "type": "object", "properties": { diff --git a/data/xap/xap_0.1.0.hjson b/data/xap/xap_0.1.0.hjson index eef1b05e0dd..366f2cbf318 100755 --- a/data/xap/xap_0.1.0.hjson +++ b/data/xap/xap_0.1.0.hjson @@ -1,10 +1,6 @@ { version: 0.1.0 - uses: { - keycodes: 0.0.1 - } - documentation: { order: [ broadcast_messages diff --git a/data/xap/xap_0.3.0.hjson b/data/xap/xap_0.3.0.hjson index 81f881bb077..1bd24c47f2d 100644 --- a/data/xap/xap_0.3.0.hjson +++ b/data/xap/xap_0.3.0.hjson @@ -1,12 +1,6 @@ { version: 0.3.0 - uses: { - rgblight: 0.0.1 - rgb_matrix: 0.0.1 - led_matrix: 0.0.1 - } - routes: { 0x06: { diff --git a/lib/python/qmk/cli/xap/xap.py b/lib/python/qmk/cli/xap/xap.py index f1f28f86ce0..e6643be65c8 100644 --- a/lib/python/qmk/cli/xap/xap.py +++ b/lib/python/qmk/cli/xap/xap.py @@ -4,13 +4,12 @@ import cmd from milc import cli +from qmk.keycodes import load_spec +from qmk.decorators import lru_cache from qmk.keyboard import render_layout -from qmk.xap.common import get_xap_keycodes from xap_client import XAPClient, XAPEventType, XAPSecureStatus, XAPConfigRgblight, XAPConfigBacklight, XAPConfigRgbMatrix, XAPRoutes -KEYCODE_MAP = get_xap_keycodes('latest') - def print_dotted_output(kb_info_json, prefix=''): """Print the info.json in a plain text format with dot-joined keys. @@ -38,6 +37,16 @@ def print_dotted_output(kb_info_json, prefix=''): cli.echo(' {fg_blue}%s{fg_reset}: %s', new_prefix, kb_info_json[key]) +@lru_cache(timeout=5) +def _load_keycodes(keycode_version): + """Gets keycode data for the required version of the XAP definitions. + """ + spec = load_spec(keycode_version) + + # Transform into something more usable - { raw_value : first alias || keycode } + return {int(k, 16): v.get('aliases', [v.get('key')])[0] for k, v in spec['keycodes'].items()} + + def _list_devices(): """Dump out available devices """ @@ -62,7 +71,7 @@ class XAPShell(cmd.Cmd): cmd.Cmd.__init__(self) self.device = device # cache keycodes for this device - self.keycodes = get_xap_keycodes(device.version()['xap']) + self.keycodes = _load_keycodes(device.version().get('keycodes', 'latest')) def do_about(self, arg): """Prints out the version info of QMK diff --git a/lib/python/qmk/keycodes.py b/lib/python/qmk/keycodes.py new file mode 100644 index 00000000000..85aa77be383 --- /dev/null +++ b/lib/python/qmk/keycodes.py @@ -0,0 +1,54 @@ +from pathlib import Path + +from qmk.json_schema import deep_update, json_load + +CONSTANTS_PATH = Path('data/constants/') + + +def _validate(spec): + # no duplicate keycodes + keycodes = [] + for value in spec['keycodes'].values(): + keycodes.append(value['key']) + keycodes.extend(value.get('aliases', [])) + duplicates = set([x for x in keycodes if keycodes.count(x) > 1]) + if duplicates: + raise ValueError(f'Keycode spec contains duplicate keycodes! ({",".join(duplicates)})') + + +def load_spec(version): + """Build keycode data from the requested spec file + """ + if version == 'latest': + version = list_versions()[0] + + file = CONSTANTS_PATH / f'keycodes_{version}.hjson' + if not file.exists(): + raise ValueError(f'Requested keycode spec ({version}) is invalid!') + + # Load base + spec = json_load(file) + + # Merge in fragments + fragments = CONSTANTS_PATH.glob(f'keycodes_{version}_*.hjson') + for file in fragments: + deep_update(spec, json_load(file)) + + # Sort? + spec['keycodes'] = dict(sorted(spec['keycodes'].items())) + + # Validate? + _validate(spec) + + return spec + + +def list_versions(): + """Return available versions - sorted newest first + """ + ret = [] + for file in CONSTANTS_PATH.glob('keycodes_[0-9].[0-9].[0-9].hjson'): + ret.append(file.stem.split('_')[1]) + + ret.sort(reverse=True) + return ret diff --git a/lib/python/qmk/xap/common.py b/lib/python/qmk/xap/common.py index da888b09c8c..9e00034f5cc 100755 --- a/lib/python/qmk/xap/common.py +++ b/lib/python/qmk/xap/common.py @@ -9,7 +9,7 @@ from jinja2 import Environment, FileSystemLoader, select_autoescape from qmk.casing import to_snake from qmk.constants import QMK_FIRMWARE -from qmk.json_schema import json_load, validate +from qmk.json_schema import validate from qmk.decorators import lru_cache from qmk.keymap import locate_keymap from qmk.path import keyboard @@ -149,20 +149,6 @@ def merge_xap_defs(kb, km): return defs -@lru_cache(timeout=5) -def get_xap_keycodes(xap_version): - """Gets keycode data for the required version of the XAP definitions. - """ - defs = get_xap_defs(xap_version) - - # Load DD keycodes for the dependency - keycode_version = defs['uses']['keycodes'] - spec = json_load(Path(f'data/constants/keycodes_{keycode_version}.json')) - - # Transform into something more usable - { raw_value : first alias || keycode } - return {int(k, 16): v.get('aliases', [v.get('key')])[0] for k, v in spec['keycodes'].items()} - - def route_conditions(route_stack): """Handles building the C preprocessor conditional based on the current route. """