guix-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[bug#66217] [PATCH 15/22] gnu: Add ergodox-firmware-colemak-jc-mod.


From: Maxim Cournoyer
Subject: [bug#66217] [PATCH 15/22] gnu: Add ergodox-firmware-colemak-jc-mod.
Date: Tue, 26 Sep 2023 15:04:38 -0400

* gnu/packages/firmware.scm (make-ergodox-firmware): New procedure
(ergodox-firmware-colemak-jc-mod): New variable.
* gnu/packages/patches/ergodox-firmware-fix-json-target.patch: New file.
* gnu/packages/patches/ergodox-firmware-fix-numpad.patch: Likewise.
* gnu/local.mk (dist_patch_DATA): Register them.
---

 gnu/local.mk                                  |    2 +
 gnu/packages/firmware.scm                     |   77 +-
 .../ergodox-firmware-fix-json-target.patch    | 1405 +++++++++++++++++
 .../patches/ergodox-firmware-fix-numpad.patch |   18 +
 4 files changed, 1501 insertions(+), 1 deletion(-)
 create mode 100644 gnu/packages/patches/ergodox-firmware-fix-json-target.patch
 create mode 100644 gnu/packages/patches/ergodox-firmware-fix-numpad.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index c04c4196cdf..052e6f2013c 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1120,6 +1120,8 @@ dist_patch_DATA =                                         
\
   %D%/packages/patches/enblend-enfuse-reproducible.patch       \
   %D%/packages/patches/enjarify-setup-py.patch                 \
   %D%/packages/patches/enlightenment-fix-setuid-path.patch     \
+  %D%/packages/patches/ergodox-firmware-fix-json-target.patch  \
+  %D%/packages/patches/ergodox-firmware-fix-numpad.patch       \
   %D%/packages/patches/erlang-man-path.patch                   \
   %D%/packages/patches/esmini-no-clutter-log.patch             \
   %D%/packages/patches/esmini-use-pkgconfig.patch              \
diff --git a/gnu/packages/firmware.scm b/gnu/packages/firmware.scm
index a7428df8129..a901ae46944 100644
--- a/gnu/packages/firmware.scm
+++ b/gnu/packages/firmware.scm
@@ -85,7 +85,8 @@ (define-module (gnu packages firmware)
   #:use-module (ice-9 format)
   #:use-module (ice-9 match)
 
-  #:export (make-qmk-firmware))
+  #:export (make-ergodox-firmware
+            make-qmk-firmware))
 
 (define-public ath9k-htc-firmware
   (package
@@ -1222,6 +1223,80 @@ (define-public crust-pinebook
 (define-public crust-pine64-plus
   (make-crust-package "pine64_plus"))
 
+
+;;;
+;;; ErgoDox firmware.
+;;;
+
+(define* (make-ergodox-firmware/implementation layout #:key override.c
+                                               override.h)
+  "Return an ergodox-firmware package for LAYOUT, optionally using OVERRIDE.C,
+a C source file-like object to override LAYOUT which may be accompanied by
+OVERRIDE.H, to also override the corresponding layout include file."
+  (let ((revision "0")
+        (commit "89b7e2bfdafb2a87e0248846d5c95cc5e9a27858"))
+    (package
+      (name (string-append "ergodox-firmware-" layout))
+      (version (git-version "1" revision commit))
+      (source (origin
+                (method git-fetch)
+                (uri (git-reference
+                      (url "https://github.com/benblazak/ergodox-firmware";)
+                      (commit commit)))
+                (file-name (git-file-name name version))
+                (sha256
+                 (base32
+                  "1z28frxyb21nz90frycrpsbxjp09374wawayvjphnwc8njlvkkpy"))
+                (patches
+                 (search-patches "ergodox-firmware-fix-json-target.patch"
+                                 "ergodox-firmware-fix-numpad.patch"))))
+      (build-system gnu-build-system)
+      (arguments
+       (list
+        #:tests? #f                   ;no test suite
+        #:make-flags
+        #~(list (string-append "LAYOUT=" #$layout)
+                ;; Simplify the output directory name.
+                "ROOT=output")
+        #:phases
+        #~(modify-phases %standard-phases
+            (add-after 'unpack 'copy-override-files
+              (lambda _
+                (when #$override.c
+                  (copy-file #$override.c
+                             (format #f "src/keyboard/ergodox/layout/~a.c"
+                                     #$layout)))
+                (when #$override.h
+                  (copy-file #$override.h
+                             (format #f "src/keyboard/ergodox/layout/~a.h"
+                                     #$layout)))))
+            ;; The Makefile-based build system lacks configure
+            ;; and install targets.
+            (delete 'configure)
+            (replace 'install
+              (lambda _
+                (with-directory-excursion "output"
+                  (install-file "firmware.hex" #$output)
+                  (install-file "firmware.eep" #$output)
+                  (install-file "firmware--layout.html" #$output)))))))
+      (native-inputs (list (make-avr-toolchain) python))
+      (home-page "https://www.ergodox.io";)
+      (synopsis "Firmware for the ErgoDox keyboard")
+      (description (format #f "This package contains the original firmware for
+the ErgoDox keyboard, built using the ~a layout (as defined in the
+@file{src/keyboard/ergodox/layout/~@*~a.c} source file).  It contains the
+@file{firmware.hex} and the @file{firmware.eep} files, which can be loaded to
+a target using the @code{teensy-loader-cli} package as well as a
+@file{firmware--layout.html} file, useful to easily visualize the
+corresponding layout." layout))
+      (license license:expat))))
+
+(define make-ergodox-firmware
+  (memoize make-ergodox-firmware/implementation))
+
+(define-public ergodox-firmware-colemak-jc-mod
+  (make-ergodox-firmware "colemak-jc-mod"))
+
 
 ;;;
 ;;; QMK Firmware.
diff --git a/gnu/packages/patches/ergodox-firmware-fix-json-target.patch 
b/gnu/packages/patches/ergodox-firmware-fix-json-target.patch
new file mode 100644
index 00000000000..52da4e2497d
--- /dev/null
+++ b/gnu/packages/patches/ergodox-firmware-fix-json-target.patch
@@ -0,0 +1,1405 @@
+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)' \
diff --git a/gnu/packages/patches/ergodox-firmware-fix-numpad.patch 
b/gnu/packages/patches/ergodox-firmware-fix-numpad.patch
new file mode 100644
index 00000000000..47af9f8398d
--- /dev/null
+++ b/gnu/packages/patches/ergodox-firmware-fix-numpad.patch
@@ -0,0 +1,18 @@
+Submitted upstream: https://github.com/benblazak/ergodox-firmware/pull/100
+
+diff --git a/src/lib/key-functions/public/special.c 
b/src/lib/key-functions/public/special.c
+index 42aba45..6488137 100644
+--- a/src/lib/key-functions/public/special.c
++++ b/src/lib/key-functions/public/special.c
+@@ -102,9 +102,9 @@ void kbfun_2_keys_capslock_press_release(void) {
+ static uint8_t numpad_layer_id;
+ 
+ static inline void numpad_toggle_numlock(void) {
+-      _kbfun_press_release(true, KEY_LockingNumLock);
++      _kbfun_press_release(true, KEYPAD_NumLock_Clear);
+       usb_keyboard_send();
+-      _kbfun_press_release(false, KEY_LockingNumLock);
++      _kbfun_press_release(false, KEYPAD_NumLock_Clear);
+       usb_keyboard_send();
+ }
+ 
-- 
2.41.0






reply via email to

[Prev in Thread] Current Thread [Next in Thread]