Generate encodermap output from keymap.json. (#18915)

Co-authored-by: Joel Challis <git@zvecr.com>
This commit is contained in:
Nick Brassel 2023-02-11 13:45:51 +11:00 committed by GitHub
parent 01593501e3
commit 9991894514
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 119 additions and 72 deletions

View File

@ -21,6 +21,20 @@
"items": {"type": "string"} "items": {"type": "string"}
} }
}, },
"encoders": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "object",
"required": ["ccw", "cw"],
"properties": {
"ccw": {"type": "string"},
"cw": {"type": "string"}
}
}
}
},
"macros": { "macros": {
"type": "array", "type": "array",
"items": { "items": {

View File

@ -30,9 +30,99 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
__KEYMAP_GOES_HERE__ __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): def template_json(keyboard):
"""Returns a `keymap.json` template for a 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. A sequence of strings containing macros to implement for this keyboard.
""" """
new_keymap = template_c(keymap_json['keyboard']) new_keymap = template_c(keymap_json['keyboard'])
layer_txt = [] layer_txt = _generate_keymap_table(keymap_json)
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))
keymap = '\n'.join(layer_txt) keymap = '\n'.join(layer_txt)
new_keymap = new_keymap.replace('__KEYMAP_GOES_HERE__', keymap) new_keymap = new_keymap.replace('__KEYMAP_GOES_HERE__', keymap)
if keymap_json.get('macros'): encodermap = ''
macro_txt = [ if 'encoders' in keymap_json and keymap_json['encoders'] is not None:
'bool process_record_user(uint16_t keycode, keyrecord_t *record) {', encoder_txt = _generate_encodermap_table(keymap_json)
' if (record->event.pressed) {', encodermap = '\n'.join(encoder_txt)
' switch (keycode) {', new_keymap = new_keymap.replace('__ENCODER_MAP_GOES_HERE__', encodermap)
]
for i, macro_array in enumerate(keymap_json['macros']): macros = ''
macro = [] 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)
for macro_fragment in macro_array: hostlang = ''
if isinstance(macro_fragment, str): if 'host_language' in keymap_json and keymap_json['host_language'] is not None:
macro_fragment = macro_fragment.replace('\\', '\\\\') hostlang = f'#include "keymap_{keymap_json["host_language"]}.h"\n#include "sendstring_{keymap_json["host_language"]}.h"\n'
macro_fragment = macro_fragment.replace('\r\n', r'\n') new_keymap = new_keymap.replace('__INCLUDES__', hostlang)
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__', '')
return new_keymap return new_keymap