aboutsummaryrefslogtreecommitdiff
path: root/layouts/community/ergodox/algernon/tools
diff options
context:
space:
mode:
authorJack Humbert <jack.humb@gmail.com>2017-08-23 22:29:07 -0400
committerGitHub <noreply@github.com>2017-08-23 22:29:07 -0400
commitd2ff66a985b938e87fffe55c1d9f1dc55e356f91 (patch)
tree561b3e203033849573a17f5ac6248077ab687676 /layouts/community/ergodox/algernon/tools
parent7260fc3eef98fb7b0e2ed24d3d0d14cf2e613000 (diff)
downloadqmk_firmware-d2ff66a985b938e87fffe55c1d9f1dc55e356f91.tar.gz
qmk_firmware-d2ff66a985b938e87fffe55c1d9f1dc55e356f91.zip
Creates a layouts/ folder for keymaps shared between keyboards (#1609)
* include variables and .h files as pp directives * start layout compilation * split ergodoxes up * don't compile all layouts for everything * might seg fault * reset layouts variable * actually reset layouts * include rules.mk instead * remove includes from rules.mk * update variable setting * load visualizer from path * adds some more examples * adds more layouts * more boards added * more boards added * adds documentation for layouts * use lowercase names for LAYOUT_ * add layout.json files for each layout * add community folder, default keymaps for layouts * touch-up default layouts * touch-up layouts, some keyboard rules.mk * update documentation for layouts * fix up serial/i2c switches
Diffstat (limited to 'layouts/community/ergodox/algernon/tools')
-rw-r--r--layouts/community/ergodox/algernon/tools/heatmap-layout.ADORE.json486
-rw-r--r--layouts/community/ergodox/algernon/tools/heatmap-layout.Dvorak.json477
-rw-r--r--layouts/community/ergodox/algernon/tools/hid-commands80
-rw-r--r--layouts/community/ergodox/algernon/tools/log-to-heatmap.py344
-rw-r--r--layouts/community/ergodox/algernon/tools/text-to-log.py107
5 files changed, 1494 insertions, 0 deletions
diff --git a/layouts/community/ergodox/algernon/tools/heatmap-layout.ADORE.json b/layouts/community/ergodox/algernon/tools/heatmap-layout.ADORE.json
new file mode 100644
index 000000000..e09efecc4
--- /dev/null
+++ b/layouts/community/ergodox/algernon/tools/heatmap-layout.ADORE.json
@@ -0,0 +1,486 @@
1[
2 {
3 "backcolor": "#ffffff",
4 "name": "ErgoDox - algernon's layout: Heatmap",
5 "author": "Gergely Nagy <kbd@gergo.csillger.hu>",
6 "notes": "See [here](https://github.com/algernon/ergodox-layout#readme) for the QMK keymap source.",
7 "switchMount": "cherry",
8 "switchBrand": "gateron",
9 "switchType": "KS-3-Tea",
10 "pcb": true,
11 "css": ".keyborder { -webkit-filter: blur(5px); filter: blur(5px); } .keytop { -webkit-filter: blur(10px); } .keylabels { border: 1px solid black; }"
12 },
13 [
14 {
15 "x": 3.5,
16 "fa": [
17 0,
18 0,
19 2
20 ]
21 },
22 "*\n5\nF5",
23 {
24 "x": 10.5,
25 "a": 4,
26 "fa": [
27 0,
28 0,
29 2
30 ]
31 },
32 "#\n4\nF4"
33 ],
34 [
35 {
36 "y": -0.875,
37 "x": 2.5
38 },
39 "@\n7\nF7",
40 {
41 "x": 1
42 },
43 "^\n3\nF3",
44 {
45 "x": 8.5
46 },
47 "!\n2\nF2",
48 {
49 "x": 1
50 },
51 "&\n6\nF6"
52 ],
53 [
54 {
55 "y": -0.875,
56 "x": 5.5
57 },
58 "$\n1\nF1",
59 {
60 "a": 7,
61 "f": 3
62 },
63 "F11",
64 {
65 "x": 4.5,
66 "f": 3
67 },
68 "Fx",
69 {
70 "a": 4,
71 "f": 3,
72 "fa": [
73 0,
74 0,
75 2
76 ]
77 },
78 "%\n0\nF10"
79 ],
80 [
81 {
82 "y": -0.875,
83 "f": 9,
84 "a": 6,
85 "w": 1.5
86 },
87 "\n\n<i class='kb kb-Multimedia-Play-Pause'></i>",
88 {
89 "f": 3,
90 "a": 4,
91 "fa": [
92 0,
93 0,
94 2
95 ]
96 },
97 " \n9\nF9",
98 {
99 "x": 14.5
100 },
101 " \n8\nF8",
102 {
103 "a": 7,
104 "w": 1.5
105 },
106 "STENO"
107 ],
108 [
109 {
110 "y": -0.375,
111 "x": 3.5,
112 "a": 6
113 },
114 "C",
115 {
116 "x": 10.5
117 },
118 "L"
119 ],
120 [
121 {
122 "y": -0.875,
123 "x": 2.5,
124 "a": 6
125 },
126 "W",
127 {
128 "x": 1,
129 "a": 6
130 },
131 "H",
132 {
133 "x": 8.5
134 },
135 "G",
136 {
137 "x": 1
138 },
139 "P"
140 ],
141 [
142 {
143 "y": -0.875,
144 "x": 5.5
145 },
146 "F",
147 {
148 "a": 4,
149 "fa": [0, 0, 0],
150 "h": 1.5
151 },
152 "{\n(\n[",
153 {
154 "x": 4.5,
155 "h": 1.5
156 },
157 "}\n)\n]",
158 {
159 "a": 6
160 },
161 "M"
162 ],
163 [
164 {
165 "y": -0.875,
166 "f": 3,
167 "a": 4,
168 "w": 1.5
169 },
170 "\n\n|\n\\",
171 {
172 "a": 6,
173 "f": 3
174 },
175 "X",
176 {
177 "x": 14.5,
178 "a": 4
179 },
180 "/\n?",
181 {
182 "a": 4,
183 "w": 1.5
184 },
185 "~\n`"
186 ],
187 [
188 {
189 "y": -0.375,
190 "x": 3.5,
191 "a": 6
192 },
193 "E",
194 {
195 "x": 10.5
196 },
197 "T"
198 ],
199 [
200 {
201 "y": -0.875,
202 "x": 2.5
203 },
204 "O",
205 {
206 "x": 1,
207 "n": true
208 },
209 "I",
210 {
211 "x": 8.5,
212 "n": true
213 },
214 "R",
215 {
216 "x": 1
217 },
218 "N"
219 ],
220 [
221 {
222 "y": -0.875,
223 "x": 5.5
224 },
225 "U",
226 {
227 "x": 6.5
228 },
229 "D"
230 ],
231 [
232 {
233 "y": -0.875,
234 "fa": [
235 6
236 ],
237 "w": 1.5
238 },
239 "<i class='fa fa-arrows'></i>\n\nTab",
240 {
241 "f": 3
242 },
243 "A",
244 {
245 "x": 14.5,
246 "f": 3
247 },
248 "S",
249 {
250 "a": 4,
251 "fa": [
252 0,
253 0,
254 0,
255 0,
256 0,
257 0,
258 0,
259 6
260 ],
261 "w": 1.5
262 },
263 "+\n="
264 ],
265 [
266 {
267 "y": -0.625,
268 "x": 6.5,
269 "a": 7,
270 "f": 9,
271 "h": 1.5
272 },
273 "<i class='fa fa-columns'></i>",
274 {
275 "x": 4.5,
276 "h": 1.5
277 },
278 "<i class='fa fa-table'></i>"
279 ],
280 [
281 {
282 "y": -0.75,
283 "x": 3.5,
284 "a": 4,
285 "f": 3
286 },
287 "\"\n'",
288 {
289 "x": 10.5,
290 "a": 6,
291 "f": 3
292 },
293 "V"
294 ],
295 [
296 {
297 "y": -0.875,
298 "x": 2.5,
299 "a": 6
300 },
301 "Q",
302 {
303 "x": 1,
304 "a": 4
305 },
306 "<\n,",
307 {
308 "x": 8.5,
309 "a": 6
310 },
311 "K",
312 {
313 "x": 1
314 },
315 "Y"
316 ],
317 [
318 {
319 "y": -0.875,
320 "x": 5.5,
321 "a": 4
322 },
323 ">\n.",
324 {
325 "x": 6.5,
326 "a": 6
327 },
328 "B"
329 ],
330 [
331 {
332 "y": -0.875,
333 "f": 9,
334 "w": 1.5,
335 "g": true
336 },
337 "",
338 {
339 "a": 6,
340 "f": 3,
341 "g": false
342 },
343 "Z",
344 {
345 "x": 14.5
346 },
347 "J",
348 {
349 "f": 9,
350 "g": true,
351 "w": 1.5,
352 "a": 4
353 },
354 ""
355 ],
356 [
357 {
358 "y": -0.375,
359 "x": 3.5,
360 "g": true,
361 "a": 7,
362 "f": 3
363 },
364 "",
365 {
366 "x": 10.5
367 },
368 ""
369 ],
370 [
371 {
372 "y": -0.875,
373 "x": 2.5
374 },
375 "",
376 {
377 "x": 1,
378 "g": false,
379 "a": 5
380 },
381 ";\n:",
382 {
383 "x": 8.5
384 },
385 "_\n-",
386 {
387 "x": 1,
388 "g": true,
389 "a": 7
390 },
391 ""
392 ],
393 [
394 {
395 "y": -0.75,
396 "x": 0.5
397 },
398 "",
399 {},
400 "",
401 {
402 "x": 14.5
403 },
404 "",
405 {},
406 ""
407 ],
408 [
409 {
410 "r": 30,
411 "rx": 6.5,
412 "ry": 4.25,
413 "y": -1,
414 "x": 1,
415 "g": false
416 },
417 "Alt",
418 {
419 "a": 4,
420 "fa": [
421 0,
422 0,
423 0,
424 9
425 ]
426 },
427 "\n\n\n<i class='kb kb-logo-linux-debian fa-large'></i>"
428 ],
429 [
430 {
431 "a": 7,
432 "f": 9,
433 "h": 2
434 },
435 "<i class='kb kb-Unicode-BackSpace-DeleteLeft-Big'></i>",
436 {
437 "h": 2
438 },
439 "<i class='fa fa-angle-double-up'></i>",
440 {
441 "f": 3
442 },
443 "Ctrl"
444 ],
445 [
446 {
447 "x": 2
448 },
449 "ESC"
450 ],
451 [
452 {
453 "r": -30,
454 "rx": 13,
455 "y": -1,
456 "x": -3,
457 "f": 2
458 },
459 "MEDIA",
460 {},
461 "DEL"
462 ],
463 [
464 {
465 "x": -3
466 },
467 "HUN",
468 {
469 "f": 9,
470 "h": 2
471 },
472 "<i class='kb kb-Return-2'></i>",
473 {
474 "f": 3,
475 "h": 2
476 },
477 "SPC"
478 ],
479 [
480 {
481 "x": -3,
482 "f": 2
483 },
484 "LEAD"
485 ]
486]
diff --git a/layouts/community/ergodox/algernon/tools/heatmap-layout.Dvorak.json b/layouts/community/ergodox/algernon/tools/heatmap-layout.Dvorak.json
new file mode 100644
index 000000000..1e53281c5
--- /dev/null
+++ b/layouts/community/ergodox/algernon/tools/heatmap-layout.Dvorak.json
@@ -0,0 +1,477 @@
1[
2 {
3 "backcolor": "#ffffff",
4 "name": "ErgoDox - algernon's layout: Heatmap",
5 "author": "Gergely Nagy <kbd@gergo.csillger.hu>",
6 "notes": "See [here](https://github.com/algernon/ergodox-layout#readme) for the QMK keymap source.",
7 "switchMount": "cherry",
8 "switchBrand": "gateron",
9 "switchType": "KS-3-Tea",
10 "pcb": true,
11 "css": ".keyborder { -webkit-filter: blur(5px); filter: blur(5px); } .keytop { -webkit-filter: blur(10px); } .keylabels { border: 1px solid black; }"
12 },
13 [
14 {
15 "x": 3.5,
16 "fa": [
17 0,
18 0,
19 2
20 ]
21 },
22 "*\n5\nF5",
23 {
24 "x": 10.5,
25 "a": 4,
26 "fa": [
27 0,
28 0,
29 2
30 ]
31 },
32 "#\n4\nF4"
33 ],
34 [
35 {
36 "y": -0.875,
37 "x": 2.5
38 },
39 "@\n7\nF7",
40 {
41 "x": 1
42 },
43 "^\n3\nF3",
44 {
45 "x": 8.5
46 },
47 "!\n2\nF2",
48 {
49 "x": 1
50 },
51 "&\n6\nF6"
52 ],
53 [
54 {
55 "y": -0.875,
56 "x": 5.5
57 },
58 "$\n1\nF1",
59 {
60 "a": 7,
61 "f": 3
62 },
63 "F11",
64 {
65 "x": 4.5,
66 "f": 3
67 },
68 "Fx",
69 {
70 "a": 4,
71 "f": 3,
72 "fa": [
73 0,
74 0,
75 2
76 ]
77 },
78 "%\n0\nF10"
79 ],
80 [
81 {
82 "y": -0.875,
83 "f": 6,
84 "a": 6,
85 "w": 1.5
86 },
87 "<i class='fa fa-fast-backward'></i>\n\n<i class='fa fa-fast-forward'></i>",
88 {
89 "f": 3,
90 "a": 4,
91 "fa": [
92 0,
93 0,
94 2
95 ]
96
97 },
98 " \n9\nF9",
99 {
100 "x": 14.5
101 },
102 " \n8\nF8",
103 {
104 "a": 7,
105 "w": 1.5
106 },
107 "STENO"
108 ],
109 [
110 {
111 "y": -0.375,
112 "x": 3.5,
113 "a": 4
114 },
115 ">\n.",
116 {
117 "x": 10.5,
118 "a": 6
119 },
120 "C"
121 ],
122 [
123 {
124 "y": -0.875,
125 "x": 2.5,
126 "a": 4
127 },
128 "<\n,",
129 {
130 "x": 1,
131 "a": 6
132 },
133 "P",
134 {
135 "x": 8.5
136 },
137 "G",
138 {
139 "x": 1
140 },
141 "R"
142 ],
143 [
144 {
145 "y": -0.875,
146 "x": 5.5
147 },
148 "Y",
149 {
150 "a": 4,
151 "h": 1.5
152 },
153 "{\n(\n[",
154 {
155 "x": 4.5,
156 "h": 1.5
157 },
158 "}\n)\n]",
159 {
160 "a": 6
161 },
162 "F"
163 ],
164 [
165 {
166 "y": -0.875,
167 "f": 3,
168 "a": 4,
169 "w": 1.5
170 },
171 "\n\n~\n`",
172 {
173 "a": 4,
174 "f": 3
175 },
176 "\"\n'",
177 {
178 "x": 14.5,
179 "a": 6
180 },
181 "L",
182 {
183 "a": 4,
184 "w": 1.5
185 },
186 "|\n\\"
187 ],
188 [
189 {
190 "y": -0.375,
191 "x": 3.5,
192 "a": 6
193 },
194 "E",
195 {
196 "x": 10.5
197 },
198 "T"
199 ],
200 [
201 {
202 "y": -0.875,
203 "x": 2.5
204 },
205 "O",
206 {
207 "x": 1,
208 "n": true
209 },
210 "U",
211 {
212 "x": 8.5,
213 "n": true
214 },
215 "H",
216 {
217 "x": 1
218 },
219 "N"
220 ],
221 [
222 {
223 "y": -0.875,
224 "x": 5.5
225 },
226 "I",
227 {
228 "x": 6.5
229 },
230 "D"
231 ],
232 [
233 {
234 "y": -0.875,
235 "fa": [
236 6
237 ],
238 "w": 1.5
239 },
240 "<i class='fa fa-arrows'></i>\n\nTab",
241 {
242 "f": 3
243 },
244 "A",
245 {
246 "x": 14.5,
247 "f": 3
248 },
249 "S",
250 {
251 "a": 4,
252 "fa": [
253 0,
254 0,
255 0,
256 0,
257 0,
258 0,
259 0,
260 6
261 ],
262 "w": 1.5
263 },
264 "+\n="
265 ],
266 [
267 {
268 "y": -0.625,
269 "x": 6.5,
270 "a": 7,
271 "f": 9,
272 "h": 1.5
273 },
274 "<i class='fa fa-columns'></i>",
275 {
276 "x": 4.5,
277 "h": 1.5
278 },
279 "<i class='fa fa-table'></i>"
280 ],
281 [
282 {
283 "y": -0.75,
284 "x": 3.5,
285 "f": 3,
286 "a": 6
287 },
288 "J",
289 {
290 "x": 10.5
291 },
292 "W"
293 ],
294 [
295 {
296 "y": -0.875,
297 "x": 2.5
298 },
299 "Q",
300 {
301 "x": 1
302 },
303 "K",
304 {
305 "x": 8.5
306 },
307 "M",
308 {
309 "x": 1
310 },
311 "V"
312 ],
313 [
314 {
315 "y": -0.875,
316 "x": 5.5
317 },
318 "X",
319 {
320 "x": 6.5
321 },
322 "B"
323 ],
324 [
325 {
326 "y": -0.875,
327 "f": 9,
328 "w": 1.5
329 },
330 "\n\n<i class='kb kb-Multimedia-Play-Pause'></i>",
331 {
332 "a": 4,
333 "f": 3
334 },
335 "?\n/",
336 {
337 "x": 14.5,
338 "a": 6
339 },
340 "Z",
341 {
342 "f": 9,
343 "w": 1.5
344 },
345 "<i class='kb kb-Multimedia-Stop'></i>"
346 ],
347 [
348 {
349 "y": -0.375,
350 "x": 3.5,
351 "g": true,
352 "a": 7,
353 "f": 3
354 },
355 "",
356 {
357 "x": 10.5
358 },
359 ""
360 ],
361 [
362 {
363 "y": -0.875,
364 "x": 2.5
365 },
366 "",
367 {
368 "x": 1,
369 "g": false,
370 "a": 5
371 },
372 ";\n:",
373 {
374 "x": 8.5
375 },
376 "_\n-",
377 {
378 "x": 1,
379 "g": true,
380 "a": 7
381 },
382 ""
383 ],
384 [
385 {
386 "y": -0.75,
387 "x": 0.5
388 },
389 "",
390 {},
391 "",
392 {
393 "x": 14.5
394 },
395 "",
396 {},
397 ""
398 ],
399 [
400 {
401 "r": 30,
402 "rx": 6.5,
403 "ry": 4.25,
404 "y": -1,
405 "x": 1,
406 "g": false
407 },
408 "Alt",
409 {
410 "a": 4,
411 "fa": [
412 0,
413 0,
414 0,
415 9
416 ]
417 },
418 "\n\n\n<i class='kb kb-logo-linux-debian fa-large'></i>"
419 ],
420 [
421 {
422 "a": 7,
423 "f": 9,
424 "h": 2
425 },
426 "<i class='kb kb-Unicode-BackSpace-DeleteLeft-Big'></i>",
427 {
428 "h": 2
429 },
430 "<i class='fa fa-angle-double-up'></i>",
431 {
432 "f": 3
433 },
434 "Ctrl"
435 ],
436 [
437 {
438 "x": 2
439 },
440 "ESC"
441 ],
442 [
443 {
444 "r": -30,
445 "rx": 13,
446 "y": -1,
447 "x": -3,
448 "f": 2
449 },
450 "MEDIA",
451 {},
452 "DEL"
453 ],
454 [
455 {
456 "x": -3
457 },
458 "LEAD",
459 {
460 "f": 9,
461 "h": 2
462 },
463 "<i class='kb kb-Return-2'></i>",
464 {
465 "f": 3,
466 "h": 2
467 },
468 "SPC"
469 ],
470 [
471 {
472 "x": -3,
473 "f": 2
474 },
475 "HUN"
476 ]
477]
diff --git a/layouts/community/ergodox/algernon/tools/hid-commands b/layouts/community/ergodox/algernon/tools/hid-commands
new file mode 100644
index 000000000..54ca7556a
--- /dev/null
+++ b/layouts/community/ergodox/algernon/tools/hid-commands
@@ -0,0 +1,80 @@
1#!/bin/bash
2set -e
3
4LAST_APPSEL_START=0
5
6cmd_wm () {
7 WIN="$(xdotool getactivewindow)"
8 wmctrl -i -r ${WIN} -b remove,maximized_vert,maximized_horz
9 xdotool windowsize ${WIN} 100% 100%
10 wmctrl -i -r ${WIN} -b add,maximized_vert,maximized_horz
11}
12
13_cmd_appsel () {
14 wmctrl -x -a $1 || true
15 xdotool key Escape
16}
17
18cmd_appsel_music () {
19 wmctrl -x -a rhythmbox || wmctrl -x -a spotify || \
20 wmctrl -x -a banshee || wmctrl -x -a kodi || true
21 xdotool key Escape
22}
23
24cmd_appsel_slack () {
25 _cmd_appsel slack
26}
27
28cmd_appsel_emacs () {
29 _cmd_appsel emacs
30}
31
32cmd_appsel_term () {
33 _cmd_appsel gnome-terminal
34}
35
36cmd_appsel_chrome () {
37 _cmd_appsel chrom
38}
39
40cmd_appsel_start () {
41 if [ ! -z "${DISABLE_APPSEL_START}" ]; then
42 return
43 fi
44
45 APPSEL_START=$(date +%s)
46 if [ $APPSEL_START -lt $(expr $LAST_APPSEL_START + 10) ]; then
47 return
48 fi
49 LAST_APPSEL_START=$APPSEL_START
50 notify-send -t 1000 "Please select an application!" -c device -u low \
51 -i /usr/share/icons/Adwaita/24x24/devices/video-display.png
52}
53
54cmd_reflash () {
55 teensy_loader_cli -v -w ~/src/ext/qmk_firmware/algernon.hex --mcu atmega32u4 || true
56}
57
58cmd_help () {
59 cat <<EOF
60Use the source, Luke!
61EOF
62}
63
64while read l; do
65 case "$l" in
66 "CMD:"*)
67 ;;
68 *)
69 continue
70 ;;
71 esac
72
73 cmd="$(echo $l | cut -d: -f2-)"
74
75 echo "Got command: ${cmd}"
76
77 if type cmd_${cmd} >/dev/null 2>&1; then
78 cmd_${cmd}
79 fi
80done
diff --git a/layouts/community/ergodox/algernon/tools/log-to-heatmap.py b/layouts/community/ergodox/algernon/tools/log-to-heatmap.py
new file mode 100644
index 000000000..e927e0e39
--- /dev/null
+++ b/layouts/community/ergodox/algernon/tools/log-to-heatmap.py
@@ -0,0 +1,344 @@
1#! /usr/bin/env python3
2import json
3import os
4import sys
5import re
6import argparse
7import time
8
9from math import floor
10from os.path import dirname
11from subprocess import Popen, PIPE, STDOUT
12from blessings import Terminal
13
14class Heatmap(object):
15 coords = [
16 [
17 # Row 0
18 [ 4, 0], [ 4, 2], [ 2, 0], [ 1, 0], [ 2, 2], [ 3, 0], [ 3, 2],
19 [ 3, 4], [ 3, 6], [ 2, 4], [ 1, 2], [ 2, 6], [ 4, 4], [ 4, 6],
20 ],
21 [
22 # Row 1
23 [ 8, 0], [ 8, 2], [ 6, 0], [ 5, 0], [ 6, 2], [ 7, 0], [ 7, 2],
24 [ 7, 4], [ 7, 6], [ 6, 4], [ 5, 2], [ 6, 6], [ 8, 4], [ 8, 6],
25 ],
26 [
27 # Row 2
28 [12, 0], [12, 2], [10, 0], [ 9, 0], [10, 2], [11, 0], [ ],
29 [ ], [11, 2], [10, 4], [ 9, 2], [10, 6], [12, 4], [12, 6],
30 ],
31 [
32 # Row 3
33 [17, 0], [17, 2], [15, 0], [14, 0], [15, 2], [16, 0], [13, 0],
34 [13, 2], [16, 2], [15, 4], [14, 2], [15, 6], [17, 4], [17, 6],
35 ],
36 [
37 # Row 4
38 [20, 0], [20, 2], [19, 0], [18, 0], [19, 2], [], [], [], [],
39 [19, 4], [18, 2], [19, 6], [20, 4], [20, 6], [], [], [], []
40 ],
41 [
42 # Row 5
43 [ ], [23, 0], [22, 2], [22, 0], [22, 4], [21, 0], [21, 2],
44 [24, 0], [24, 2], [25, 0], [25, 4], [25, 2], [26, 0], [ ],
45 ],
46 ]
47
48 def set_attr_at(self, block, n, attr, fn, val):
49 blk = self.heatmap[block][n]
50 if attr in blk:
51 blk[attr] = fn(blk[attr], val)
52 else:
53 blk[attr] = fn(None, val)
54
55 def coord(self, col, row):
56 return self.coords[row][col]
57
58 @staticmethod
59 def set_attr(orig, new):
60 return new
61
62 def set_bg(self, coords, color):
63 (block, n) = coords
64 self.set_attr_at(block, n, "c", self.set_attr, color)
65 #self.set_attr_at(block, n, "g", self.set_attr, False)
66
67 def set_tap_info(self, coords, count, cap):
68 (block, n) = coords
69 def _set_tap_info(o, _count, _cap):
70 ns = 4 - o.count ("\n")
71 return o + "\n" * ns + "%.02f%%" % (float(_count) / float(_cap) * 100)
72
73 if not cap:
74 cap = 1
75 self.heatmap[block][n + 1] = _set_tap_info (self.heatmap[block][n + 1], count, cap)
76
77 @staticmethod
78 def heatmap_color (v):
79 colors = [ [0.3, 0.3, 1], [0.3, 1, 0.3], [1, 1, 0.3], [1, 0.3, 0.3]]
80 fb = 0
81 if v <= 0:
82 idx1, idx2 = 0, 0
83 elif v >= 1:
84 idx1, idx2 = len(colors) - 1, len(colors) - 1
85 else:
86 val = v * (len(colors) - 1)
87 idx1 = int(floor(val))
88 idx2 = idx1 + 1
89 fb = val - float(idx1)
90
91 r = (colors[idx2][0] - colors[idx1][0]) * fb + colors[idx1][0]
92 g = (colors[idx2][1] - colors[idx1][1]) * fb + colors[idx1][1]
93 b = (colors[idx2][2] - colors[idx1][2]) * fb + colors[idx1][2]
94
95 r, g, b = [x * 255 for x in (r, g, b)]
96 return "#%02x%02x%02x" % (int(r), int(g), int(b))
97
98 def __init__(self, layout):
99 self.log = {}
100 self.total = 0
101 self.max_cnt = 0
102 self.layout = layout
103
104 def update_log(self, coords):
105 (c, r) = coords
106 if not (c, r) in self.log:
107 self.log[(c, r)] = 0
108 self.log[(c, r)] = self.log[(c, r)] + 1
109 self.total = self.total + 1
110 if self.max_cnt < self.log[(c, r)]:
111 self.max_cnt = self.log[(c, r)]
112
113 def get_heatmap(self):
114 with open("%s/heatmap-layout.%s.json" % (dirname(sys.argv[0]), self.layout), "r") as f:
115 self.heatmap = json.load (f)
116
117 ## Reset colors
118 for row in self.coords:
119 for coord in row:
120 if coord != []:
121 self.set_bg (coord, "#d9dae0")
122
123 for (c, r) in self.log:
124 coords = self.coord(c, r)
125 b, n = coords
126 cap = self.max_cnt
127 if cap == 0:
128 cap = 1
129 v = float(self.log[(c, r)]) / cap
130 self.set_bg (coords, self.heatmap_color (v))
131 self.set_tap_info (coords, self.log[(c, r)], self.total)
132 return self.heatmap
133
134 def get_stats(self):
135 usage = [
136 # left hand
137 [0, 0, 0, 0, 0],
138 # right hand
139 [0, 0, 0, 0, 0]
140 ]
141 finger_map = [0, 0, 1, 2, 3, 3, 3, 1, 1, 1, 2, 3, 4, 4]
142 for (c, r) in self.log:
143 if r == 5: # thumb cluster
144 if c <= 6: # left side
145 usage[0][4] = usage[0][4] + self.log[(c, r)]
146 else:
147 usage[1][0] = usage[1][0] + self.log[(c, r)]
148 elif r == 4 and (c == 4 or c == 9): # bottom row thumb keys
149 if c <= 6: # left side
150 usage[0][4] = usage[0][4] + self.log[(c, r)]
151 else:
152 usage[1][0] = usage[1][0] + self.log[(c, r)]
153 else:
154 fc = c
155 hand = 0
156 if fc >= 7:
157 hand = 1
158 fm = finger_map[fc]
159 usage[hand][fm] = usage[hand][fm] + self.log[(c, r)]
160 hand_usage = [0, 0]
161 for f in usage[0]:
162 hand_usage[0] = hand_usage[0] + f
163 for f in usage[1]:
164 hand_usage[1] = hand_usage[1] + f
165
166 total = self.total
167 if total == 0:
168 total = 1
169 stats = {
170 "total-keys": total,
171 "hands": {
172 "left": {
173 "usage": round(float(hand_usage[0]) / total * 100, 2),
174 "fingers": {
175 "pinky": 0,
176 "ring": 0,
177 "middle": 0,
178 "index": 0,
179 "thumb": 0,
180 }
181 },
182 "right": {
183 "usage": round(float(hand_usage[1]) / total * 100, 2),
184 "fingers": {
185 "thumb": 0,
186 "index": 0,
187 "middle": 0,
188 "ring": 0,
189 "pinky": 0,
190 }
191 },
192 }
193 }
194
195 hmap = ['left', 'right']
196 fmap = ['pinky', 'ring', 'middle', 'index', 'thumb',
197 'thumb', 'index', 'middle', 'ring', 'pinky']
198 for hand_idx in range(len(usage)):
199 hand = usage[hand_idx]
200 for finger_idx in range(len(hand)):
201 stats['hands'][hmap[hand_idx]]['fingers'][fmap[finger_idx + hand_idx * 5]] = round(float(hand[finger_idx]) / total * 100, 2)
202 return stats
203
204def dump_all(out_dir, heatmaps):
205 stats = {}
206 t = Terminal()
207 t.clear()
208 sys.stdout.write("\x1b[2J\x1b[H")
209
210 print ('{t.underline}{outdir}{t.normal}\n'.format(t=t, outdir=out_dir))
211
212 keys = list(heatmaps.keys())
213 keys.sort()
214
215 for layer in keys:
216 if len(heatmaps[layer].log) == 0:
217 continue
218
219 with open ("%s/%s.json" % (out_dir, layer), "w") as f:
220 json.dump(heatmaps[layer].get_heatmap(), f)
221 stats[layer] = heatmaps[layer].get_stats()
222
223 left = stats[layer]['hands']['left']
224 right = stats[layer]['hands']['right']
225
226 print ('{t.bold}{layer}{t.normal} ({total:,} taps):'.format(t=t, layer=layer,
227 total=int(stats[layer]['total-keys'] / 2)))
228 print (('{t.underline} | ' + \
229 'left ({l[usage]:6.2f}%) | ' + \
230 'right ({r[usage]:6.2f}%) |{t.normal}').format(t=t, l=left, r=right))
231 print ((' {t.bright_magenta}pinky{t.white} | {left[pinky]:6.2f}% | {right[pinky]:6.2f}% |\n' + \
232 ' {t.bright_cyan}ring{t.white} | {left[ring]:6.2f}% | {right[ring]:6.2f}% |\n' + \
233 ' {t.bright_blue}middle{t.white} | {left[middle]:6.2f}% | {right[middle]:6.2f}% |\n' + \
234 ' {t.bright_green}index{t.white} | {left[index]:6.2f}% | {right[index]:6.2f}% |\n' + \
235 ' {t.bright_red}thumb{t.white} | {left[thumb]:6.2f}% | {right[thumb]:6.2f}% |\n' + \
236 '').format(left=left['fingers'], right=right['fingers'], t=t))
237
238def process_line(line, heatmaps, opts, stamped_log = None):
239 m = re.search ('KL: col=(\d+), row=(\d+), pressed=(\d+), layer=(.*)', line)
240 if not m:
241 return False
242 if stamped_log is not None:
243 if line.startswith("KL:"):
244 print ("%10.10f %s" % (time.time(), line),
245 file = stamped_log, end = '')
246 else:
247 print (line,
248 file = stamped_log, end = '')
249 stamped_log.flush()
250
251 (c, r, l) = (int(m.group (2)), int(m.group (1)), m.group (4))
252 if (c, r) not in opts.allowed_keys:
253 return False
254
255 heatmaps[l].update_log ((c, r))
256
257 return True
258
259def setup_allowed_keys(opts):
260 if len(opts.only_key):
261 incmap={}
262 for v in opts.only_key:
263 m = re.search ('(\d+),(\d+)', v)
264 if not m:
265 continue
266 (c, r) = (int(m.group(1)), int(m.group(2)))
267 incmap[(c, r)] = True
268 else:
269 incmap={}
270 for r in range(0, 6):
271 for c in range(0, 14):
272 incmap[(c, r)] = True
273
274 for v in opts.ignore_key:
275 m = re.search ('(\d+),(\d+)', v)
276 if not m:
277 continue
278 (c, r) = (int(m.group(1)), int(m.group(2)))
279 del(incmap[(c, r)])
280
281 return incmap
282
283def main(opts):
284 heatmaps = {"Dvorak": Heatmap("Dvorak"),
285 "ADORE": Heatmap("ADORE")
286 }
287 cnt = 0
288 out_dir = opts.outdir
289
290 if not os.path.exists(out_dir):
291 os.makedirs(out_dir)
292
293 opts.allowed_keys = setup_allowed_keys(opts)
294
295 if not opts.one_shot:
296
297 try:
298 with open("%s/stamped-log" % out_dir, "r") as f:
299 while True:
300 line = f.readline()
301 if not line:
302 break
303 if not process_line(line, heatmaps, opts):
304 continue
305 except:
306 pass
307
308 stamped_log = open ("%s/stamped-log" % (out_dir), "a+")
309 else:
310 stamped_log = None
311
312 while True:
313 line = sys.stdin.readline()
314 if not line:
315 break
316 if not process_line(line, heatmaps, opts, stamped_log):
317 continue
318
319 cnt = cnt + 1
320
321 if opts.dump_interval != -1 and cnt >= opts.dump_interval and not opts.one_shot:
322 cnt = 0
323 dump_all(out_dir, heatmaps)
324
325 dump_all (out_dir, heatmaps)
326
327if __name__ == "__main__":
328 parser = argparse.ArgumentParser (description = "keylog to heatmap processor")
329 parser.add_argument ('outdir', action = 'store',
330 help = 'Output directory')
331 parser.add_argument ('--dump-interval', dest = 'dump_interval', action = 'store', type = int,
332 default = 100, help = 'Dump stats and heatmap at every Nth event, -1 for dumping at EOF only')
333 parser.add_argument ('--ignore-key', dest = 'ignore_key', action = 'append', type = str,
334 default = [], help = 'Ignore the key at position (x, y)')
335 parser.add_argument ('--only-key', dest = 'only_key', action = 'append', type = str,
336 default = [], help = 'Only include key at position (x, y)')
337 parser.add_argument ('--one-shot', dest = 'one_shot', action = 'store_true',
338 help = 'Do not load previous data, and do not update it, either.')
339 args = parser.parse_args()
340 if len(args.ignore_key) and len(args.only_key):
341 print ("--ignore-key and --only-key are mutually exclusive, please only use one of them!",
342 file = sys.stderr)
343 sys.exit(1)
344 main(args)
diff --git a/layouts/community/ergodox/algernon/tools/text-to-log.py b/layouts/community/ergodox/algernon/tools/text-to-log.py
new file mode 100644
index 000000000..f080c32cd
--- /dev/null
+++ b/layouts/community/ergodox/algernon/tools/text-to-log.py
@@ -0,0 +1,107 @@
1#!/usr/bin/env python3
2
3import os
4import sys
5
6charmap = {
7 '9': [[1, 0]],
8 '7': [[2, 0]], '@': [[2, 5], [2, 0]],
9 '5': [[3, 0]], '*': [[2, 5], [3, 0]],
10 '3': [[4, 0]], '^': [[2, 5], [4, 0]],
11 '1': [[5, 0]], '$': [[2, 5], [5, 0]],
12 '0': [[8, 0]], '%': [[2, 5], [8, 0]],
13 '2': [[9, 0]], '!': [[2, 5], [9, 0]],
14 '4': [[10, 0]], '#': [[2, 5], [10, 0]],
15 '6': [[11, 0]], '&': [[2, 5], [11, 0]],
16 '8': [[12, 0]],
17
18 '\\': [[0, 1]], '|': [[2, 5], [0, 1]],
19 'x': [[1, 1]], 'X': [[2, 5], [1, 1]],
20 'w': [[2, 1]], 'W': [[2, 5], [2, 1]],
21 'c': [[3, 1]], 'C': [[2, 5], [3, 1]],
22 'h': [[4, 1]], 'H': [[2, 5], [4, 1]],
23 'f': [[5, 1]], 'F': [[2, 5], [5, 1]],
24 '[': [[6, 1]], '{': [[2, 5], [6, 1]], '(': [[6, 1], [6, 1]],
25 ']': [[7, 1]], '}': [[2, 5], [7, 1]], ')': [[7, 1], [7, 1]],
26 'm': [[8, 1]], 'M': [[2, 5], [8, 1]],
27 'g': [[9, 1]], 'G': [[2, 5], [9, 1]],
28 'l': [[10, 1]], 'L': [[2, 5], [10, 1]],
29 'p': [[11, 1]], 'P': [[2, 5], [11, 1]],
30 '/': [[12, 1]], '?': [[2, 5], [12, 1]],
31 '`': [[13, 1]], '~': [[2, 5], [13, 1]],
32
33 '\t': [[0, 2]],
34 'a': [[1, 2]], 'A': [[2, 5], [1, 2]],
35 'o': [[2, 2]], 'O': [[2, 5], [2, 2]],
36 'e': [[3, 2]], 'E': [[2, 5], [3, 2]],
37 'i': [[4, 2]], 'I': [[2, 5], [4, 2]],
38 'u': [[5, 2]], 'U': [[2, 5], [5, 2]],
39 'd': [[8, 2]], 'D': [[2, 5], [8, 2]],
40 'r': [[9, 2]], 'R': [[2, 5], [9, 2]],
41 't': [[10, 2]], 'T': [[2, 5], [10, 2]],
42 'n': [[11, 2]], 'N': [[2, 5], [11, 2]],
43 's': [[12, 2]], 'S': [[2, 5], [12, 2]],
44 '=': [[13, 2]], '+': [[2, 5], [13, 2]],
45
46 'z': [[1, 3]], 'Z': [[2, 5], [1, 3]],
47 'q': [[2, 3]], 'Q': [[2, 5], [2, 3]],
48 '\'': [[3, 3]], '"': [[2, 5], [3, 3]],
49 ',': [[4, 3]], '<': [[2, 5], [4, 3]],
50 '.': [[5, 3]], '>': [[2, 5], [5, 3]],
51 'b': [[8, 3]], 'B': [[2, 5], [8, 3]],
52 'k': [[9, 3]], 'K': [[2, 5], [9, 3]],
53 'v': [[10, 3]], 'V': [[2, 5], [10, 3]],
54 'y': [[11, 3]], 'Y': [[2, 5], [11, 3]],
55 'j': [[12, 3]], 'J': [[2, 5], [12, 3]],
56
57 ':': [[4, 4]], ';': [[4, 4], [4, 4]],
58 '-': [[9, 4]], '_': [[2, 5], [9, 4]],
59
60 ' ': [[10, 5]],
61 '\n': [[11, 5]],
62
63 ## Layered things
64 # Hungarian
65 'á': [[9, 5], [1, 2]], 'Á': [[2, 5], [9, 5], [1, 2]],
66 'ó': [[9, 5], [2, 2]], 'Ó': [[2, 5], [9, 5], [2, 2]],
67 'ő': [[9, 5], [2, 1]], 'Ő': [[2, 5], [9, 5], [2, 1]],
68 'ö': [[9, 5], [2, 3]], 'Ö': [[2, 5], [9, 5], [2, 3]],
69 'é': [[9, 5], [3, 2]], 'É': [[2, 5], [9, 5], [3, 2]],
70 'ú': [[9, 5], [4, 2]], 'Ú': [[2, 5], [9, 5], [4, 2]],
71 'ű': [[9, 5], [4, 1]], 'Ű': [[2, 5], [9, 5], [4, 1]],
72 'ü': [[9, 5], [4, 3]], 'Ü': [[2, 5], [9, 5], [4, 3]],
73 'í': [[9, 5], [5, 2]], 'Í': [[2, 5], [9, 5], [5, 2]],
74}
75
76def lookup_char(layer, ch):
77 if ch in charmap:
78 return charmap[ch]
79 return None
80
81def process_char(layer, ch, out=sys.stdout):
82 keys = lookup_char(layer, ch)
83 if not keys:
84 print ("Unknown char: %s" % ch, file=sys.stderr)
85 else:
86 for (c, r) in keys:
87 print ("KL: col=%d, row=%d, pressed=1, layer=%s" % (r, c, layer), file=out)
88 print ("KL: col=%d, row=%d, pressed=0, layer=%s" % (r, c, layer), file=out)
89
90def process_file(fn, layer, out=sys.stdout):
91 with open(fn, "r") as f:
92 ch = f.read(1)
93 while ch:
94 process_char(layer, ch, out)
95 ch = f.read(1)
96
97if sys.argv[1] == '-':
98 out='/dev/stdin'
99else:
100 out=sys.argv[1]
101
102if len(sys.argv) >= 2:
103 layer = 'ADORE'
104else:
105 layer = sys.argv[2]
106
107process_file(out, layer = layer)