summary refs log tree commit diff
path: root/lib/python
diff options
context:
space:
mode:
authorNick Brassel <nick@tzarc.org>2023-02-11 13:45:51 +1100
committerGitHub <noreply@github.com>2023-02-11 13:45:51 +1100
commit99918945149f98cf73f9365b0ad49a2fc07d1152 (patch)
treed162dc0097445dfbd611cd9580cd04c4b31f3ac2 /lib/python
parent01593501e30624af64abc1905944788f8e3b15ba (diff)
Generate encodermap output from keymap.json. (#18915)
Co-authored-by: Joel Challis <git@zvecr.com>
Diffstat (limited to 'lib/python')
-rw-r--r--lib/python/qmk/keymap.py181
1 files changed, 107 insertions, 74 deletions
diff --git a/lib/python/qmk/keymap.py b/lib/python/qmk/keymap.py
index ce518e379d..dddf6449a7 100644
--- a/lib/python/qmk/keymap.py
+++ b/lib/python/qmk/keymap.py
@@ -30,9 +30,99 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
 __KEYMAP_GOES_HERE__
 };
 
+#if defined(ENCODER_ENABLE) && defined(ENCODER_MAP_ENABLE)
+const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
+__ENCODER_MAP_GOES_HERE__
+};
+#endif // defined(ENCODER_ENABLE) && defined(ENCODER_MAP_ENABLE)
+
+__MACRO_OUTPUT_GOES_HERE__
+
 """
 
 
+def _generate_keymap_table(keymap_json):
+    lines = []
+    for layer_num, layer in enumerate(keymap_json['layers']):
+        if layer_num != 0:
+            lines[-1] = lines[-1] + ','
+        layer = map(_strip_any, layer)
+        layer_keys = ', '.join(layer)
+        lines.append('\t[%s] = %s(%s)' % (layer_num, keymap_json['layout'], layer_keys))
+    return lines
+
+
+def _generate_encodermap_table(keymap_json):
+    lines = []
+    for layer_num, layer in enumerate(keymap_json['encoders']):
+        if layer_num != 0:
+            lines[-1] = lines[-1] + ','
+        encoder_keycode_txt = ', '.join([f'ENCODER_CCW_CW({_strip_any(e["ccw"])}, {_strip_any(e["cw"])})' for e in layer])
+        lines.append('\t[%s] = {%s}' % (layer_num, encoder_keycode_txt))
+    return lines
+
+
+def _generate_macros_function(keymap_json):
+    macro_txt = [
+        'bool process_record_user(uint16_t keycode, keyrecord_t *record) {',
+        '    if (record->event.pressed) {',
+        '        switch (keycode) {',
+    ]
+
+    for i, macro_array in enumerate(keymap_json['macros']):
+        macro = []
+
+        for macro_fragment in macro_array:
+            if isinstance(macro_fragment, str):
+                macro_fragment = macro_fragment.replace('\\', '\\\\')
+                macro_fragment = macro_fragment.replace('\r\n', r'\n')
+                macro_fragment = macro_fragment.replace('\n', r'\n')
+                macro_fragment = macro_fragment.replace('\r', r'\n')
+                macro_fragment = macro_fragment.replace('\t', r'\t')
+                macro_fragment = macro_fragment.replace('"', r'\"')
+
+                macro.append(f'"{macro_fragment}"')
+
+            elif isinstance(macro_fragment, dict):
+                newstring = []
+
+                if macro_fragment['action'] == 'delay':
+                    newstring.append(f"SS_DELAY({macro_fragment['duration']})")
+
+                elif macro_fragment['action'] == 'beep':
+                    newstring.append(r'"\a"')
+
+                elif macro_fragment['action'] == 'tap' and len(macro_fragment['keycodes']) > 1:
+                    last_keycode = macro_fragment['keycodes'].pop()
+
+                    for keycode in macro_fragment['keycodes']:
+                        newstring.append(f'SS_DOWN(X_{keycode})')
+
+                    newstring.append(f'SS_TAP(X_{last_keycode})')
+
+                    for keycode in reversed(macro_fragment['keycodes']):
+                        newstring.append(f'SS_UP(X_{keycode})')
+
+                else:
+                    for keycode in macro_fragment['keycodes']:
+                        newstring.append(f"SS_{macro_fragment['action'].upper()}(X_{keycode})")
+
+                macro.append(''.join(newstring))
+
+        new_macro = "".join(macro)
+        new_macro = new_macro.replace('""', '')
+        macro_txt.append(f'            case QK_MACRO_{i}:')
+        macro_txt.append(f'                SEND_STRING({new_macro});')
+        macro_txt.append('                return false;')
+
+    macro_txt.append('        }')
+    macro_txt.append('    }')
+    macro_txt.append('\n    return true;')
+    macro_txt.append('};')
+    macro_txt.append('')
+    return macro_txt
+
+
 def template_json(keyboard):
     """Returns a `keymap.json` template for a keyboard.
 
