You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

230 lines
10 KiB

  1. #!/usr/bin/env python3
  2. import json
  3. from functools import reduce
  4. from chord import *
  5. import sys
  6. comma_separator = (lambda x, y: str(x) + ", " + str(y))
  7. string_sum = (lambda x, y: str(x) + " + " + str(y))
  8. newline_separator = (lambda x, y: str(x) + "\n" + str(y))
  9. def add_includes(data):
  10. output_buffer = ""
  11. if not ("do_not_include_QMK" in data["parameters"] and data["parameters"]["do_not_include_QMK"] == True):
  12. output_buffer += "#include QMK_KEYBOARD_H\n"
  13. if len(data["extra_dependencies"]) > 0:
  14. for dependecy in data["extra_dependencies"]:
  15. output_buffer += '#include "' + dependecy + '"\n'
  16. return output_buffer + "\n"
  17. def add_parameters(data):
  18. output_buffer = ""
  19. number_of_keys = len(data["keys"])
  20. if number_of_keys <= 8:
  21. hash_type = "uint8_t"
  22. elif number_of_keys <= 16:
  23. hash_type = "uint16_t"
  24. elif number_of_keys <= 32:
  25. hash_type = "uint32_t"
  26. elif number_of_keys <= 64:
  27. hash_type = "uint64_t"
  28. else:
  29. raise Exception("The engine currently supports only up to 64 keys.")
  30. output_buffer += "#define CHORD_TIMEOUT " + str(data["parameters"]["chord_timeout"]) + "\n"
  31. output_buffer += "#define DANCE_TIMEOUT " + str(data["parameters"]["dance_timeout"]) + "\n"
  32. output_buffer += "#define LEADER_TIMEOUT " + str(data["parameters"]["leader_timeout"]) + "\n"
  33. output_buffer += "#define TAP_TIMEOUT " + str(data["parameters"]["tap_timeout"]) + "\n"
  34. output_buffer += "#define LONG_PRESS_MULTIPLIER " + str(data["parameters"]["long_press_multiplier"]) + "\n"
  35. output_buffer += "#define DYNAMIC_MACRO_MAX_LENGTH " + str(data["parameters"]["dynamic_macro_max_length"]) + "\n"
  36. output_buffer += "#define COMMAND_MAX_LENGTH " + str(data["parameters"]["command_max_length"]) + "\n"
  37. output_buffer += "#define STRING_MAX_LENGTH " + str(data["parameters"]["string_max_length"]) + "\n"
  38. output_buffer += "#define LEADER_MAX_LENGTH " + str(data["parameters"]["leader_max_length"]) + "\n"
  39. output_buffer += "#define HASH_TYPE " + hash_type + "\n"
  40. output_buffer += "#define NUMBER_OF_KEYS " + str(len(data["keys"])) + "\n"
  41. output_buffer += "#define DEFAULT_PSEUDOLAYER " + data["parameters"]["default_pseudolayer"] + "\n"
  42. return output_buffer + "\n"
  43. def add_keycodes(data):
  44. output_buffer = ""
  45. if not len(data["keys"]) == len(set(data["keys"])):
  46. raise Exception("The keys must have unique names")
  47. for key, counter in zip(data["keys"], range(0, len(data["keys"]))):
  48. output_buffer += "#define H_" + key + " ((HASH_TYPE) 1 << " + str(counter) + ")\n"
  49. output_buffer += "\n"
  50. output_buffer += "enum internal_keycodes {\n"
  51. output_buffer += " " + data["keys"][0] + " = SAFE_RANGE,\n"
  52. output_buffer += " " + reduce(comma_separator, [key for key in data["keys"][1:]]) + ",\n"
  53. output_buffer += " FIRST_INTERNAL_KEYCODE = " + data["keys"][0] + ",\n"
  54. output_buffer += " LAST_INTERNAL_KEYCODE = " + data["keys"][-1] + "\n"
  55. output_buffer += "};\n"
  56. return output_buffer + "\n"
  57. def add_pseudolayers(data):
  58. output_buffer = ""
  59. if len(data["pseudolayers"]) == 0:
  60. raise Exception("You didn't define any pseudolayers")
  61. if not len([pseudolayer["name"] for pseudolayer in data["pseudolayers"]]) == len(set([pseudolayer["name"] for pseudolayer in data["pseudolayers"]])):
  62. raise Exception("The pseudolayers must have unique names")
  63. pseudolayers = data["pseudolayers"]
  64. if not "ALWAYS_ON" in [layer["name"] for layer in pseudolayers]:
  65. pseudolayers += [{"name": "ALWAYS_ON", "chords": []}] # the engine expects ALWAYS_ON to exist
  66. output_buffer += "enum pseudolayers {\n"
  67. output_buffer += " " + reduce(comma_separator, [layer["name"] for layer in pseudolayers]) + "\n"
  68. output_buffer += "};\n"
  69. return output_buffer + "\n"
  70. def add_layers(data):
  71. output_buffer = ""
  72. output_buffer += "const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {\n"
  73. for layer, counter in zip(data["layers"], range(0,len(data["layers"]))):
  74. if layer["type"] == "auto":
  75. output_buffer += " [" + str(counter) + "] = " + data["parameters"]["layout_function_name"] + "(" + reduce(comma_separator, [key for key in data["keys"]]) + "),\n"
  76. else:
  77. output_buffer += " [" + str(counter) + "] = " + data["parameters"]["layout_function_name"] + "(" + reduce(comma_separator, [key for key in layer["keycodes"]]) + "),\n"
  78. output_buffer += "};\n"
  79. output_buffer += "size_t keymapsCount = " + str(len(data["layers"])) + ";\n"
  80. return output_buffer + "\n"
  81. def prep_buffers(data):
  82. output_buffer = ""
  83. output_buffer += "uint8_t keycodes_buffer_array[] = {\n"
  84. output_buffer += " " + reduce(comma_separator, ["0"] * len(data["keys"])) + "\n"
  85. output_buffer += "};\n"
  86. output_buffer += "\n"
  87. output_buffer += "uint8_t command_buffer[] = {\n"
  88. output_buffer += " " + reduce(comma_separator, ["0"] * data["parameters"]["command_max_length"]) + "\n"
  89. output_buffer += "};\n"
  90. output_buffer += "\n"
  91. output_buffer += "uint16_t leader_buffer[] = {\n"
  92. output_buffer += " " + reduce(comma_separator, ["0"] * data["parameters"]["leader_max_length"]) + "\n"
  93. output_buffer += "};\n"
  94. output_buffer += "\n"
  95. output_buffer += "uint8_t dynamic_macro_buffer[] = {\n"
  96. output_buffer += " " + reduce(comma_separator, ["0"] * data["parameters"]["dynamic_macro_max_length"]) + "\n"
  97. output_buffer += "};"
  98. return output_buffer + "\n"
  99. def parse_keyboard_specifics(data):
  100. keyboard_part_0 = add_includes(data)
  101. keyboard_part_0 += add_keycodes(data)
  102. keyboard_part_0 += add_pseudolayers(data)
  103. keyboard_part_0 += add_parameters(data)
  104. keyboard_part_0 += add_layers(data)
  105. keyboard_part_0 += prep_buffers(data)
  106. return keyboard_part_0 + '\n'
  107. def parse_chords(data):
  108. keyboard_part_2 = ""
  109. strings = []
  110. number_of_strings = 0
  111. number_of_chords = 0
  112. for pseudolayer in data["pseudolayers"]:
  113. name = pseudolayer["name"]
  114. for chord in pseudolayer["chords"]:
  115. if chord["type"] == "chord_set":
  116. keycodes = reduce(comma_separator, [word for word in chord["keycodes"]])
  117. [keyboard_part_2, number_of_chords, number_of_strings, strings] = add_chord_set(name, keycodes, chord["set"], data, keyboard_part_2, number_of_chords, number_of_strings, strings)
  118. if chord["type"] == "visual_array":
  119. [keyboard_part_2, number_of_chords, number_of_strings, strings] = add_dictionary(name, chord["keys"], chord["dictionary"], keyboard_part_2, number_of_chords, number_of_strings, strings)
  120. if chord["type"] == "visual":
  121. keycodes = reduce(comma_separator, [word for word in chord["chord"]])
  122. [keyboard_part_2, number_of_chords, number_of_strings, strings] = secret_chord(name, chord["keycode"], keycodes, data, keyboard_part_2, number_of_chords, number_of_strings, strings)
  123. elif chord["type"] == "simple":
  124. keycodes = reduce(string_sum, ["H_" + word for word in chord["chord"]])
  125. [keyboard_part_2, number_of_chords, number_of_strings, strings] = add_key(name, keycodes, chord["keycode"], keyboard_part_2, number_of_chords, number_of_strings, strings)
  126. keyboard_part_2 += "\n"
  127. keyboard_part_2 += "const struct Chord* const list_of_chords[] PROGMEM = {\n"
  128. keyboard_part_2 += " " + reduce(comma_separator, ["&chord_" + str(i) for i in range(0, number_of_chords)]) + "\n"
  129. keyboard_part_2 += "};\n"
  130. keyboard_part_2 += "\n"
  131. if len(data["leader_sequences"]) > 0:
  132. keyboard_part_2 += reduce(newline_separator, [sequence["function"] for sequence in data["leader_sequences"]]) + "\n\n"
  133. keyboard_part_2 += "const uint16_t leader_triggers[][LEADER_MAX_LENGTH] PROGMEM = {\n"
  134. for sequence in data["leader_sequences"]:
  135. keyboard_part_2 += " {" + reduce(comma_separator, sequence["sequence"] + ["0"] * (data["parameters"]["leader_max_length"] - len(sequence["sequence"]))) + "},\n"
  136. keyboard_part_2 += "};\n\n"
  137. keyboard_part_2 += "void (*leader_functions[]) (void) = {\n"
  138. keyboard_part_2 += " " + reduce(comma_separator, ["&" + sequence["name"] for sequence in data["leader_sequences"]]) + "\n"
  139. keyboard_part_2 += "};\n"
  140. else:
  141. keyboard_part_2 += "const uint16_t** const leader_triggers PROGMEM = NULL;\n"
  142. keyboard_part_2 += "void (*leader_functions[]) (void) = {};\n"
  143. keyboard_part_2 += "\n"
  144. keyboard_part_2 += "#define NUMBER_OF_CHORDS " + str(number_of_chords) + "\n"
  145. keyboard_part_2 += "#define NUMBER_OF_LEADER_COMBOS " + str(len(data["leader_sequences"]))
  146. return keyboard_part_2 + "\n\n"
  147. def parse_strings_for_chords(data):
  148. keyboard_part_1 = ""
  149. for string, i in zip(strings, range(0, len(strings))):
  150. keyboard_part_1 += "const char string_" + str(i) + " [] PROGMEM = \"" + string + "\";\n"
  151. keyboard_part_1 += "\n"
  152. keyboard_part_1 += "const char * const strings[] PROGMEM = {\n"
  153. if len(strings) > 0:
  154. keyboard_part_1 += " " + reduce(comma_separator, ["string_" + str(i) for i in range(0, len(strings))])
  155. keyboard_part_1 += "\n};\n"
  156. return keyboard_part_1
  157. def main():
  158. if len(sys.argv) != 3:
  159. raise Exception("Wrong number of arguments.\n\nUsage: python parser.py keymap.json keymap.c")
  160. input_filepath = sys.argv[1]
  161. output_filepath = sys.argv[2]
  162. with open(input_filepath, "r") as read_file:
  163. data = json.load(read_file)
  164. keyboard_part_0 = parse_keyboard_specifics(data)
  165. keyboard_part_1 = parse_strings_for_chords(data)
  166. keyboard_part_2 = parse_chords(data)
  167. engine_part_1 = open("engine.part.1", "r").read()
  168. engine_part_2 = open("engine.part.2", "r").read() + "\n"
  169. engine_part_3 = open("engine.part.3", "r").read()
  170. output_buffer = keyboard_part_0
  171. output_buffer += engine_part_1
  172. if len(data["extra_code"]) > 0:
  173. output_buffer += data["extra_code"] + "\n"
  174. output_buffer += keyboard_part_1
  175. output_buffer += engine_part_2
  176. output_buffer += keyboard_part_2
  177. output_buffer += engine_part_3
  178. with open(output_filepath, "w") as write_file:
  179. write_file.write(output_buffer)
  180. if __name__ == "__main__":
  181. main()