From 3e128552d92714ff86d4378b4e3acccc62d6f132 Mon Sep 17 00:00:00 2001
From: Gergely Nagy <algernon@madhouse-project.org>
Date: Sun, 18 Sep 2016 11:48:47 +0200
Subject: Update the ergodox/algernon keymap to v1.7

Overall changes
===============

* The number row has been completely rearranged on both the **Base** and
  the **ADORE** layers.
* The number/function key behavior was changed: function keys are now on
  the **Media**.
* The `:`/`;` and `-`/`_` keys were put back to their thumb position on
  the bottom row, on both the **Base** and **ADORE** layers.
* The bottom large keys on the inner side of each half now function as
  [tmux](http://tmux.github.io/) keys: the left to send the prefix, the
  right to send the `display-panes` key. The left also doubles as a GNU
  screen prefix key, and sends `C-a` when double tapped.
* A number of functions, such as the **AppSel** layer, now require the
  `hid-commands` tool to be running, with the output of `hid_listen`
  being piped to it.

ADORE
=====

* `Y` and `X` have been swapped again.

Media/Navigation layer
======================

* The function keys are now on this layer.
* Mouse keys have been removed.
* Media start/stop/prev/next have been removed.
* `Print screen` has been removed.
* There is only one screen lock key now.

Heatmap
=======

* Fixed a few issues in the finger-stats calculation.
* The tool now also timestamps and saves all input lines to a logfile,
  which it loads on start, allowing one to continue the collection after
  upgrading the tool.
* The heatmap tool will now colorize the stats by default.
* The periodic stats are now printed in a more compact format.

Tools
=====

* Added a new tool, `tools/layer-notify` that listens to layer change
  events on the HID console, and pops up a notification on layer
  changes.
* Another new tool, `tools/text-to-log.py` has been added that converts
  arbitrary text to a keylogger output, which can be fed to the heatmap
  generator.
* A number of features have been moved to the `tools/hid-commands`
  utility. These generally are OS dependent, and are easier to implement
  on the software side.

Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
---
 .../algernon/tools/heatmap-layout.ADORE.json       | 132 ++++-----------
 .../algernon/tools/heatmap-layout.Dvorak.json      | 129 ++++-----------
 .../ergodox/keymaps/algernon/tools/hid-commands    |  61 +++++++
 .../ergodox/keymaps/algernon/tools/layer-notify    |  12 ++
 .../keymaps/algernon/tools/log-to-heatmap.py       | 184 +++++++++++++++------
 .../ergodox/keymaps/algernon/tools/max-focused     |   5 -
 .../ergodox/keymaps/algernon/tools/text-to-log.py  | 107 ++++++++++++
 7 files changed, 382 insertions(+), 248 deletions(-)
 create mode 100755 keyboards/ergodox/keymaps/algernon/tools/hid-commands
 create mode 100755 keyboards/ergodox/keymaps/algernon/tools/layer-notify
 delete mode 100755 keyboards/ergodox/keymaps/algernon/tools/max-focused
 create mode 100755 keyboards/ergodox/keymaps/algernon/tools/text-to-log.py

(limited to 'keyboards/ergodox/keymaps/algernon/tools')

diff --git a/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.ADORE.json b/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.ADORE.json
index 4dfa877a78..502d1e6ea4 100644
--- a/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.ADORE.json
+++ b/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.ADORE.json
@@ -13,18 +13,15 @@
   [
     {
       "x": 3.5,
-      "c": "#a7d0db",
       "fa": [
         0,
         0,
         2
       ]
     },
-    "#\n3\nF3",
+    "*\n5\nF5",
     {
       "x": 10.5,
-      "c": "#a7d0db",
-      "t": "#000000",
       "a": 4,
       "fa": [
         0,
@@ -32,54 +29,44 @@
         2
       ]
     },
-    "*\n8\nF8"
+    "#\n4\nF4"
   ],
   [
     {
       "y": -0.875,
-      "x": 2.5,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 2.5
     },
-    "@\n2\nF2",
+    "@\n7\nF7",
     {
-      "x": 1,
-      "c": "#7adabd",
-      "t": "#000000"
+      "x": 1
     },
-    "$\n4\nF4",
+    "^\n3\nF3",
     {
       "x": 8.5
     },
-    "&\n7\nF7",
+    "!\n2\nF2",
     {
-      "x": 1,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 1
     },
-    "(\n9\nF9"
+    "&\n6\nF6"
   ],
   [
     {
       "y": -0.875,
-      "x": 5.5,
-      "c": "#7adabd",
-      "t": "#000000"
+      "x": 5.5
     },
-    "%\n5\nF5",
+    "$\n1\nF1",
     {
-      "c": "#f9cd31",
       "a": 7,
-      "f": 2
+      "f": 3
     },
-    "STENO",
+    "F11",
     {
       "x": 4.5,
       "f": 3
     },
     "F12",
     {
-      "c": "#7adabd",
       "a": 4,
       "f": 3,
       "fa": [
@@ -88,19 +75,17 @@
         2
       ]
     },
-    "^\n6\nF6"
+    "%\n0\nF10"
   ],
   [
     {
       "y": -0.875,
-      "c": "#ffb2d2",
       "f": 9,
       "a": 6,
       "w": 1.5
     },
     "\n\n<i class='kb kb-Multimedia-Play-Pause'></i>",
     {
-      "t": "#0d0d0b",
       "f": 3,
       "a": 4,
       "fa": [
@@ -109,23 +94,21 @@
           2
       ]
     },
-    "!\n1\nF1",
+    " \n9\nF9",
     {
       "x": 14.5
     },
-    ")\n0\nF10",
+    " \n8\nF8",
     {
       "a": 7,
       "w": 1.5
     },
-    "F11"
+    "STENO"
   ],
   [
     {
       "y": -0.375,
       "x": 3.5,
-      "c": "#a7d0db",
-      "t": "#000000",
       "a": 6
     },
     "G",
@@ -138,15 +121,11 @@
     {
       "y": -0.875,
       "x": 2.5,
-      "c": "#bfbad1",
-      "t": "#0d0d0b",
       "a": 6
     },
     "W",
     {
       "x": 1,
-      "c": "#7adabd",
-      "t": "#000000",
       "a": 6
     },
     "L",
@@ -155,22 +134,17 @@
     },
     "H",
     {
-      "x": 1,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 1
     },
     "P"
   ],
   [
     {
       "y": -0.875,
-      "x": 5.5,
-      "c": "#7adabd",
-      "t": "#000000"
+      "x": 5.5
     },
     "M",
     {
-      "c": "#93c9b7",
       "a": 4,
       "fa": [0, 0, 0],
       "h": 1.5
@@ -182,7 +156,6 @@
     },
     "}\n)\n]",
     {
-      "c": "#7adabd",
       "a": 6
     },
     "F"
@@ -190,24 +163,21 @@
   [
     {
       "y": -0.875,
-      "c": "#ffb07b",
-      "t": "#0d0d0b",
       "f": 3,
       "a": 4,
       "w": 1.5
     },
     "\n\n~\n`",
     {
-      "c": "#ffb2d2",
       "a": 6,
       "f": 3
     },
-    "Y",
+    "X",
     {
       "x": 14.5,
       "a": 6
     },
-    "X",
+    "Y",
     {
       "a": 4,
       "w": 1.5
@@ -218,8 +188,6 @@
     {
       "y": -0.375,
       "x": 3.5,
-      "c": "#a7d0db",
-      "t": "#000000",
       "a": 6
     },
     "E",
@@ -231,15 +199,11 @@
   [
     {
       "y": -0.875,
-      "x": 2.5,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 2.5
     },
     "O",
     {
       "x": 1,
-      "c": "#7adabd",
-      "t": "#000000",
       "n": true
     },
     "I",
@@ -249,18 +213,14 @@
     },
     "R",
     {
-      "x": 1,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 1
     },
     "N"
   ],
   [
     {
       "y": -0.875,
-      "x": 5.5,
-      "c": "#7adabd",
-      "t": "#000000"
+      "x": 5.5
     },
     "U",
     {
@@ -271,8 +231,6 @@
   [
     {
       "y": -0.875,
-      "c": "#ffb2d2",
-      "t": "#0d0d0b",
       "fa": [
         6
       ],
@@ -308,22 +266,21 @@
     {
       "y": -0.625,
       "x": 6.5,
-      "c": "#93c9b7",
-      "t": "#000000",
+      "a": 7,
+      "f": 9,
       "h": 1.5
     },
-    ";\n:",
+    "<i class='fa fa-columns'></i>",
     {
       "x": 4.5,
       "h": 1.5
     },
-    "_\n-"
+    "<i class='fa fa-table'></i>"
   ],
   [
     {
       "y": -0.75,
       "x": 3.5,
-      "c": "#a7d0db",
       "a": 4,
       "f": 3
     },
@@ -339,15 +296,11 @@
     {
       "y": -0.875,
       "x": 2.5,
-      "c": "#bfbad1",
-      "t": "#0d0d0b",
       "a": 6
     },
     "Q",
     {
       "x": 1,
-      "c": "#7adabd",
-      "t": "#000000",
       "a": 4
     },
     "<\n,",
@@ -357,9 +310,7 @@
     },
     "K",
     {
-      "x": 1,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 1
     },
     "J"
   ],
@@ -367,8 +318,6 @@
     {
       "y": -0.875,
       "x": 5.5,
-      "c": "#7adabd",
-      "t": "#000000",
       "a": 4
     },
     ">\n.",
@@ -381,15 +330,12 @@
   [
     {
       "y": -0.875,
-      "c": "#ffb07b",
       "f": 9,
       "w": 1.5,
       "g": true
     },
     "",
     {
-      "c": "#ffb2d2",
-      "t": "#0d0d0b",
       "a": 6,
       "f": 3,
       "g": false
@@ -401,8 +347,6 @@
     },
     "?\n/",
     {
-      "c": "#ffb07b",
-      "t": "#000000",
       "f": 9,
       "g": true,
       "w": 1.5,
@@ -414,7 +358,6 @@
     {
       "y": -0.375,
       "x": 3.5,
-      "c": "#d9dae0",
       "g": true,
       "a": 7,
       "f": 3
@@ -433,18 +376,16 @@
     "",
     {
       "x": 1,
-      "c": "#d4872a",
-      "g": true,
+      "g": false,
       "a": 5
     },
-    "",
+    ";\n:",
     {
       "x": 8.5
     },
-    "",
+    "_\n-",
     {
       "x": 1,
-      "c": "#d9dae0",
       "g": true,
       "a": 7
     },
@@ -472,7 +413,6 @@
       "ry": 4.25,
       "y": -1,
       "x": 1,
-      "c": "#f9cd31",
       "g": false
     },
     "Alt",
@@ -489,7 +429,6 @@
   ],
   [
     {
-      "c": "#d4872a",
       "a": 7,
       "f": 9,
       "h": 2
@@ -500,15 +439,13 @@
     },
     "<i class='fa fa-angle-double-up'></i>",
     {
-      "c": "#f9cd31",
       "f": 3
     },
     "Ctrl"
   ],
   [
     {
-      "x": 2,
-      "c": "#e26757"
+      "x": 2
     },
     "ESC"
   ],
@@ -518,7 +455,6 @@
       "rx": 13,
       "y": -1,
       "x": -3,
-      "c": "#f9cd31",
       "f": 2
     },
     "MEDIA",
@@ -531,7 +467,6 @@
     },
     "HUN",
     {
-      "c": "#d4872a",
       "f": 9,
       "h": 2
     },
@@ -545,7 +480,6 @@
   [
     {
       "x": -3,
-      "c": "#f9cd31",
       "f": 2
     },
     "LEAD"
diff --git a/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.Dvorak.json b/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.Dvorak.json
index 1248d36af7..5b4ca06c30 100644
--- a/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.Dvorak.json
+++ b/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.Dvorak.json
@@ -13,18 +13,15 @@
   [
     {
       "x": 3.5,
-      "c": "#a7d0db",
       "fa": [
         0,
         0,
         2
       ]
     },
-    "#\n3\nF3",
+    "*\n5\nF5",
     {
       "x": 10.5,
-      "c": "#a7d0db",
-      "t": "#000000",
       "a": 4,
       "fa": [
         0,
@@ -32,54 +29,44 @@
         2
       ]
     },
-    "*\n8\nF8"
+    "#\n4\nF4"
   ],
   [
     {
       "y": -0.875,
-      "x": 2.5,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 2.5
     },
-    "@\n2\nF2",
+    "@\n7\nF7",
     {
-      "x": 1,
-      "c": "#7adabd",
-      "t": "#000000"
+      "x": 1
     },
-    "$\n4\nF4",
+    "^\n3\nF3",
     {
       "x": 8.5
     },
-    "&\n7\nF7",
+    "!\n2\nF2",
     {
-      "x": 1,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 1
     },
-    "(\n9\nF9"
+    "&\n6\nF6"
   ],
   [
     {
       "y": -0.875,
-      "x": 5.5,
-      "c": "#7adabd",
-      "t": "#000000"
+      "x": 5.5
     },
-    "%\n5\nF5",
+    "$\n1\nF1",
     {
-      "c": "#f9cd31",
       "a": 7,
-      "f": 2
+      "f": 3
     },
-    "STENO",
+    "F11",
     {
       "x": 4.5,
       "f": 3
     },
     "F12",
     {
-      "c": "#7adabd",
       "a": 4,
       "f": 3,
       "fa": [
@@ -88,12 +75,11 @@
         2
       ]
     },
-    "^\n6\nF6"
+    "%\n0\nF10"
   ],
   [
     {
       "y": -0.875,
-      "c": "#ffb2d2",
       "f": 6,
       "a": 6,
       "w": 1.5
@@ -101,7 +87,6 @@
     "<i class='fa fa-fast-backward'></i>\n\n<i class='fa fa-fast-forward'></i>",
     {
       "f": 3,
-      "t": "#0d0d0b",
       "a": 4,
       "fa": [
           0,
@@ -110,23 +95,21 @@
       ]
 
     },
-    "!\n1\nF1",
+    " \n9\nF9",
     {
       "x": 14.5
     },
-    ")\n0\nF10",
+    " \n8\nF8",
     {
       "a": 7,
       "w": 1.5
     },
-    "F11"
+    "STENO"
   ],
   [
     {
       "y": -0.375,
       "x": 3.5,
-      "c": "#a7d0db",
-      "t": "#000000",
       "a": 4
     },
     ">\n.",
@@ -140,15 +123,11 @@
     {
       "y": -0.875,
       "x": 2.5,
-      "c": "#bfbad1",
-      "t": "#0d0d0b",
       "a": 4
     },
     "<\n,",
     {
       "x": 1,
-      "c": "#7adabd",
-      "t": "#000000",
       "a": 6
     },
     "P",
@@ -157,22 +136,17 @@
     },
     "G",
     {
-      "x": 1,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 1
     },
     "R"
   ],
   [
     {
       "y": -0.875,
-      "x": 5.5,
-      "c": "#7adabd",
-      "t": "#000000"
+      "x": 5.5
     },
     "Y",
     {
-      "c": "#93c9b7",
       "a": 4,
       "h": 1.5
     },
@@ -183,7 +157,6 @@
     },
     "}\n)\n]",
     {
-      "c": "#7adabd",
       "a": 6
     },
     "F"
@@ -191,14 +164,12 @@
   [
     {
       "y": -0.875,
-      "c": "#ffb07b",
-      "t": "#0d0d0b",
       "f": 3,
+      "a": 4,
       "w": 1.5
     },
     "\n\n~\n`",
     {
-      "c": "#ffb2d2",
       "a": 4,
       "f": 3
     },
@@ -218,8 +189,6 @@
     {
       "y": -0.375,
       "x": 3.5,
-      "c": "#a7d0db",
-      "t": "#000000",
       "a": 6
     },
     "E",
@@ -231,15 +200,11 @@
   [
     {
       "y": -0.875,
-      "x": 2.5,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 2.5
     },
     "O",
     {
       "x": 1,
-      "c": "#7adabd",
-      "t": "#000000",
       "n": true
     },
     "U",
@@ -249,18 +214,14 @@
     },
     "H",
     {
-      "x": 1,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 1
     },
     "N"
   ],
   [
     {
       "y": -0.875,
-      "x": 5.5,
-      "c": "#7adabd",
-      "t": "#000000"
+      "x": 5.5
     },
     "I",
     {
@@ -271,8 +232,6 @@
   [
     {
       "y": -0.875,
-      "c": "#ffb2d2",
-      "t": "#0d0d0b",
       "fa": [
         6
       ],
@@ -308,23 +267,22 @@
     {
       "y": -0.625,
       "x": 6.5,
-      "c": "#93c9b7",
-      "t": "#000000",
       "a": 7,
+      "f": 9,
       "h": 1.5
     },
-    "(",
+    "<i class='fa fa-columns'></i>",
     {
       "x": 4.5,
       "h": 1.5
     },
-    ")"
+    "<i class='fa fa-table'></i>"
   ],
   [
     {
       "y": -0.75,
       "x": 3.5,
-      "c": "#a7d0db",
+      "f": 3,
       "a": 6
     },
     "J",
@@ -336,15 +294,11 @@
   [
     {
       "y": -0.875,
-      "x": 2.5,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 2.5
     },
     "Q",
     {
-      "x": 1,
-      "c": "#7adabd",
-      "t": "#000000"
+      "x": 1
     },
     "K",
     {
@@ -352,18 +306,14 @@
     },
     "M",
     {
-      "x": 1,
-      "c": "#bfbad1",
-      "t": "#0d0d0b"
+      "x": 1
     },
     "V"
   ],
   [
     {
       "y": -0.875,
-      "x": 5.5,
-      "c": "#7adabd",
-      "t": "#000000"
+      "x": 5.5
     },
     "X",
     {
@@ -374,14 +324,11 @@
   [
     {
       "y": -0.875,
-      "c": "#ffb07b",
       "f": 9,
       "w": 1.5
     },
     "\n\n<i class='kb kb-Multimedia-Play-Pause'></i>",
     {
-      "c": "#ffb2d2",
-      "t": "#0d0d0b",
       "a": 4,
       "f": 3
     },
@@ -392,8 +339,6 @@
     },
     "Z",
     {
-      "c": "#ffb07b",
-      "t": "#000000",
       "f": 9,
       "w": 1.5
     },
@@ -403,7 +348,6 @@
     {
       "y": -0.375,
       "x": 3.5,
-      "c": "#d9dae0",
       "g": true,
       "a": 7,
       "f": 3
@@ -422,7 +366,6 @@
     "",
     {
       "x": 1,
-      "c": "#d4872a",
       "g": false,
       "a": 5
     },
@@ -433,7 +376,6 @@
     "_\n-",
     {
       "x": 1,
-      "c": "#d9dae0",
       "g": true,
       "a": 7
     },
@@ -461,7 +403,6 @@
       "ry": 4.25,
       "y": -1,
       "x": 1,
-      "c": "#f9cd31",
       "g": false
     },
     "Alt",
@@ -478,7 +419,6 @@
   ],
   [
     {
-      "c": "#d4872a",
       "a": 7,
       "f": 9,
       "h": 2
@@ -489,15 +429,13 @@
     },
     "<i class='fa fa-angle-double-up'></i>",
     {
-      "c": "#f9cd31",
       "f": 3
     },
     "Ctrl"
   ],
   [
     {
-      "x": 2,
-      "c": "#e26757"
+      "x": 2
     },
     "ESC"
   ],
@@ -507,7 +445,6 @@
       "rx": 13,
       "y": -1,
       "x": -3,
-      "c": "#f9cd31",
       "f": 2
     },
     "MEDIA",
@@ -520,7 +457,6 @@
     },
     "LEAD",
     {
-      "c": "#d4872a",
       "f": 9,
       "h": 2
     },
@@ -534,7 +470,6 @@
   [
     {
       "x": -3,
-      "c": "#f9cd31",
       "f": 2
     },
     "HUN"
diff --git a/keyboards/ergodox/keymaps/algernon/tools/hid-commands b/keyboards/ergodox/keymaps/algernon/tools/hid-commands
new file mode 100755
index 0000000000..f3b83cf6d1
--- /dev/null
+++ b/keyboards/ergodox/keymaps/algernon/tools/hid-commands
@@ -0,0 +1,61 @@
+#!/bin/bash
+set -e
+
+cmd_wm () {
+    WIN="$(xdotool getactivewindow)"
+    wmctrl -i -r ${WIN} -b remove,maximized_vert,maximized_horz
+    xdotool windowsize ${WIN} 100% 100%
+    wmctrl -i -r ${WIN} -b add,maximized_vert,maximized_horz
+}
+
+_cmd_appsel () {
+    wmctrl -x -a $1 || true
+    xdotool key Escape
+}
+
+cmd_appsel_music () {
+    wmctrl -x -a rhythmbox || wmctrl -x -a spotify || true
+    xdotool key Escape
+}
+
+cmd_appsel_slack () {
+    _cmd_appsel slack
+}
+
+cmd_appsel_emacs () {
+    _cmd_appsel emacs24
+}
+
+cmd_appsel_term () {
+    _cmd_appsel gnome-terminal
+}
+
+cmd_appsel_chrome () {
+    _cmd_appsel chromium
+}
+
+cmd_help () {
+    cat <<EOF
+Use the source, Luke!
+EOF
+}
+
+while read l; do
+    case "$l" in
+        "CMD:"*)
+            ;;
+        *)
+            continue
+            ;;
+    esac
+
+    cmd="$(echo $l | cut -d: -f2-)"
+
+    echo "Got command: ${cmd}"
+
+    if type cmd_${cmd} >/dev/null 2>&1; then
+        cmd_${cmd}
+    fi
+done
+
+
diff --git a/keyboards/ergodox/keymaps/algernon/tools/layer-notify b/keyboards/ergodox/keymaps/algernon/tools/layer-notify
new file mode 100755
index 0000000000..627c2861ef
--- /dev/null
+++ b/keyboards/ergodox/keymaps/algernon/tools/layer-notify
@@ -0,0 +1,12 @@
+#!/bin/sh
+HL="${HID_LISTEN:-$HOME/src/ext/hid_listen/hid_listen}"
+
+sudo "${HL}" | grep --line-buffered LAYER: | \
+(while read line; do
+     case $line in
+         LAYER:*)
+             layer="$(echo $(echo $line | cut -d: -f2-))"
+             notify-send -i mark-location-symbolic "Switched to layer: $layer"
+             ;;
+     esac
+ done)
diff --git a/keyboards/ergodox/keymaps/algernon/tools/log-to-heatmap.py b/keyboards/ergodox/keymaps/algernon/tools/log-to-heatmap.py
index 68585843be..09c737646c 100755
--- a/keyboards/ergodox/keymaps/algernon/tools/log-to-heatmap.py
+++ b/keyboards/ergodox/keymaps/algernon/tools/log-to-heatmap.py
@@ -1,12 +1,15 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
 import json
 import os
 import sys
 import re
 import argparse
+import time
 
 from math import floor
 from os.path import dirname
+from subprocess import Popen, PIPE, STDOUT
+from blessings import Terminal
 
 class Heatmap(object):
     coords = [
@@ -33,7 +36,7 @@ class Heatmap(object):
         [
             # Row 4
             [20,  0], [20,  2], [19,  0], [18,  0], [19,  2], [], [], [], [],
-            [19,  4], [18,  2], [19,  6], [20,  4], [20,  6],
+            [19,  4], [18,  2], [19,  6], [20,  4], [20,  6], [], [], [], []
         ],
         [
             # Row 5
@@ -56,11 +59,13 @@ class Heatmap(object):
     def set_attr(orig, new):
         return new
 
-    def set_bg(self, (block, n), color):
+    def set_bg(self, coords, color):
+        (block, n) = coords
         self.set_attr_at(block, n, "c", self.set_attr, color)
         #self.set_attr_at(block, n, "g", self.set_attr, False)
 
-    def set_tap_info(self, (block, n), count, cap):
+    def set_tap_info(self, coords, count, cap):
+        (block, n) = coords
         def _set_tap_info(o, _count, _cap):
             ns = 4 - o.count ("\n")
             return o + "\n" * ns + "%.02f%%" % (float(_count) / float(_cap) * 100)
@@ -87,8 +92,8 @@ class Heatmap(object):
         g = (colors[idx2][1] - colors[idx1][1]) * fb + colors[idx1][1]
         b = (colors[idx2][2] - colors[idx1][2]) * fb + colors[idx1][2]
 
-        r, g, b = [x * 255 for x in r, g, b]
-        return "#%02x%02x%02x" % (r, g, b)
+        r, g, b = [x * 255 for x in (r, g, b)]
+        return "#%02x%02x%02x" % (int(r), int(g), int(b))
 
     def __init__(self, layout):
         self.log = {}
@@ -96,7 +101,8 @@ class Heatmap(object):
         self.max_cnt = 0
         self.layout = layout
 
-    def update_log(self, (c, r)):
+    def update_log(self, coords):
+        (c, r) = coords
         if not (c, r) in self.log:
             self.log[(c, r)] = 0
         self.log[(c, r)] = self.log[(c, r)] + 1
@@ -132,18 +138,17 @@ class Heatmap(object):
             # right hand
             [0, 0, 0, 0, 0]
         ]
-        finger_map = [0, 0, 1, 2, 3, 4, 4]
+        finger_map = [0, 0, 1, 2, 3, 3, 3, 1, 1, 1, 2, 3, 4, 4]
         for (c, r) in self.log:
             if r == 5: # thumb cluster
                 if c <= 6: # left side
                     usage[0][4] = usage[0][4] + self.log[(c, r)]
                 else:
-                    usage[1][4] = usage[1][4] + self.log[(c, r)]
+                    usage[1][0] = usage[1][0] + self.log[(c, r)]
             else:
                 fc = c
                 hand = 0
                 if fc >= 7:
-                    fc = fc - 7
                     hand = 1
                 fm = finger_map[fc]
                 usage[hand][fm] = usage[hand][fm] + self.log[(c, r)]
@@ -157,79 +162,158 @@ class Heatmap(object):
         if total == 0:
             total = 1
         stats = {
+            "total-keys": total,
             "hands": {
                 "left": {
-                    "usage": float(hand_usage[0]) / total * 100,
+                    "usage": round(float(hand_usage[0]) / total * 100, 2),
                     "fingers": {
-                        "0 - pinky": 0,
-                        "1 - ring": 0,
-                        "2 - middle": 0,
-                        "3 - index": 0,
-                        "4 - thumb": 0,
+                        "pinky": 0,
+                        "ring": 0,
+                        "middle": 0,
+                        "index": 0,
+                        "thumb": 0,
                     }
                 },
                 "right": {
-                    "usage": float(hand_usage[1]) / total * 100,
+                    "usage": round(float(hand_usage[1]) / total * 100, 2),
                     "fingers": {
-                        "0 - thumb": 0,
-                        "1 - index": 0,
-                        "2 - middle": 0,
-                        "3 - ring": 0,
-                        "4 - pinky": 0,
+                        "thumb": 0,
+                        "index": 0,
+                        "middle": 0,
+                        "ring": 0,
+                        "pinky": 0,
                     }
                 },
             }
         }
 
         hmap = ['left', 'right']
-        fmap = ['0 - pinky', '1 - ring', '2 - middle', '3 - index', '4 - thumb',
-                '0 - thumb', '1 - index', '2 - middle', '3 - ring', '4 - pinky']
+        fmap = ['pinky', 'ring', 'middle', 'index', 'thumb',
+                'thumb', 'index', 'middle', 'ring', 'pinky']
         for hand_idx in range(len(usage)):
             hand = usage[hand_idx]
             for finger_idx in range(len(hand)):
-                stats['hands'][hmap[hand_idx]]['fingers'][fmap[finger_idx + hand_idx * 5]] = float(hand[finger_idx]) / total * 100
+                stats['hands'][hmap[hand_idx]]['fingers'][fmap[finger_idx + hand_idx * 5]] = round(float(hand[finger_idx]) / total * 100, 2)
         return stats
 
 def dump_all(out_dir, heatmaps):
-    for layer in heatmaps.keys():
+    stats = {}
+    t = Terminal()
+    t.clear()
+    sys.stdout.write("\x1b[2J\x1b[H")
+
+    print ('{t.underline}{outdir}{t.normal}\n'.format(t=t, outdir=out_dir))
+
+    keys = list(heatmaps.keys())
+    keys.sort()
+
+    for layer in keys:
         if len(heatmaps[layer].log) == 0:
             continue
 
         with open ("%s/%s.json" % (out_dir, layer), "w") as f:
             json.dump(heatmaps[layer].get_heatmap(), f)
-        print >>sys.stderr, "%s stats:" % (layer)
-        json.dump (heatmaps[layer].get_stats(), sys.stderr,
-                   indent = 4, sort_keys = True)
-        print >>sys.stderr, ""
-        print >>sys.stderr, ""
+        stats[layer] = heatmaps[layer].get_stats()
 
-def main(opts):
+        left = stats[layer]['hands']['left']
+        right = stats[layer]['hands']['right']
+
+        print ('{t.bold}{layer}{t.normal} ({total:,} taps):'.format(t=t, layer=layer,
+                                                                    total=int(stats[layer]['total-keys'] / 2)))
+        print (('{t.underline}        | ' + \
+                'left ({l[usage]:6.2f}%)  | ' + \
+                'right ({r[usage]:6.2f}%) |{t.normal}').format(t=t, l=left, r=right))
+        print ((' {t.bright_magenta}pinky{t.white}  |     {left[pinky]:6.2f}%     |     {right[pinky]:6.2f}%     |\n' + \
+                ' {t.bright_cyan}ring{t.white}   |     {left[ring]:6.2f}%     |     {right[ring]:6.2f}%     |\n' + \
+                ' {t.bright_blue}middle{t.white} |     {left[middle]:6.2f}%     |     {right[middle]:6.2f}%     |\n' + \
+                ' {t.bright_green}index{t.white}  |     {left[index]:6.2f}%     |     {right[index]:6.2f}%     |\n' + \
+                ' {t.bright_red}thumb{t.white}  |     {left[thumb]:6.2f}%     |     {right[thumb]:6.2f}%     |\n' + \
+                '').format(left=left['fingers'], right=right['fingers'], t=t))
+
+def process_line(line, heatmaps, opts, stamped_log = None):
+    m = re.search ('KL: col=(\d+), row=(\d+), pressed=(\d+), layer=(.*)', line)
+    if not m:
+        return False
+    if stamped_log is not None:
+        if line.startswith("KL:"):
+            print ("%10.10f %s" % (time.time(), line),
+                   file = stamped_log, end = '')
+        else:
+            print (line,
+                   file = stamped_log, end = '')
+        stamped_log.flush()
+
+    (c, r, l) = (int(m.group (2)), int(m.group (1)), m.group (4))
+    if (c, r) not in opts.allowed_keys:
+        return False
+
+    heatmaps[l].update_log ((c, r))
+
+    return True
+
+def setup_allowed_keys(opts):
+    if len(opts.only_key):
+        incmap={}
+        for v in opts.only_key:
+            m = re.search ('(\d+),(\d+)', v)
+            if not m:
+                continue
+            (c, r) = (int(m.group(1)), int(m.group(2)))
+            incmap[(c, r)] = True
+    else:
+        incmap={}
+        for r in range(0, 6):
+            for c in range(0, 14):
+                incmap[(c, r)] = True
 
+        for v in opts.ignore_key:
+            m = re.search ('(\d+),(\d+)', v)
+            if not m:
+                continue
+            (c, r) = (int(m.group(1)), int(m.group(2)))
+            del(incmap[(c, r)])
+
+    return incmap
+
+def main(opts):
     heatmaps = {"Dvorak": Heatmap("Dvorak"),
                 "ADORE": Heatmap("ADORE")
     }
     cnt = 0
-    restrict_row = opts.restrict_row
     out_dir = opts.outdir
 
+    if not os.path.exists(out_dir):
+        os.makedirs(out_dir)
+
+    opts.allowed_keys = setup_allowed_keys(opts)
+
+    if not opts.one_shot:
+
+        try:
+            with open("%s/stamped-log" % out_dir, "r") as f:
+                while True:
+                    line = f.readline()
+                    if not line:
+                        break
+                    if not process_line(line, heatmaps, opts):
+                        continue
+        except:
+            pass
+
+        stamped_log = open ("%s/stamped-log" % (out_dir), "a+")
+    else:
+        stamped_log = None
+
     while True:
         line = sys.stdin.readline()
         if not line:
             break
-        m = re.search ('KL: col=(\d+), row=(\d+), pressed=(\d+), layer=(.*)', line)
-        if not m:
+        if not process_line(line, heatmaps, opts, stamped_log):
             continue
 
         cnt = cnt + 1
-        (c, r, l) = (int(m.group (2)), int(m.group (1)), m.group (4))
-        if restrict_row != -1 and r != restrict_row:
-            continue
-        if c in opts.ignore_columns:
-            continue
-
-        heatmaps[l].update_log ((c, r))
 
-        if opts.dump_interval != -1 and cnt >= opts.dump_interval:
+        if opts.dump_interval != -1 and cnt >= opts.dump_interval and not opts.one_shot:
             cnt = 0
             dump_all(out_dir, heatmaps)
 
@@ -239,11 +323,17 @@ if __name__ == "__main__":
     parser = argparse.ArgumentParser (description = "keylog to heatmap processor")
     parser.add_argument ('outdir', action = 'store',
                          help = 'Output directory')
-    parser.add_argument ('--row', dest = 'restrict_row', action = 'store', type = int,
-                         default = -1, help = 'Restrict processing to this row only')
     parser.add_argument ('--dump-interval', dest = 'dump_interval', action = 'store', type = int,
                          default = 100, help = 'Dump stats and heatmap at every Nth event, -1 for dumping at EOF only')
-    parser.add_argument ('--ignore-column', dest = 'ignore_columns', action = 'append', type = int,
-                         default = [], help = 'Ignore the specified columns')
+    parser.add_argument ('--ignore-key', dest = 'ignore_key', action = 'append', type = str,
+                         default = [], help = 'Ignore the key at position (x, y)')
+    parser.add_argument ('--only-key', dest = 'only_key', action = 'append', type = str,
+                         default = [], help = 'Only include key at position (x, y)')
+    parser.add_argument ('--one-shot', dest = 'one_shot', action = 'store_true',
+                         help = 'Do not load previous data, and do not update it, either.')
     args = parser.parse_args()
+    if len(args.ignore_key) and len(args.only_key):
+        print ("--ignore-key and --only-key are mutually exclusive, please only use one of them!",
+               file = sys.stderr)
+        sys.exit(1)
     main(args)
diff --git a/keyboards/ergodox/keymaps/algernon/tools/max-focused b/keyboards/ergodox/keymaps/algernon/tools/max-focused
deleted file mode 100755
index 4d5220aa8b..0000000000
--- a/keyboards/ergodox/keymaps/algernon/tools/max-focused
+++ /dev/null
@@ -1,5 +0,0 @@
-#! /bin/sh
-WIN="$(xdotool getactivewindow)"
-wmctrl -i -r ${WIN} -b remove,maximized_vert,maximized_horz
-xdotool windowsize ${WIN} 100% 100%
-wmctrl -i -r ${WIN} -b add,maximized_vert,maximized_horz
diff --git a/keyboards/ergodox/keymaps/algernon/tools/text-to-log.py b/keyboards/ergodox/keymaps/algernon/tools/text-to-log.py
new file mode 100755
index 0000000000..e068c3cbfb
--- /dev/null
+++ b/keyboards/ergodox/keymaps/algernon/tools/text-to-log.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+
+charmap = {
+    '9': [[1, 0]],
+    '7': [[2, 0]], '@': [[2, 5], [2, 0]],
+    '5': [[3, 0]], '*': [[2, 5], [3, 0]],
+    '3': [[4, 0]], '^': [[2, 5], [4, 0]],
+    '1': [[5, 0]], '$': [[2, 5], [5, 0]],
+    '0': [[8, 0]], '%': [[2, 5], [8, 0]],
+    '2': [[9, 0]], '!': [[2, 5], [9, 0]],
+    '4': [[10, 0]], '#': [[2, 5], [10, 0]],
+    '6': [[11, 0]], '&': [[2, 5], [11, 0]],
+    '8': [[12, 0]],
+
+    '`': [[0, 1]], '~': [[2, 5], [0, 1]],
+    'y': [[1, 1]], 'Y': [[2, 5], [1, 1]],
+    'w': [[2, 1]], 'W': [[2, 5], [2, 1]],
+    'g': [[3, 1]], 'G': [[2, 5], [3, 1]],
+    'l': [[4, 1]], 'L': [[2, 5], [4, 1]],
+    'm': [[5, 1]], 'M': [[2, 5], [5, 1]],
+    '[': [[6, 1]], '{': [[2, 5], [6, 1]], '(': [[6, 1], [6, 1]],
+    ']': [[7, 1]], '}': [[2, 5], [7, 1]], ')': [[7, 1], [7, 1]],
+    'f': [[8, 1]], 'F': [[2, 5], [8, 1]],
+    'h': [[9, 1]], 'H': [[2, 5], [9, 1]],
+    'c': [[10, 1]], 'C': [[2, 5], [10, 1]],
+    'p': [[11, 1]], 'P': [[2, 5], [11, 1]],
+    'x': [[12, 1]], 'X': [[2, 5], [12, 1]],
+    '\\': [[13, 1]], '|': [[2, 5], [13, 1]],
+
+    '\t': [[0, 2]],
+    'a': [[1, 2]], 'A': [[2, 5], [1, 2]],
+    'o': [[2, 2]], 'O': [[2, 5], [2, 2]],
+    'e': [[3, 2]], 'E': [[2, 5], [3, 2]],
+    'i': [[4, 2]], 'I': [[2, 5], [4, 2]],
+    'u': [[5, 2]], 'U': [[2, 5], [5, 2]],
+    'd': [[8, 2]], 'D': [[2, 5], [8, 2]],
+    'r': [[9, 2]], 'R': [[2, 5], [9, 2]],
+    't': [[10, 2]], 'T': [[2, 5], [10, 2]],
+    'n': [[11, 2]], 'N': [[2, 5], [11, 2]],
+    's': [[12, 2]], 'S': [[2, 5], [12, 2]],
+    '=': [[13, 2]], '+': [[2, 5], [13, 2]],
+
+    'z': [[1, 3]], 'Z': [[2, 5], [1, 3]],
+    'q': [[2, 3]], 'Q': [[2, 5], [2, 3]],
+    '\'': [[3, 3]], '"': [[2, 5], [3, 3]],
+    ',': [[4, 3]], '<': [[2, 5], [4, 3]],
+    '.': [[5, 3]], '>': [[2, 5], [5, 3]],
+    'b': [[8, 3]], 'B': [[2, 5], [8, 3]],
+    'k': [[9, 3]], 'K': [[2, 5], [9, 3]],
+    'v': [[10, 3]], 'V': [[2, 5], [10, 3]],
+    'j': [[11, 3]], 'J': [[2, 5], [11, 3]],
+    '/': [[12, 3]], '?': [[2, 5], [12, 3]],
+
+    ':': [[4, 4]], ';': [[4, 4], [4, 4]],
+    '-': [[9, 4]], '_': [[2, 5], [9, 4]],
+
+    ' ': [[10, 5]],
+    '\n': [[11, 5]],
+
+    ## Layered things
+    # Hungarian
+    'á': [[9, 5], [1, 2]],  'Á': [[2, 5], [9, 5], [1, 2]],
+    'ó': [[9, 5], [2, 2]],  'Ó': [[2, 5], [9, 5], [2, 2]],
+    'ő': [[9, 5], [2, 1]],  'Ő': [[2, 5], [9, 5], [2, 1]],
+    'ö': [[9, 5], [2, 3]],  'Ö': [[2, 5], [9, 5], [2, 3]],
+    'é': [[9, 5], [3, 2]],  'É': [[2, 5], [9, 5], [3, 2]],
+    'ú': [[9, 5], [4, 2]],  'Ú': [[2, 5], [9, 5], [4, 2]],
+    'ű': [[9, 5], [4, 1]],  'Ű': [[2, 5], [9, 5], [4, 1]],
+    'ü': [[9, 5], [4, 3]],  'Ü': [[2, 5], [9, 5], [4, 3]],
+    'í': [[9, 5], [5, 2]],  'Í': [[2, 5], [9, 5], [5, 2]],
+}
+
+def lookup_char(layer, ch):
+    if ch in charmap:
+        return charmap[ch]
+    return None
+
+def process_char(layer, ch, out=sys.stdout):
+    keys = lookup_char(layer, ch)
+    if not keys:
+        print ("Unknown char: %s" % ch, file=sys.stderr)
+    else:
+        for (c, r) in keys:
+            print ("KL: col=%d, row=%d, pressed=1, layer=%s" % (r, c, layer), file=out)
+            print ("KL: col=%d, row=%d, pressed=0, layer=%s" % (r, c, layer), file=out)
+
+def process_file(fn, layer, out=sys.stdout):
+    with open(fn, "r") as f:
+        ch = f.read(1)
+        while ch:
+            process_char(layer, ch, out)
+            ch = f.read(1)
+
+if sys.argv[1] == '-':
+    out='/dev/stdin'
+else:
+    out=sys.argv[1]
+
+if len(sys.argv) >= 2:
+    layer = 'ADORE'
+else:
+    layer = sys.argv[2]
+
+process_file(out, layer = layer)
-- 
cgit v1.2.3