forked from mirrors/qmk_userspace
		
	Generate encodermap output from keymap.json. (#18915)
Co-authored-by: Joel Challis <git@zvecr.com>
This commit is contained in:
		
					parent
					
						
							
								01593501e3
							
						
					
				
			
			
				commit
				
					
						9991894514
					
				
			
		
					 2 changed files with 119 additions and 72 deletions
				
			
		| 
						 | 
					@ -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": {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue