1406 lines
36 KiB
Diff
1406 lines
36 KiB
Diff
|
Submitted upstream:
|
||
|
<https://github.com/benblazak/ergodox-firmware/pull/99>
|
||
|
<https://github.com/benblazak/ergodox-firmware/pull/98>
|
||
|
|
||
|
diff --git a/build-scripts/gen-layout.py b/build-scripts/gen-layout.py
|
||
|
index fd5e54c..251a463 100755
|
||
|
--- a/build-scripts/gen-layout.py
|
||
|
+++ b/build-scripts/gen-layout.py
|
||
|
@@ -22,8 +22,10 @@ import sys
|
||
|
|
||
|
# -----------------------------------------------------------------------------
|
||
|
|
||
|
-class Namespace():
|
||
|
- pass
|
||
|
+
|
||
|
+class Namespace:
|
||
|
+ pass
|
||
|
+
|
||
|
|
||
|
template = Namespace()
|
||
|
doc = Namespace()
|
||
|
@@ -31,45 +33,45 @@ info = Namespace()
|
||
|
|
||
|
# -----------------------------------------------------------------------------
|
||
|
|
||
|
+
|
||
|
def main():
|
||
|
- arg_parser = argparse.ArgumentParser(
|
||
|
- description = "Generate a picture of the firmware's "
|
||
|
- + "keyboard layout" )
|
||
|
+ arg_parser = argparse.ArgumentParser(
|
||
|
+ description="Generate a picture of the firmware's " + "keyboard layout"
|
||
|
+ )
|
||
|
|
||
|
- arg_parser.add_argument(
|
||
|
- '--ui-info-file',
|
||
|
- required = True )
|
||
|
+ arg_parser.add_argument("--ui-info-file", required=True)
|
||
|
|
||
|
- args = arg_parser.parse_args(sys.argv[1:])
|
||
|
+ args = arg_parser.parse_args(sys.argv[1:])
|
||
|
|
||
|
- # constant file paths
|
||
|
- args.template_svg_file = './build-scripts/gen_layout/template.svg'
|
||
|
- args.template_js_file = './build-scripts/gen_layout/template.js'
|
||
|
+ # constant file paths
|
||
|
+ args.template_svg_file = "./build-scripts/gen_layout/template.svg"
|
||
|
+ args.template_js_file = "./build-scripts/gen_layout/template.js"
|
||
|
|
||
|
- # normalize paths
|
||
|
- args.ui_info_file = os.path.abspath(args.ui_info_file)
|
||
|
- args.template_svg_file = os.path.abspath(args.template_svg_file)
|
||
|
- args.template_js_file = os.path.abspath(args.template_js_file)
|
||
|
+ # normalize paths
|
||
|
+ args.ui_info_file = os.path.abspath(args.ui_info_file)
|
||
|
+ args.template_svg_file = os.path.abspath(args.template_svg_file)
|
||
|
+ args.template_js_file = os.path.abspath(args.template_js_file)
|
||
|
|
||
|
- # set vars
|
||
|
- doc.main = '' # to store the html document we're generating
|
||
|
- template.svg = open(args.template_svg_file).read()
|
||
|
- template.js = open(args.template_js_file).read()
|
||
|
- info.all = json.loads(open(args.ui_info_file).read())
|
||
|
+ # set vars
|
||
|
+ doc.main = "" # to store the html document we're generating
|
||
|
+ template.svg = open(args.template_svg_file).read()
|
||
|
+ template.js = open(args.template_js_file).read()
|
||
|
+ info.all = json.loads(open(args.ui_info_file).read())
|
||
|
|
||
|
- info.matrix_positions = info.all['mappings']['matrix-positions']
|
||
|
- info.matrix_layout = info.all['mappings']['matrix-layout']
|
||
|
+ info.matrix_positions = info.all["mappings"]["matrix-positions"]
|
||
|
+ info.matrix_layout = info.all["mappings"]["matrix-layout"]
|
||
|
|
||
|
- # prefix
|
||
|
- doc.prefix = ("""
|
||
|
+ # prefix
|
||
|
+ doc.prefix = (
|
||
|
+ """
|
||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
|
<html>
|
||
|
|
||
|
<head>
|
||
|
<script>
|
||
|
"""
|
||
|
-+ template.js +
|
||
|
-""" </script>
|
||
|
+ + template.js
|
||
|
+ + """ </script>
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
@@ -78,9 +80,13 @@ def main():
|
||
|
|
||
|
<ul>
|
||
|
<li>git commit date:
|
||
|
- <code>""" + info.all['miscellaneous']['git-commit-date'] + """</code></li>
|
||
|
+ <code>"""
|
||
|
+ + info.all["miscellaneous"]["git-commit-date"]
|
||
|
+ + """</code></li>
|
||
|
<li>git commit id:
|
||
|
- <code>""" + info.all['miscellaneous']['git-commit-id'] + """</code></li>
|
||
|
+ <code>"""
|
||
|
+ + info.all["miscellaneous"]["git-commit-id"]
|
||
|
+ + """</code></li>
|
||
|
</ul>
|
||
|
|
||
|
<h2>Notes</h2>
|
||
|
@@ -123,301 +129,293 @@ def main():
|
||
|
|
||
|
<br>
|
||
|
|
||
|
-""")[1:-1]
|
||
|
+"""
|
||
|
+ )[1:-1]
|
||
|
|
||
|
- # suffix
|
||
|
- doc.suffix = ("""
|
||
|
+ # suffix
|
||
|
+ doc.suffix = (
|
||
|
+ """
|
||
|
</body>
|
||
|
</html>
|
||
|
|
||
|
-""")[1:-1]
|
||
|
-
|
||
|
- # substitute into template
|
||
|
- # -------
|
||
|
- # note: this is not general enough to handle any possible layout well, at
|
||
|
- # the moment. but it should handle more standard ones well. (hopefully
|
||
|
- # minor) modifications may be necessary on a case by case basis
|
||
|
- # -------
|
||
|
- layer_number = -1
|
||
|
- for (layout, layer) in zip( info.matrix_layout,
|
||
|
- range(len(info.matrix_layout))):
|
||
|
- layer_number += 1
|
||
|
- svg = template.svg
|
||
|
- for (name, (code, press, release)) \
|
||
|
- in zip(info.matrix_positions, layout):
|
||
|
- replace = ''
|
||
|
- if press == 'kbfun_transparent':
|
||
|
- replace = ''
|
||
|
- elif press == 'kbfun_shift_press_release':
|
||
|
- replace = 'sh ' + keycode_to_string.get(code, '[n/a]')
|
||
|
- elif press == 'kbfun_jump_to_bootloader':
|
||
|
- replace = '[btldr]'
|
||
|
- elif press == 'NULL' and release == 'NULL':
|
||
|
- replace = '(null)'
|
||
|
- elif re.search(r'numpad', press+release):
|
||
|
- replace = '[num]'
|
||
|
- elif re.search(r'layer', press+release):
|
||
|
- replace = 'la ' + re.findall(r'\d+', press+release)[0] + ' '
|
||
|
- if re.search(r'push', press+release):
|
||
|
- replace += '+'
|
||
|
- if re.search(r'pop', press+release):
|
||
|
- replace += '-'
|
||
|
- replace += ' ' + str(code)
|
||
|
- else:
|
||
|
- replace = keycode_to_string.get(code, '[n/a]')
|
||
|
-
|
||
|
- svg = re.sub(
|
||
|
- '>'+name+'<', '>'+replace+'<', svg )
|
||
|
- svg = re.sub(
|
||
|
- r"\('(" + name + r".*)'\)",
|
||
|
- r"('\1', " + str(layer) + r")",
|
||
|
- svg )
|
||
|
-
|
||
|
- doc.main += '<h2>Layer ' + str(layer_number) + '</h2>\n' + svg
|
||
|
-
|
||
|
- # change the font size
|
||
|
- doc.main = re.sub(r'22.5px', '15px', doc.main)
|
||
|
-
|
||
|
- print(doc.prefix + doc.main + doc.suffix)
|
||
|
+"""
|
||
|
+ )[1:-1]
|
||
|
+
|
||
|
+ # substitute into template
|
||
|
+ # -------
|
||
|
+ # note: this is not general enough to handle any possible layout well, at
|
||
|
+ # the moment. but it should handle more standard ones well. (hopefully
|
||
|
+ # minor) modifications may be necessary on a case by case basis
|
||
|
+ # -------
|
||
|
+ layer_number = -1
|
||
|
+ for (layout, layer) in zip(
|
||
|
+ info.matrix_layout, range(len(info.matrix_layout))
|
||
|
+ ):
|
||
|
+ layer_number += 1
|
||
|
+ svg = template.svg
|
||
|
+ for (name, (code, press, release)) in zip(
|
||
|
+ info.matrix_positions, layout
|
||
|
+ ):
|
||
|
+ replace = ""
|
||
|
+ if press == "kbfun_transparent":
|
||
|
+ replace = ""
|
||
|
+ elif press == "kbfun_shift_press_release":
|
||
|
+ replace = "sh " + keycode_to_string.get(code, "[n/a]")
|
||
|
+ elif press == "kbfun_jump_to_bootloader":
|
||
|
+ replace = "[btldr]"
|
||
|
+ elif press == "NULL" and release == "NULL":
|
||
|
+ replace = "(null)"
|
||
|
+ elif re.search(r"numpad", press + release):
|
||
|
+ replace = "[num]"
|
||
|
+ elif re.search(r"layer", press + release):
|
||
|
+ replace = "la " + re.findall(r"\d+", press + release)[0] + " "
|
||
|
+ if re.search(r"push", press + release):
|
||
|
+ replace += "+"
|
||
|
+ if re.search(r"pop", press + release):
|
||
|
+ replace += "-"
|
||
|
+ replace += " " + str(code)
|
||
|
+ else:
|
||
|
+ replace = keycode_to_string.get(code, "[n/a]")
|
||
|
+
|
||
|
+ svg = re.sub(">" + name + "<", ">" + replace + "<", svg)
|
||
|
+ svg = re.sub(
|
||
|
+ r"\('(" + name + r".*)'\)", r"('\1', " + str(layer) + r")", svg
|
||
|
+ )
|
||
|
+
|
||
|
+ doc.main += "<h2>Layer " + str(layer_number) + "</h2>\n" + svg
|
||
|
+
|
||
|
+ # change the font size
|
||
|
+ doc.main = re.sub(r"22.5px", "15px", doc.main)
|
||
|
+
|
||
|
+ print(doc.prefix + doc.main + doc.suffix)
|
||
|
+
|
||
|
|
||
|
# -----------------------------------------------------------------------------
|
||
|
# -----------------------------------------------------------------------------
|
||
|
|
||
|
keycode_to_string = {
|
||
|
- 0x01: "Error", # ErrorRollOver
|
||
|
- 0x02: "POSTFail",
|
||
|
- 0x03: "Error", # ErrorUndefined
|
||
|
- 0x04: "a A",
|
||
|
- 0x05: "b B",
|
||
|
- 0x06: "c C",
|
||
|
- 0x07: "d D",
|
||
|
- 0x08: "e E",
|
||
|
- 0x09: "f F",
|
||
|
- 0x0A: "g G",
|
||
|
- 0x0B: "h H",
|
||
|
- 0x0C: "i I",
|
||
|
- 0x0D: "j J",
|
||
|
- 0x0E: "k K",
|
||
|
- 0x0F: "l L",
|
||
|
- 0x10: "m M",
|
||
|
- 0x11: "n N",
|
||
|
- 0x12: "o O",
|
||
|
- 0x13: "p P",
|
||
|
- 0x14: "q Q",
|
||
|
- 0x15: "r R",
|
||
|
- 0x16: "s S",
|
||
|
- 0x17: "t T",
|
||
|
- 0x18: "u U",
|
||
|
- 0x19: "v V",
|
||
|
- 0x1A: "w W",
|
||
|
- 0x1B: "x X",
|
||
|
- 0x1C: "y Y",
|
||
|
- 0x1D: "z Z",
|
||
|
- 0x1E: "1 !",
|
||
|
- 0x1F: "2 @",
|
||
|
- 0x20: "3 #",
|
||
|
- 0x21: "4 $",
|
||
|
- 0x22: "5 %",
|
||
|
- 0x23: "6 ^",
|
||
|
- 0x24: "7 &",
|
||
|
- 0x25: "8 *",
|
||
|
- 0x26: "9 (",
|
||
|
- 0x27: "0 )",
|
||
|
- 0x28: "Return",
|
||
|
- 0x29: "Esc",
|
||
|
- 0x2A: "Backspace",
|
||
|
- 0x2B: "Tab",
|
||
|
- 0x2C: "Space",
|
||
|
- 0x2D: "- _",
|
||
|
- 0x2E: "= +",
|
||
|
- 0x2F: "[ {",
|
||
|
- 0x30: "] }",
|
||
|
- 0x31: "\ |",
|
||
|
- 0x32: "# ~",
|
||
|
- 0x33: "; :",
|
||
|
- 0x34: "\' \"",
|
||
|
- 0x35: "` ~",
|
||
|
- 0x36: ", <",
|
||
|
- 0x37: ". >",
|
||
|
- 0x38: "/ ?",
|
||
|
- 0x39: "Caps",
|
||
|
- 0x3A: "F1",
|
||
|
- 0x3B: "F2",
|
||
|
- 0x3C: "F3",
|
||
|
- 0x3D: "F4",
|
||
|
- 0x3E: "F5",
|
||
|
- 0x3F: "F6",
|
||
|
- 0x40: "F7",
|
||
|
- 0x41: "F8",
|
||
|
- 0x42: "F9",
|
||
|
- 0x43: "F10",
|
||
|
- 0x44: "F11",
|
||
|
- 0x45: "F12",
|
||
|
- 0x46: "PrintScreen",
|
||
|
- 0x47: "ScrollLock",
|
||
|
- 0x48: "Pause",
|
||
|
- 0x49: "Ins", # Insert
|
||
|
- 0x4A: "Hm", # Home
|
||
|
- 0x4B: "Pg\u2191", # up arrow
|
||
|
- 0x4C: "Delete",
|
||
|
- 0x4D: "End",
|
||
|
- 0x4E: "Pg\u2193", # down arrow
|
||
|
- 0x4F: "\u2192", # right arrow
|
||
|
- 0x50: "\u2190", # left arrow
|
||
|
- 0x51: "\u2193", # down arrow
|
||
|
- 0x52: "\u2191", # up arrow
|
||
|
-
|
||
|
- 0x53: "Num",
|
||
|
- 0x54: "/",
|
||
|
- 0x55: "*",
|
||
|
- 0x56: "-",
|
||
|
- 0x57: "+",
|
||
|
- 0x58: "Enter",
|
||
|
- 0x59: "1 End",
|
||
|
- 0x5A: "2 \u2193", # down arrow
|
||
|
- 0x5B: "3 Pg\u2193", # down arrow
|
||
|
- 0x5C: "4 \u2190", # left arrow
|
||
|
- 0x5D: "5",
|
||
|
- 0x5E: "6 \u2192", # right arrow
|
||
|
- 0x5F: "7 Hm", # Home
|
||
|
- 0x60: "8 \u2191", # up arrow
|
||
|
- 0x61: "9 Pg\u2191", # up arrow
|
||
|
- 0x62: "0 Ins", # Insert
|
||
|
- 0x63: ". Del",
|
||
|
-
|
||
|
- 0x64: "\ |",
|
||
|
- 0x65: "App",
|
||
|
- 0x66: "Power",
|
||
|
-
|
||
|
- 0x67: "=",
|
||
|
-
|
||
|
- 0x68: "F13",
|
||
|
- 0x69: "F14",
|
||
|
- 0x6A: "F15",
|
||
|
- 0x6B: "F16",
|
||
|
- 0x6C: "F17",
|
||
|
- 0x6D: "F18",
|
||
|
- 0x6E: "F19",
|
||
|
- 0x6F: "F20",
|
||
|
- 0x70: "F21",
|
||
|
- 0x71: "F22",
|
||
|
- 0x72: "F23",
|
||
|
- 0x73: "F24",
|
||
|
- 0x74: "Exec",
|
||
|
- 0x75: "Help",
|
||
|
- 0x76: "Menu",
|
||
|
- 0x77: "Select",
|
||
|
- 0x78: "Stop",
|
||
|
- 0x79: "Again",
|
||
|
- 0x7A: "Undo",
|
||
|
- 0x7B: "Cut",
|
||
|
- 0x7C: "Copy",
|
||
|
- 0x7D: "Paste",
|
||
|
- 0x7E: "Find",
|
||
|
- 0x7F: "Mute",
|
||
|
- 0x80: "VolUp",
|
||
|
- 0x81: "VolDown",
|
||
|
- 0x82: "LockingCapsLock",
|
||
|
- 0x83: "LockingNumLock",
|
||
|
- 0x84: "LockingScrollLock",
|
||
|
-
|
||
|
- 0x85: ",",
|
||
|
- 0x86: "=",
|
||
|
-
|
||
|
- 0x87: "Int1",
|
||
|
- 0x88: "Int2",
|
||
|
- 0x89: "Int3",
|
||
|
- 0x8A: "Int4",
|
||
|
- 0x8B: "Int5",
|
||
|
- 0x8C: "Int6",
|
||
|
- 0x8D: "Int7",
|
||
|
- 0x8E: "Int8",
|
||
|
- 0x8F: "Int9",
|
||
|
- 0x90: "LANG1",
|
||
|
- 0x91: "LANG2",
|
||
|
- 0x92: "LANG3",
|
||
|
- 0x93: "LANG4",
|
||
|
- 0x94: "LANG5",
|
||
|
- 0x95: "LANG6",
|
||
|
- 0x96: "LANG7",
|
||
|
- 0x97: "LANG8",
|
||
|
- 0x98: "LANG9",
|
||
|
- 0x99: "AlternateErase",
|
||
|
- 0x9A: "SysReq_Attention",
|
||
|
- 0x9B: "Cancel",
|
||
|
- 0x9C: "Clear",
|
||
|
- 0x9D: "Prior",
|
||
|
- 0x9E: "Return",
|
||
|
- 0x9F: "Separator",
|
||
|
- 0xA0: "Out",
|
||
|
- 0xA1: "Oper",
|
||
|
- 0xA2: "Clear_Again",
|
||
|
- 0xA3: "CrSel_Props",
|
||
|
- 0xA4: "ExSel",
|
||
|
-
|
||
|
- 0xB0: "00",
|
||
|
- 0xB1: "000",
|
||
|
-
|
||
|
- 0xB2: "Thousands_Sep",
|
||
|
- 0xB3: "Decimal_Sep",
|
||
|
- 0xB4: "$",
|
||
|
- 0xB5: "Currency_Subunit",
|
||
|
-
|
||
|
- 0xB6: "(",
|
||
|
- 0xB7: ")",
|
||
|
- 0xB8: "{",
|
||
|
- 0xB9: "}",
|
||
|
-
|
||
|
- 0xBA: "Tab",
|
||
|
- 0xBB: "Backspace",
|
||
|
- 0xBC: "A",
|
||
|
- 0xBD: "B",
|
||
|
- 0xBE: "C",
|
||
|
- 0xBF: "D",
|
||
|
- 0xC0: "E",
|
||
|
- 0xC1: "F",
|
||
|
- 0xC2: "XOR",
|
||
|
- 0xC3: "^",
|
||
|
- 0xC4: "%",
|
||
|
- 0xC5: "<",
|
||
|
- 0xC6: ">",
|
||
|
- 0xC7: "&",
|
||
|
- 0xC8: "&&",
|
||
|
- 0xC9: "|",
|
||
|
- 0xCA: "||",
|
||
|
- 0xCB: ":",
|
||
|
- 0xCC: "#",
|
||
|
- 0xCD: "Space",
|
||
|
- 0xCE: "@",
|
||
|
- 0xCF: "!",
|
||
|
- 0xD0: "Mem_Store",
|
||
|
- 0xD1: "Mem_Recall",
|
||
|
- 0xD2: "Mem_Clear",
|
||
|
- 0xD3: "Mem_+",
|
||
|
- 0xD4: "Mem_-",
|
||
|
- 0xD5: "Mem_*",
|
||
|
- 0xD6: "Mem_/",
|
||
|
- 0xD7: "+-",
|
||
|
- 0xD8: "Clear",
|
||
|
- 0xD9: "ClearEntry",
|
||
|
- 0xDA: "Binary",
|
||
|
- 0xDB: "Octal",
|
||
|
- 0xDC: ".",
|
||
|
- 0xDD: "Hexadecimal",
|
||
|
-
|
||
|
- 0xE0: "L-Ctrl",
|
||
|
- 0xE1: "L-Shift",
|
||
|
- 0xE2: "L-Alt",
|
||
|
- 0xE3: "L-GUI",
|
||
|
- 0xE4: "R-Ctrl",
|
||
|
- 0xE5: "R-Shift",
|
||
|
- 0xE6: "R-Alt",
|
||
|
- 0xE7: "R-GUI",
|
||
|
- }
|
||
|
+ 0x01: "Error", # ErrorRollOver
|
||
|
+ 0x02: "POSTFail",
|
||
|
+ 0x03: "Error", # ErrorUndefined
|
||
|
+ 0x04: "a A",
|
||
|
+ 0x05: "b B",
|
||
|
+ 0x06: "c C",
|
||
|
+ 0x07: "d D",
|
||
|
+ 0x08: "e E",
|
||
|
+ 0x09: "f F",
|
||
|
+ 0x0A: "g G",
|
||
|
+ 0x0B: "h H",
|
||
|
+ 0x0C: "i I",
|
||
|
+ 0x0D: "j J",
|
||
|
+ 0x0E: "k K",
|
||
|
+ 0x0F: "l L",
|
||
|
+ 0x10: "m M",
|
||
|
+ 0x11: "n N",
|
||
|
+ 0x12: "o O",
|
||
|
+ 0x13: "p P",
|
||
|
+ 0x14: "q Q",
|
||
|
+ 0x15: "r R",
|
||
|
+ 0x16: "s S",
|
||
|
+ 0x17: "t T",
|
||
|
+ 0x18: "u U",
|
||
|
+ 0x19: "v V",
|
||
|
+ 0x1A: "w W",
|
||
|
+ 0x1B: "x X",
|
||
|
+ 0x1C: "y Y",
|
||
|
+ 0x1D: "z Z",
|
||
|
+ 0x1E: "1 !",
|
||
|
+ 0x1F: "2 @",
|
||
|
+ 0x20: "3 #",
|
||
|
+ 0x21: "4 $",
|
||
|
+ 0x22: "5 %",
|
||
|
+ 0x23: "6 ^",
|
||
|
+ 0x24: "7 &",
|
||
|
+ 0x25: "8 *",
|
||
|
+ 0x26: "9 (",
|
||
|
+ 0x27: "0 )",
|
||
|
+ 0x28: "Return",
|
||
|
+ 0x29: "Esc",
|
||
|
+ 0x2A: "Backspace",
|
||
|
+ 0x2B: "Tab",
|
||
|
+ 0x2C: "Space",
|
||
|
+ 0x2D: "- _",
|
||
|
+ 0x2E: "= +",
|
||
|
+ 0x2F: "[ {",
|
||
|
+ 0x30: "] }",
|
||
|
+ 0x31: "\ |",
|
||
|
+ 0x32: "# ~",
|
||
|
+ 0x33: "; :",
|
||
|
+ 0x34: "' \"",
|
||
|
+ 0x35: "` ~",
|
||
|
+ 0x36: ", <",
|
||
|
+ 0x37: ". >",
|
||
|
+ 0x38: "/ ?",
|
||
|
+ 0x39: "Caps",
|
||
|
+ 0x3A: "F1",
|
||
|
+ 0x3B: "F2",
|
||
|
+ 0x3C: "F3",
|
||
|
+ 0x3D: "F4",
|
||
|
+ 0x3E: "F5",
|
||
|
+ 0x3F: "F6",
|
||
|
+ 0x40: "F7",
|
||
|
+ 0x41: "F8",
|
||
|
+ 0x42: "F9",
|
||
|
+ 0x43: "F10",
|
||
|
+ 0x44: "F11",
|
||
|
+ 0x45: "F12",
|
||
|
+ 0x46: "PrintScreen",
|
||
|
+ 0x47: "ScrollLock",
|
||
|
+ 0x48: "Pause",
|
||
|
+ 0x49: "Ins", # Insert
|
||
|
+ 0x4A: "Hm", # Home
|
||
|
+ 0x4B: "Pg\u2191", # up arrow
|
||
|
+ 0x4C: "Delete",
|
||
|
+ 0x4D: "End",
|
||
|
+ 0x4E: "Pg\u2193", # down arrow
|
||
|
+ 0x4F: "\u2192", # right arrow
|
||
|
+ 0x50: "\u2190", # left arrow
|
||
|
+ 0x51: "\u2193", # down arrow
|
||
|
+ 0x52: "\u2191", # up arrow
|
||
|
+ 0x53: "Num",
|
||
|
+ 0x54: "/",
|
||
|
+ 0x55: "*",
|
||
|
+ 0x56: "-",
|
||
|
+ 0x57: "+",
|
||
|
+ 0x58: "Enter",
|
||
|
+ 0x59: "1 End",
|
||
|
+ 0x5A: "2 \u2193", # down arrow
|
||
|
+ 0x5B: "3 Pg\u2193", # down arrow
|
||
|
+ 0x5C: "4 \u2190", # left arrow
|
||
|
+ 0x5D: "5",
|
||
|
+ 0x5E: "6 \u2192", # right arrow
|
||
|
+ 0x5F: "7 Hm", # Home
|
||
|
+ 0x60: "8 \u2191", # up arrow
|
||
|
+ 0x61: "9 Pg\u2191", # up arrow
|
||
|
+ 0x62: "0 Ins", # Insert
|
||
|
+ 0x63: ". Del",
|
||
|
+ 0x64: "\ |",
|
||
|
+ 0x65: "App",
|
||
|
+ 0x66: "Power",
|
||
|
+ 0x67: "=",
|
||
|
+ 0x68: "F13",
|
||
|
+ 0x69: "F14",
|
||
|
+ 0x6A: "F15",
|
||
|
+ 0x6B: "F16",
|
||
|
+ 0x6C: "F17",
|
||
|
+ 0x6D: "F18",
|
||
|
+ 0x6E: "F19",
|
||
|
+ 0x6F: "F20",
|
||
|
+ 0x70: "F21",
|
||
|
+ 0x71: "F22",
|
||
|
+ 0x72: "F23",
|
||
|
+ 0x73: "F24",
|
||
|
+ 0x74: "Exec",
|
||
|
+ 0x75: "Help",
|
||
|
+ 0x76: "Menu",
|
||
|
+ 0x77: "Select",
|
||
|
+ 0x78: "Stop",
|
||
|
+ 0x79: "Again",
|
||
|
+ 0x7A: "Undo",
|
||
|
+ 0x7B: "Cut",
|
||
|
+ 0x7C: "Copy",
|
||
|
+ 0x7D: "Paste",
|
||
|
+ 0x7E: "Find",
|
||
|
+ 0x7F: "Mute",
|
||
|
+ 0x80: "VolUp",
|
||
|
+ 0x81: "VolDown",
|
||
|
+ 0x82: "LockingCapsLock",
|
||
|
+ 0x83: "LockingNumLock",
|
||
|
+ 0x84: "LockingScrollLock",
|
||
|
+ 0x85: ",",
|
||
|
+ 0x86: "=",
|
||
|
+ 0x87: "Int1",
|
||
|
+ 0x88: "Int2",
|
||
|
+ 0x89: "Int3",
|
||
|
+ 0x8A: "Int4",
|
||
|
+ 0x8B: "Int5",
|
||
|
+ 0x8C: "Int6",
|
||
|
+ 0x8D: "Int7",
|
||
|
+ 0x8E: "Int8",
|
||
|
+ 0x8F: "Int9",
|
||
|
+ 0x90: "LANG1",
|
||
|
+ 0x91: "LANG2",
|
||
|
+ 0x92: "LANG3",
|
||
|
+ 0x93: "LANG4",
|
||
|
+ 0x94: "LANG5",
|
||
|
+ 0x95: "LANG6",
|
||
|
+ 0x96: "LANG7",
|
||
|
+ 0x97: "LANG8",
|
||
|
+ 0x98: "LANG9",
|
||
|
+ 0x99: "AlternateErase",
|
||
|
+ 0x9A: "SysReq_Attention",
|
||
|
+ 0x9B: "Cancel",
|
||
|
+ 0x9C: "Clear",
|
||
|
+ 0x9D: "Prior",
|
||
|
+ 0x9E: "Return",
|
||
|
+ 0x9F: "Separator",
|
||
|
+ 0xA0: "Out",
|
||
|
+ 0xA1: "Oper",
|
||
|
+ 0xA2: "Clear_Again",
|
||
|
+ 0xA3: "CrSel_Props",
|
||
|
+ 0xA4: "ExSel",
|
||
|
+ 0xB0: "00",
|
||
|
+ 0xB1: "000",
|
||
|
+ 0xB2: "Thousands_Sep",
|
||
|
+ 0xB3: "Decimal_Sep",
|
||
|
+ 0xB4: "$",
|
||
|
+ 0xB5: "Currency_Subunit",
|
||
|
+ 0xB6: "(",
|
||
|
+ 0xB7: ")",
|
||
|
+ 0xB8: "{",
|
||
|
+ 0xB9: "}",
|
||
|
+ 0xBA: "Tab",
|
||
|
+ 0xBB: "Backspace",
|
||
|
+ 0xBC: "A",
|
||
|
+ 0xBD: "B",
|
||
|
+ 0xBE: "C",
|
||
|
+ 0xBF: "D",
|
||
|
+ 0xC0: "E",
|
||
|
+ 0xC1: "F",
|
||
|
+ 0xC2: "XOR",
|
||
|
+ 0xC3: "^",
|
||
|
+ 0xC4: "%",
|
||
|
+ 0xC5: "<",
|
||
|
+ 0xC6: ">",
|
||
|
+ 0xC7: "&",
|
||
|
+ 0xC8: "&&",
|
||
|
+ 0xC9: "|",
|
||
|
+ 0xCA: "||",
|
||
|
+ 0xCB: ":",
|
||
|
+ 0xCC: "#",
|
||
|
+ 0xCD: "Space",
|
||
|
+ 0xCE: "@",
|
||
|
+ 0xCF: "!",
|
||
|
+ 0xD0: "Mem_Store",
|
||
|
+ 0xD1: "Mem_Recall",
|
||
|
+ 0xD2: "Mem_Clear",
|
||
|
+ 0xD3: "Mem_+",
|
||
|
+ 0xD4: "Mem_-",
|
||
|
+ 0xD5: "Mem_*",
|
||
|
+ 0xD6: "Mem_/",
|
||
|
+ 0xD7: "+-",
|
||
|
+ 0xD8: "Clear",
|
||
|
+ 0xD9: "ClearEntry",
|
||
|
+ 0xDA: "Binary",
|
||
|
+ 0xDB: "Octal",
|
||
|
+ 0xDC: ".",
|
||
|
+ 0xDD: "Hexadecimal",
|
||
|
+ 0xE0: "L-Ctrl",
|
||
|
+ 0xE1: "L-Shift",
|
||
|
+ 0xE2: "L-Alt",
|
||
|
+ 0xE3: "L-GUI",
|
||
|
+ 0xE4: "R-Ctrl",
|
||
|
+ 0xE5: "R-Shift",
|
||
|
+ 0xE6: "R-Alt",
|
||
|
+ 0xE7: "R-GUI",
|
||
|
+}
|
||
|
|
||
|
# -----------------------------------------------------------------------------
|
||
|
# -----------------------------------------------------------------------------
|
||
|
|
||
|
-if __name__ == '__main__':
|
||
|
- main()
|
||
|
-
|
||
|
+if __name__ == "__main__":
|
||
|
+ main()
|
||
|
diff --git a/build-scripts/gen-ui-info.py b/build-scripts/gen-ui-info.py
|
||
|
index 1c93d32..0fa52e3 100755
|
||
|
--- a/build-scripts/gen-ui-info.py
|
||
|
+++ b/build-scripts/gen-ui-info.py
|
||
|
@@ -13,7 +13,16 @@ Depends on:
|
||
|
- the project '.map' file (generated by the compiler)
|
||
|
"""
|
||
|
|
||
|
-_FORMAT_DESCRIPTION = ("""
|
||
|
+import argparse
|
||
|
+import json
|
||
|
+import os
|
||
|
+import pathlib
|
||
|
+import re
|
||
|
+import subprocess
|
||
|
+import sys
|
||
|
+
|
||
|
+_FORMAT_DESCRIPTION = (
|
||
|
+ """
|
||
|
/* ----------------------------------------------------------------------------
|
||
|
* Version 0
|
||
|
* ----------------------------------------------------------------------------
|
||
|
@@ -31,7 +40,7 @@ var ui_info = {
|
||
|
".meta-data": { // for the JSON file
|
||
|
"version": "<number>",
|
||
|
"date-generated": "<string>", // format: RFC 3339
|
||
|
- "description": "<string>",
|
||
|
+ "description": "<string>",
|
||
|
},
|
||
|
"keyboard-functions": {
|
||
|
"<(function name)>": {
|
||
|
@@ -57,7 +66,7 @@ var ui_info = {
|
||
|
"..."
|
||
|
},
|
||
|
"mappings": {
|
||
|
- /*
|
||
|
+ /*
|
||
|
* The mappings prefixed with 'matrix' have their elements in the same
|
||
|
* order as the .hex file (whatever order that is). The mappings
|
||
|
* prefixed with 'physical' will have their elements in an order
|
||
|
@@ -113,365 +122,304 @@ var ui_info = {
|
||
|
"number-of-layers": "<number>"
|
||
|
}
|
||
|
}
|
||
|
-""")[1:-1]
|
||
|
+"""
|
||
|
+)[1:-1]
|
||
|
|
||
|
# -----------------------------------------------------------------------------
|
||
|
|
||
|
-import argparse
|
||
|
-import json
|
||
|
-import os
|
||
|
-import re
|
||
|
-import subprocess
|
||
|
-import sys
|
||
|
-
|
||
|
-# -----------------------------------------------------------------------------
|
||
|
|
||
|
def gen_static(current_date=None, git_commit_date=None, git_commit_id=None):
|
||
|
- """Generate static information"""
|
||
|
-
|
||
|
- return {
|
||
|
- '.meta-data': {
|
||
|
- 'version': 0, # the format version number
|
||
|
- 'date-generated': current_date,
|
||
|
- 'description': _FORMAT_DESCRIPTION,
|
||
|
- },
|
||
|
- 'miscellaneous': {
|
||
|
- 'git-commit-date': git_commit_date, # should be passed by makefile
|
||
|
- 'git-commit-id': git_commit_id, # should be passed by makefile
|
||
|
- },
|
||
|
- }
|
||
|
-
|
||
|
-def gen_derived(data):
|
||
|
- return {} # don't really need this info anymore
|
||
|
-# """
|
||
|
-# Generate derived information
|
||
|
-# Should be called last
|
||
|
-# """
|
||
|
-# return {
|
||
|
-# 'miscellaneous': {
|
||
|
-# 'number-of-layers':
|
||
|
-# int( data['layout-matrices']['_kb_layout']['length']/(6*14) ),
|
||
|
-# # because 6*14 is the number of bytes/layer for '_kb_layout'
|
||
|
-# # (which is a uint8_t matrix)
|
||
|
-# },
|
||
|
-# }
|
||
|
-
|
||
|
-# -----------------------------------------------------------------------------
|
||
|
+ """Generate static information"""
|
||
|
|
||
|
-def parse_mapfile(map_file_path):
|
||
|
- return {} # don't really need this info anymore
|
||
|
-# """Parse the '.map' file"""
|
||
|
-#
|
||
|
-# def parse_keyboard_function(f, line):
|
||
|
-# """Parse keyboard-functions in the '.map' file"""
|
||
|
-#
|
||
|
-# search = re.search(r'(0x\S+)\s+(0x\S+)', next(f))
|
||
|
-# position = int( search.group(1), 16 )
|
||
|
-# length = int( search.group(2), 16 )
|
||
|
-#
|
||
|
-# search = re.search(r'0x\S+\s+(\S+)', next(f))
|
||
|
-# name = search.group(1)
|
||
|
-#
|
||
|
-# return {
|
||
|
-# 'keyboard-functions': {
|
||
|
-# name: {
|
||
|
-# 'position': position,
|
||
|
-# 'length': length,
|
||
|
-# },
|
||
|
-# },
|
||
|
-# }
|
||
|
-#
|
||
|
-# def parse_layout_matrices(f, line):
|
||
|
-# """Parse layout matrix information in the '.map' file"""
|
||
|
-#
|
||
|
-# name = re.search(r'.progmem.data.(_kb_layout\S*)', line).group(1)
|
||
|
-#
|
||
|
-# search = re.search(r'(0x\S+)\s+(0x\S+)', next(f))
|
||
|
-# position = int( search.group(1), 16 )
|
||
|
-# length = int( search.group(2), 16 )
|
||
|
-#
|
||
|
-# return {
|
||
|
-# 'layout-matrices': {
|
||
|
-# name: {
|
||
|
-# 'position': position,
|
||
|
-# 'length': length,
|
||
|
-# },
|
||
|
-# },
|
||
|
-# }
|
||
|
-#
|
||
|
-# # --- parse_mapfile() ---
|
||
|
-#
|
||
|
-# # normalize paths
|
||
|
-# map_file_path = os.path.abspath(map_file_path)
|
||
|
-# # check paths
|
||
|
-# if not os.path.exists(map_file_path):
|
||
|
-# raise ValueError("invalid 'map_file_path' given")
|
||
|
-#
|
||
|
-# output = {}
|
||
|
-#
|
||
|
-# f = open(map_file_path)
|
||
|
-#
|
||
|
-# for line in f:
|
||
|
-# if re.search(r'^\s*\.text\.kbfun_', line):
|
||
|
-# dict_merge(output, parse_keyboard_function(f, line))
|
||
|
-# elif re.search(r'^\s*\.progmem\.data.*layout', line):
|
||
|
-# dict_merge(output, parse_layout_matrices(f, line))
|
||
|
-#
|
||
|
-# return output
|
||
|
+ return {
|
||
|
+ ".meta-data": {
|
||
|
+ "version": 0, # the format version number
|
||
|
+ "date-generated": current_date,
|
||
|
+ "description": _FORMAT_DESCRIPTION,
|
||
|
+ },
|
||
|
+ "miscellaneous": {
|
||
|
+ "git-commit-date": git_commit_date, # should be passed by makefile
|
||
|
+ "git-commit-id": git_commit_id, # should be passed by makefile
|
||
|
+ },
|
||
|
+ }
|
||
|
|
||
|
|
||
|
def find_keyboard_functions(source_code_path):
|
||
|
- """Parse all files in the source directory"""
|
||
|
-
|
||
|
- def read_comments(f, line):
|
||
|
- """
|
||
|
- Read in properly formatted multi-line comments
|
||
|
- - Comments must start with '/*' and end with '*/', each on their own
|
||
|
- line
|
||
|
- """
|
||
|
- comments = ''
|
||
|
- while(line.strip() != r'*/'):
|
||
|
- comments += line[2:].strip()+'\n'
|
||
|
- line = next(f)
|
||
|
- return comments
|
||
|
-
|
||
|
- def parse_comments(comments):
|
||
|
- """
|
||
|
- Parse an INI style comment string
|
||
|
- - Fields begin with '[field-name]', and continue until the next field,
|
||
|
- or the end of the comment
|
||
|
- - Fields '[name]', '[description]', and '[note]' are treated specially
|
||
|
- """
|
||
|
-
|
||
|
- def add_field(output, field, value):
|
||
|
- """Put a field+value pair in 'output', the way we want it, if the
|
||
|
- pair is valid"""
|
||
|
-
|
||
|
- value = value.strip()
|
||
|
-
|
||
|
- if field is not None:
|
||
|
- if field in ('name', 'description'):
|
||
|
- if field not in output:
|
||
|
- output[field] = value
|
||
|
- else:
|
||
|
- if field == 'note':
|
||
|
- field = 'notes'
|
||
|
-
|
||
|
- if field not in output:
|
||
|
- output[field] = []
|
||
|
-
|
||
|
- output[field] += [value]
|
||
|
-
|
||
|
- # --- parse_comments() ---
|
||
|
-
|
||
|
- output = {}
|
||
|
-
|
||
|
- field = None
|
||
|
- value = None
|
||
|
- for line in comments.split('\n'):
|
||
|
- line = line.strip()
|
||
|
-
|
||
|
- if re.search(r'^\[.*\]$', line):
|
||
|
- add_field(output, field, value)
|
||
|
- field = line[1:-1]
|
||
|
- value = None
|
||
|
-
|
||
|
- else:
|
||
|
- if value is None:
|
||
|
- value = ''
|
||
|
- if len(value) > 0 and value[-1] == '.':
|
||
|
- line = ' '+line
|
||
|
- value += ' '+line
|
||
|
-
|
||
|
- add_field(output, field, value)
|
||
|
-
|
||
|
- return output
|
||
|
-
|
||
|
- def parse_keyboard_function(f, line, comments):
|
||
|
- """Parse keyboard-functions in the source code"""
|
||
|
-
|
||
|
- search = re.search(r'void\s+(kbfun_\S+)\s*\(void\)', line)
|
||
|
- name = search.group(1)
|
||
|
-
|
||
|
- return {
|
||
|
- 'keyboard-functions': {
|
||
|
- name: {
|
||
|
- 'comments': parse_comments(comments),
|
||
|
- },
|
||
|
- },
|
||
|
- }
|
||
|
-
|
||
|
- # --- find_keyboard_functions() ---
|
||
|
-
|
||
|
- # normalize paths
|
||
|
- source_code_path = os.path.abspath(source_code_path)
|
||
|
- # check paths
|
||
|
- if not os.path.exists(source_code_path):
|
||
|
- raise ValueError("invalid 'source_code_path' given")
|
||
|
-
|
||
|
- output = {}
|
||
|
-
|
||
|
- for tup in os.walk(source_code_path):
|
||
|
- for file_name in tup[2]:
|
||
|
- # normalize paths
|
||
|
- file_name = os.path.abspath( os.path.join( tup[0], file_name ) )
|
||
|
-
|
||
|
- # ignore non '.c' files
|
||
|
- if file_name[-2:] != '.c':
|
||
|
- continue
|
||
|
-
|
||
|
- f = open(file_name)
|
||
|
-
|
||
|
- comments = ''
|
||
|
- for line in f:
|
||
|
- if line.strip() == r'/*':
|
||
|
- comments = read_comments(f, line)
|
||
|
- elif re.search(r'void\s+kbfun_\S+\s*\(void\)', line):
|
||
|
- dict_merge(
|
||
|
- output,
|
||
|
- parse_keyboard_function(f, line, comments) )
|
||
|
-
|
||
|
- return output
|
||
|
+ """Parse all files in the source directory"""
|
||
|
+
|
||
|
+ def read_comments(f, line):
|
||
|
+ """
|
||
|
+ Read in properly formatted multi-line comments
|
||
|
+ - Comments must start with '/*' and end with '*/', each on their own
|
||
|
+ line
|
||
|
+ """
|
||
|
+ comments = ""
|
||
|
+ while line.strip() != r"*/":
|
||
|
+ comments += line[2:].strip() + "\n"
|
||
|
+ line = next(f)
|
||
|
+ return comments
|
||
|
+
|
||
|
+ def parse_comments(comments):
|
||
|
+ """
|
||
|
+ Parse an INI style comment string
|
||
|
+ - Fields begin with '[field-name]', and continue until the next field,
|
||
|
+ or the end of the comment
|
||
|
+ - Fields '[name]', '[description]', and '[note]' are treated specially
|
||
|
+ """
|
||
|
+
|
||
|
+ def add_field(output, field, value):
|
||
|
+ """Put a field+value pair in 'output', the way we want it, if the
|
||
|
+ pair is valid"""
|
||
|
+
|
||
|
+ value = value.strip()
|
||
|
+
|
||
|
+ if field is not None:
|
||
|
+ if field in ("name", "description"):
|
||
|
+ if field not in output:
|
||
|
+ output[field] = value
|
||
|
+ else:
|
||
|
+ if field == "note":
|
||
|
+ field = "notes"
|
||
|
+
|
||
|
+ if field not in output:
|
||
|
+ output[field] = []
|
||
|
+
|
||
|
+ output[field] += [value]
|
||
|
+
|
||
|
+ # --- parse_comments() ---
|
||
|
+
|
||
|
+ output = {}
|
||
|
+
|
||
|
+ field = None
|
||
|
+ value = None
|
||
|
+ for line in comments.split("\n"):
|
||
|
+ line = line.strip()
|
||
|
+
|
||
|
+ if re.search(r"^\[.*\]$", line):
|
||
|
+ add_field(output, field, value)
|
||
|
+ field = line[1:-1]
|
||
|
+ value = None
|
||
|
+ else:
|
||
|
+ if value is None:
|
||
|
+ value = ""
|
||
|
+ if len(value) > 0 and value[-1] == ".":
|
||
|
+ line = " " + line
|
||
|
+ value += " " + line
|
||
|
+
|
||
|
+ add_field(output, field, value)
|
||
|
+
|
||
|
+ return output
|
||
|
+
|
||
|
+ def parse_keyboard_function(f, line, comments):
|
||
|
+ """Parse keyboard-functions in the source code"""
|
||
|
+
|
||
|
+ search = re.search(r"void\s+(kbfun_\S+)\s*\(void\)", line)
|
||
|
+ name = search.group(1)
|
||
|
+
|
||
|
+ return {
|
||
|
+ "keyboard-functions": {
|
||
|
+ name: {
|
||
|
+ "comments": parse_comments(comments),
|
||
|
+ },
|
||
|
+ },
|
||
|
+ }
|
||
|
+
|
||
|
+ # --- find_keyboard_functions() ---
|
||
|
+
|
||
|
+ # normalize paths
|
||
|
+ source_code_path = os.path.abspath(source_code_path)
|
||
|
+ # check paths
|
||
|
+ if not os.path.exists(source_code_path):
|
||
|
+ raise ValueError("invalid 'source_code_path' given")
|
||
|
+
|
||
|
+ output = {}
|
||
|
+
|
||
|
+ for tup in os.walk(source_code_path):
|
||
|
+ for file_name in tup[2]:
|
||
|
+ # normalize paths
|
||
|
+ file_name = os.path.abspath(os.path.join(tup[0], file_name))
|
||
|
+
|
||
|
+ # ignore non '.c' files
|
||
|
+ if file_name[-2:] != ".c":
|
||
|
+ continue
|
||
|
+
|
||
|
+ f = open(file_name)
|
||
|
+
|
||
|
+ comments = ""
|
||
|
+ for line in f:
|
||
|
+ if line.strip() == r"/*":
|
||
|
+ comments = read_comments(f, line)
|
||
|
+ elif re.search(r"void\s+kbfun_\S+\s*\(void\)", line):
|
||
|
+ dict_merge(
|
||
|
+ output, parse_keyboard_function(f, line, comments)
|
||
|
+ )
|
||
|
+
|
||
|
+ return output
|
||
|
|
||
|
|
||
|
def gen_mappings(matrix_file_path, layout_file_path):
|
||
|
- # normalize paths
|
||
|
- matrix_file_path = os.path.abspath(matrix_file_path)
|
||
|
- layout_file_path = os.path.abspath(layout_file_path)
|
||
|
-
|
||
|
- def parse_matrix_file(matrix_file_path):
|
||
|
- match = re.search( # find the whole 'KB_MATRIX_LAYER' macro
|
||
|
- r'#define\s+KB_MATRIX_LAYER\s*\(([^)]+)\)[^{]*\{\{([^#]+)\}\}',
|
||
|
- open(matrix_file_path).read() )
|
||
|
-
|
||
|
- return {
|
||
|
- "mappings": {
|
||
|
- "physical-positions": re.findall(r'k..', match.group(1)),
|
||
|
- "matrix-positions": re.findall(r'k..|na', match.group(2)),
|
||
|
- },
|
||
|
- }
|
||
|
-
|
||
|
- def parse_layout_file(layout_file_path):
|
||
|
- match = re.findall( # find each whole '_kb_layout*' matrix definition
|
||
|
- r'(_kb_layout\w*)[^=]*=((?:[^{}]*\{){3}[^=]*(?:[^{}]*\}){3})',
|
||
|
- subprocess.getoutput("gcc -E '"+layout_file_path+"'") )
|
||
|
-
|
||
|
- layout = {}
|
||
|
- # collect all the values
|
||
|
- for (name, matrix) in match:
|
||
|
- layout[name] = [
|
||
|
- re.findall( # find all numbers and function pointers
|
||
|
- r'[x0-9A-F]+|&\w+|NULL',
|
||
|
- re.sub( # replace '((void *) 0)' with 'NULL'
|
||
|
- r'\(\s*\(\s*void\s*\*\s*\)\s*0\s*\)',
|
||
|
- 'NULL',
|
||
|
- el ) )
|
||
|
- for el in
|
||
|
- re.findall( # find each whole layer
|
||
|
- r'(?:[^{}]*\{){2}((?:[^}]|\}\s*,)+)(?:[^{}]*\}){2}',
|
||
|
- matrix ) ]
|
||
|
-
|
||
|
- # make the numbers into actual numbers
|
||
|
- layout['_kb_layout'] = \
|
||
|
- [[eval(el) for el in layer] for layer in layout['_kb_layout']]
|
||
|
- # remove the preceeding '&' from function pointers
|
||
|
- for matrix in ('_kb_layout_press', '_kb_layout_release'):
|
||
|
- layout[matrix] = \
|
||
|
- [ [re.sub(r'&', '', el) for el in layer]
|
||
|
- for layer in layout[matrix] ]
|
||
|
-
|
||
|
- return {
|
||
|
- "mappings": {
|
||
|
- "matrix-layout":
|
||
|
- # group them all properly
|
||
|
- [ [[c, p, r] for (c, p, r) in zip(code, press, release)]
|
||
|
- for (code, press, release) in
|
||
|
- zip( layout['_kb_layout'],
|
||
|
- layout['_kb_layout_press'],
|
||
|
- layout['_kb_layout_release'] ) ]
|
||
|
- },
|
||
|
- }
|
||
|
-
|
||
|
- return dict_merge(
|
||
|
- parse_matrix_file(matrix_file_path),
|
||
|
- parse_layout_file(layout_file_path) )
|
||
|
+ # normalize paths
|
||
|
+ matrix_file_path = os.path.abspath(matrix_file_path)
|
||
|
+ layout_file_path = os.path.abspath(layout_file_path)
|
||
|
+ layout_name = pathlib.Path(layout_file_path).with_suffix('').name
|
||
|
+
|
||
|
+ def parse_matrix_file(matrix_file_path):
|
||
|
+ match = re.search( # find the whole 'KB_MATRIX_LAYER' macro
|
||
|
+ r"#define\s+KB_MATRIX_LAYER\s*\(([^)]+)\)[^{]*\{\{([^#]+)\}\}",
|
||
|
+ open(matrix_file_path).read(),
|
||
|
+ )
|
||
|
+
|
||
|
+ return {
|
||
|
+ "mappings": {
|
||
|
+ "physical-positions": re.findall(r"k..", match.group(1)),
|
||
|
+ "matrix-positions": re.findall(r"k..|na", match.group(2)),
|
||
|
+ },
|
||
|
+ }
|
||
|
+
|
||
|
+ def parse_layout_file(layout_file_path):
|
||
|
+ output = subprocess.check_output(
|
||
|
+ ['avr-gcc', f'-DMAKEFILE_KEYBOARD_LAYOUT={layout_name}',
|
||
|
+ '-E', layout_file_path], encoding='UTF-8')
|
||
|
+ match = re.findall( # find each whole '_kb_layout*' matrix definition
|
||
|
+ r"(_kb_layout\w*)[^=]*=((?:[^{}]*\{){3}[^=]*(?:[^{}]*\}){3})",
|
||
|
+ output,
|
||
|
+ )
|
||
|
+
|
||
|
+ layout = {}
|
||
|
+ # collect all the values
|
||
|
+ for (name, matrix) in match:
|
||
|
+ layout[name] = [
|
||
|
+ re.findall( # find all numbers and function pointers
|
||
|
+ r"[x0-9A-F]+|&\w+|NULL",
|
||
|
+ re.sub( # replace '((void *) 0)' with 'NULL'
|
||
|
+ r"\(\s*\(\s*void\s*\*\s*\)\s*0\s*\)", "NULL", el
|
||
|
+ ),
|
||
|
+ )
|
||
|
+ for el in re.findall( # find each whole layer
|
||
|
+ r"(?:[^{}]*\{){2}((?:[^}]|\}\s*,)+)(?:[^{}]*\}){2}", matrix
|
||
|
+ )
|
||
|
+ ]
|
||
|
+
|
||
|
+ # make the numbers into actual numbers
|
||
|
+ layout["_kb_layout"] = [
|
||
|
+ [eval(el) for el in layer] for layer in layout["_kb_layout"]
|
||
|
+ ]
|
||
|
+ # remove the preceeding '&' from function pointers
|
||
|
+ for matrix in ("_kb_layout_press", "_kb_layout_release"):
|
||
|
+ layout[matrix] = [
|
||
|
+ [re.sub(r"&", "", el) for el in layer]
|
||
|
+ for layer in layout[matrix]
|
||
|
+ ]
|
||
|
+
|
||
|
+ return {
|
||
|
+ "mappings": {
|
||
|
+ "matrix-layout":
|
||
|
+ # group them all properly
|
||
|
+ [
|
||
|
+ [[c, p, r] for (c, p, r) in zip(code, press, release)]
|
||
|
+ for (code, press, release) in zip(
|
||
|
+ layout["_kb_layout"],
|
||
|
+ layout["_kb_layout_press"],
|
||
|
+ layout["_kb_layout_release"],
|
||
|
+ )
|
||
|
+ ]
|
||
|
+ },
|
||
|
+ }
|
||
|
+
|
||
|
+ return dict_merge(
|
||
|
+ parse_matrix_file(matrix_file_path),
|
||
|
+ parse_layout_file(layout_file_path),
|
||
|
+ )
|
||
|
|
||
|
|
||
|
# -----------------------------------------------------------------------------
|
||
|
|
||
|
+
|
||
|
def dict_merge(a, b):
|
||
|
- """
|
||
|
- Recursively merge two dictionaries
|
||
|
- - I was looking around for an easy way to do this, and found something
|
||
|
- [here]
|
||
|
- (http://www.xormedia.com/recursively-merge-dictionaries-in-python.html).
|
||
|
- This is pretty close, but i didn't copy it exactly.
|
||
|
- """
|
||
|
+ """
|
||
|
+ Recursively merge two dictionaries
|
||
|
+ - I was looking around for an easy way to do this, and found something
|
||
|
+ [here]
|
||
|
+ (http://www.xormedia.com/recursively-merge-dictionaries-in-python.html).
|
||
|
+ This is pretty close, but i didn't copy it exactly.
|
||
|
+ """
|
||
|
+
|
||
|
+ if not isinstance(a, dict) or not isinstance(b, dict):
|
||
|
+ return b
|
||
|
|
||
|
- if not isinstance(a, dict) or not isinstance(b, dict):
|
||
|
- return b
|
||
|
+ for (key, value) in b.items():
|
||
|
+ if key in a:
|
||
|
+ a[key] = dict_merge(a[key], value)
|
||
|
+ else:
|
||
|
+ a[key] = value
|
||
|
|
||
|
- for (key, value) in b.items():
|
||
|
- if key in a:
|
||
|
- a[key] = dict_merge(a[key], value)
|
||
|
- else:
|
||
|
- a[key] = value
|
||
|
+ return a
|
||
|
|
||
|
- return a
|
||
|
|
||
|
# -----------------------------------------------------------------------------
|
||
|
|
||
|
+
|
||
|
def main():
|
||
|
- arg_parser = argparse.ArgumentParser(
|
||
|
- description = 'Generate project data for use with the UI' )
|
||
|
-
|
||
|
- arg_parser.add_argument(
|
||
|
- '--current-date',
|
||
|
- help = ( "should be in the format rfc-3339 "
|
||
|
- + "(e.g. 2006-08-07 12:34:56-06:00)" ),
|
||
|
- required = True )
|
||
|
- arg_parser.add_argument(
|
||
|
- '--git-commit-date',
|
||
|
- help = ( "should be in the format rfc-3339 "
|
||
|
- + "(e.g. 2006-08-07 12:34:56-06:00)" ),
|
||
|
- required = True )
|
||
|
- arg_parser.add_argument(
|
||
|
- '--git-commit-id',
|
||
|
- help = "the git commit ID",
|
||
|
- required = True )
|
||
|
- arg_parser.add_argument(
|
||
|
- '--map-file-path',
|
||
|
- help = "the path to the '.map' file",
|
||
|
- required = True )
|
||
|
- arg_parser.add_argument(
|
||
|
- '--source-code-path',
|
||
|
- help = "the path to the source code directory",
|
||
|
- required = True )
|
||
|
- arg_parser.add_argument(
|
||
|
- '--matrix-file-path',
|
||
|
- help = "the path to the matrix file we're using",
|
||
|
- required = True )
|
||
|
- arg_parser.add_argument(
|
||
|
- '--layout-file-path',
|
||
|
- help = "the path to the layout file we're using",
|
||
|
- required = True )
|
||
|
-
|
||
|
- args = arg_parser.parse_args(sys.argv[1:])
|
||
|
-
|
||
|
- output = {}
|
||
|
- dict_merge( output, gen_static( args.current_date,
|
||
|
- args.git_commit_date,
|
||
|
- args.git_commit_id ) )
|
||
|
- dict_merge(output, parse_mapfile(args.map_file_path))
|
||
|
- dict_merge(output, find_keyboard_functions(args.source_code_path))
|
||
|
- dict_merge(output, gen_mappings( args.matrix_file_path,
|
||
|
- args.layout_file_path ))
|
||
|
- dict_merge(output, gen_derived(output))
|
||
|
-
|
||
|
- print(json.dumps(output, sort_keys=True, indent=4))
|
||
|
+ arg_parser = argparse.ArgumentParser(
|
||
|
+ description="Generate project data for use with the UI"
|
||
|
+ )
|
||
|
+
|
||
|
+ arg_parser.add_argument(
|
||
|
+ "--current-date",
|
||
|
+ help=(
|
||
|
+ "should be in the format rfc-3339 "
|
||
|
+ "(e.g. 2006-08-07 12:34:56-06:00)"
|
||
|
+ ),
|
||
|
+ required=True,
|
||
|
+ )
|
||
|
+ arg_parser.add_argument(
|
||
|
+ "--git-commit-date",
|
||
|
+ help=(
|
||
|
+ "should be in the format rfc-3339 "
|
||
|
+ "(e.g. 2006-08-07 12:34:56-06:00)"
|
||
|
+ ),
|
||
|
+ required=True,
|
||
|
+ )
|
||
|
+ arg_parser.add_argument(
|
||
|
+ "--git-commit-id", help="the git commit ID", required=True
|
||
|
+ )
|
||
|
+ arg_parser.add_argument(
|
||
|
+ "--map-file-path", help="the path to the '.map' file", required=True
|
||
|
+ )
|
||
|
+ arg_parser.add_argument(
|
||
|
+ "--source-code-path",
|
||
|
+ help="the path to the source code directory",
|
||
|
+ required=True,
|
||
|
+ )
|
||
|
+ arg_parser.add_argument(
|
||
|
+ "--matrix-file-path",
|
||
|
+ help="the path to the matrix file we're using",
|
||
|
+ required=True,
|
||
|
+ )
|
||
|
+ arg_parser.add_argument(
|
||
|
+ "--layout-file-path",
|
||
|
+ help="the path to the layout file we're using",
|
||
|
+ required=True,
|
||
|
+ )
|
||
|
+
|
||
|
+ args = arg_parser.parse_args(sys.argv[1:])
|
||
|
+
|
||
|
+ output = {}
|
||
|
+ dict_merge(
|
||
|
+ output,
|
||
|
+ gen_static(
|
||
|
+ args.current_date, args.git_commit_date, args.git_commit_id
|
||
|
+ )
|
||
|
+ )
|
||
|
+ dict_merge(output, find_keyboard_functions(args.source_code_path))
|
||
|
+ dict_merge(
|
||
|
+ output, gen_mappings(args.matrix_file_path, args.layout_file_path)
|
||
|
+ )
|
||
|
+
|
||
|
+ print(json.dumps(output, sort_keys=True, indent=4))
|
||
|
|
||
|
-# -----------------------------------------------------------------------------
|
||
|
|
||
|
-if __name__ == '__main__':
|
||
|
- main()
|
||
|
+# -----------------------------------------------------------------------------
|
||
|
|
||
|
+if __name__ == "__main__":
|
||
|
+ main()
|
||
|
diff --git a/makefile b/makefile
|
||
|
index d9fe10c..971ee0e 100644
|
||
|
--- a/makefile
|
||
|
+++ b/makefile
|
||
|
@@ -58,24 +58,27 @@ SCRIPTS := build-scripts
|
||
|
all: dist
|
||
|
|
||
|
clean:
|
||
|
- git clean -dX # remove ignored files and directories
|
||
|
- -rm -r '$(BUILD)'
|
||
|
+ git clean -fdX # remove ignored files and directories
|
||
|
+ rm -rf '$(BUILD)'
|
||
|
|
||
|
checkin:
|
||
|
-git commit -a
|
||
|
|
||
|
build-dir:
|
||
|
- -rm -r '$(BUILD)/$(TARGET)'*
|
||
|
- -mkdir -p '$(BUILD)/$(TARGET)'
|
||
|
+ rm -rf '$(BUILD)/$(TARGET)'*
|
||
|
+ mkdir -p '$(BUILD)/$(TARGET)'
|
||
|
|
||
|
firmware:
|
||
|
cd src; $(MAKE) LAYOUT=$(LAYOUT) all
|
||
|
|
||
|
-$(ROOT)/firmware.%: firmware
|
||
|
+$(ROOT):
|
||
|
+ mkdir -p '$@'
|
||
|
+
|
||
|
+$(ROOT)/firmware.%: firmware $(ROOT)
|
||
|
cp 'src/firmware.$*' '$@'
|
||
|
|
||
|
|
||
|
-$(ROOT)/firmware--ui-info.json: $(SCRIPTS)/gen-ui-info.py checkin
|
||
|
+$(ROOT)/firmware--ui-info.json: $(SCRIPTS)/gen-ui-info.py checkin firmware
|
||
|
( ./'$<' \
|
||
|
--current-date '$(shell $(DATE_PROG) --rfc-3339 s)' \
|
||
|
--git-commit-date '$(GIT_COMMIT_DATE)' \
|