@@ -206,83 +296,26 @@ def generate_c(keymap_json):
             A sequence of strings containing macros to implement for this keyboard.
     """
     new_keymap = template_c(keymap_json['keyboard'])
-    layer_txt = []
-
-    for layer_num, layer in enumerate(keymap_json['layers']):
-        if layer_num != 0:
-            layer_txt[-1] = layer_txt[-1] + ','
-        layer = map(_strip_any, layer)
-        layer_keys = ', '.join(layer)
-        layer_txt.append('\t[%s] = %s(%s)' % (layer_num, keymap_json['layout'], layer_keys))
-
+    layer_txt = _generate_keymap_table(keymap_json)
     keymap = '\n'.join(layer_txt)
     new_keymap = new_keymap.replace('__KEYMAP_GOES_HERE__', keymap)
 
-    if keymap_json.get('macros'):
-        macro_txt = [
-            'bool process_record_user(uint16_t keycode, keyrecord_t *record) {',
-            '    if (record->event.pressed) {',
-            '        switch (keycode) {',
-        ]
-
-        for i, macro_array in enumerate(keymap_json['macros']):
-            macro = []
-
-            for macro_fragment in macro_array:
-                if isinstance(macro_fragment, str):
-                    macro_fragment = macro_fragment.replace('\\', '\\\\')
-                    macro_fragment = macro_fragment.replace('\r\n', r'\n')
-                    macro_fragment = macro_fragment.replace('\n', r'\n')
-                    macro_fragment = macro_fragment.replace('\r', r'\n')
-                    macro_fragment = macro_fragment.replace('\t', r'\t')
-                    macro_fragment = macro_fragment.replace('"', r'\"')
-
-                    macro.append(f'"{macro_fragment}"')
-
-                elif isinstance(macro_fragment, dict):
-                    newstring = []
-
-                    if macro_fragment['action'] == 'delay':
-                        newstring.append(f"SS_DELAY({macro_fragment['duration']})")
-
-                    elif macro_fragment['action'] == 'beep':
-                        newstring.append(r'"\a"')
-
-                    elif macro_fragment['action'] == 'tap' and len(macro_fragment['keycodes']) > 1:
-                        last_keycode = macro_fragment['keycodes'].pop()
-
-                        for keycode in macro_fragment['keycodes']:
-                            newstring.append(f'SS_DOWN(X_{keycode})')
-
-                        newstring.append(f'SS_TAP(X_{last_keycode})')
-
-                        for keycode in reversed(macro_fragment['keycodes']):
-                            newstring.append(f'SS_UP(X_{keycode})')
-
-                    else:
-                        for keycode in macro_fragment['keycodes']:
-                            newstring.append(f"SS_{macro_fragment['action'].upper()}(X_{keycode})")
-
-                    macro.append(''.join(newstring))
-
-            new_macro = "".join(macro)
-            new_macro = new_macro.replace('""', '')
-            macro_txt.append(f'            case QK_MACRO_{i}:')
-            macro_txt.append(f'                SEND_STRING({new_macro});')
-            macro_txt.append('                return false;')
-
-        macro_txt.append('        }')
-        macro_txt.append('    }')
-        macro_txt.append('\n    return true;')
-        macro_txt.append('};')
-        macro_txt.append('')
-
-        new_keymap = '\n'.join((new_keymap, *macro_txt))
-
-    if keymap_json.get('host_language'):
-        new_keymap = new_keymap.replace('__INCLUDES__', f'#include "keymap_{keymap_json["host_language"]}.h"\n#include "sendstring_{keymap_json["host_language"]}.h"\n')
-    else:
-        new_keymap = new_keymap.replace('__INCLUDES__', '')
+    encodermap = ''
+    if 'encoders' in keymap_json and keymap_json['encoders'] is not None:
+        encoder_txt = _generate_encodermap_table(keymap_json)
+        encodermap = '\n'.join(encoder_txt)
+    new_keymap = new_keymap.replace('__ENCODER_MAP_GOES_HERE__', encodermap)
+
+    macros = ''
+    if 'macros' in keymap_json and keymap_json['macros'] is not None:
+        macro_txt = _generate_macros_function(keymap_json)
+        macros = '\n'.join(macro_txt)
+    new_keymap = new_keymap.replace('__MACRO_OUTPUT_GOES_HERE__', macros)
+
+    hostlang = ''
+    if 'host_language' in keymap_json and keymap_json['host_language'] is not None:
+        hostlang = f'#include "keymap_{keymap_json["host_language"]}.h"\n#include "sendstring_{keymap_json["host_language"]}.h"\n'
+    new_keymap = new_keymap.replace('__INCLUDES__', hostlang)
 
     return new_keymap