2023-07-22 22:04:21 +00:00
|
|
|
package main
|
|
|
|
|
2023-07-22 22:49:09 +00:00
|
|
|
import (
|
2023-07-22 23:55:16 +00:00
|
|
|
"fmt"
|
2023-07-22 22:49:09 +00:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2023-07-22 22:04:21 +00:00
|
|
|
const (
|
|
|
|
scaleX = 8
|
2023-07-24 19:07:12 +00:00
|
|
|
scaleY = 2
|
2023-07-22 22:04:21 +00:00
|
|
|
)
|
|
|
|
|
2023-07-22 23:07:23 +00:00
|
|
|
// https://github.com/qmk/qmk_firmware/blob/master/docs/keycodes.md
|
2023-08-10 10:10:16 +00:00
|
|
|
var mapRawBinding = []map[string]string{
|
2023-08-07 07:51:11 +00:00
|
|
|
{
|
|
|
|
// My custom
|
2023-08-10 07:04:24 +00:00
|
|
|
"CTL_T(KC_ESC)": "ESC CTRL",
|
2023-08-07 07:51:11 +00:00
|
|
|
"TD(TD_SAFE_BOOT)": "BOOT",
|
|
|
|
},
|
2023-07-28 12:29:28 +00:00
|
|
|
{
|
|
|
|
// Basic
|
2023-08-07 07:51:11 +00:00
|
|
|
// Prefer OPT > ALT
|
|
|
|
// Prefer CMD > GUI, WIN
|
2023-07-28 12:29:28 +00:00
|
|
|
"KC_TRNS": "",
|
|
|
|
"_______": "",
|
|
|
|
"KC_NO": "",
|
|
|
|
"XXXXXXX": "",
|
|
|
|
"KC_ENT": "ENTER",
|
2023-07-28 12:33:10 +00:00
|
|
|
"KC_BSPC": "BACKSPACE",
|
2023-07-28 12:29:28 +00:00
|
|
|
"KC_SPC": "SPACE",
|
|
|
|
"KC_MINS": "-",
|
|
|
|
"KC_EQL": "=",
|
|
|
|
"KC_LBRC": "[",
|
|
|
|
"KC_RBRC": "]",
|
|
|
|
"KC_BSLS": "\\",
|
|
|
|
"KC_SCLN": ";",
|
|
|
|
"KC_QUOT": "'",
|
|
|
|
"KC_GRV": "`",
|
|
|
|
"KC_COMM": ",",
|
|
|
|
"KC_DOT": ".",
|
|
|
|
"KC_SLSH": "/",
|
|
|
|
"KC_LCTL": "CTRL",
|
|
|
|
"KC_RCTL": "CTRL",
|
2023-08-07 07:51:11 +00:00
|
|
|
"KC_LALT": "OPT",
|
|
|
|
"KC_RALT": "OPT",
|
2023-08-07 05:47:49 +00:00
|
|
|
"KC_LOPT": "OPT",
|
|
|
|
"KC_ROPT": "OPT",
|
2023-07-28 12:29:28 +00:00
|
|
|
"KC_LGUI": "CMD",
|
|
|
|
"KC_RGUI": "CMD",
|
2023-08-07 05:47:49 +00:00
|
|
|
"KC_LCMD": "CMD",
|
|
|
|
"KC_RCMD": "CMD",
|
2023-07-28 12:29:28 +00:00
|
|
|
"KC_LSFT": "SHIFT",
|
|
|
|
"KC_RSFT": "SHIFT",
|
|
|
|
"RGB_TOG": "RGBTO",
|
|
|
|
"RGB_MOD": "RGBMO",
|
|
|
|
"RGB_HUI": "RGBH",
|
|
|
|
"RGB_SAI": "RGBS",
|
|
|
|
"RGB_VAI": "RGBV",
|
|
|
|
// Advance
|
2023-08-07 05:47:49 +00:00
|
|
|
// Space cadet
|
2023-08-10 07:04:24 +00:00
|
|
|
"SC_LSPO": "( SHIFT",
|
|
|
|
"SC_RSPC": ") SHIFT",
|
2023-08-10 10:10:16 +00:00
|
|
|
// Quantum
|
|
|
|
"EE_CLR": "EECLR",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var mapTransform = []map[string]string{
|
|
|
|
{
|
|
|
|
// Layer enum
|
|
|
|
"LAYER_QWERTY": "0",
|
|
|
|
"LAYER_COMMON": "1",
|
|
|
|
"LAYER_RARELY": "2",
|
|
|
|
"LAYER_RECOVERY": "3",
|
2023-07-28 12:40:05 +00:00
|
|
|
},
|
|
|
|
{
|
2023-08-07 07:51:11 +00:00
|
|
|
// Prefix
|
2023-07-28 12:29:28 +00:00
|
|
|
"KC_": "",
|
2023-08-10 07:04:24 +00:00
|
|
|
"QK_": "",
|
2023-07-28 12:29:28 +00:00
|
|
|
},
|
2023-08-10 10:10:16 +00:00
|
|
|
{
|
|
|
|
"MO(0)": "L0",
|
|
|
|
"MO(1)": "L1",
|
|
|
|
"MO(2)": "L2",
|
|
|
|
"MO(3)": "L3",
|
|
|
|
},
|
2023-07-22 22:49:09 +00:00
|
|
|
}
|
|
|
|
|
2023-08-10 10:21:17 +00:00
|
|
|
// Only use this as last resort
|
|
|
|
var mapBindingTiny = []map[string]string{
|
|
|
|
{
|
|
|
|
"BACKSPACE": "BACK",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-07-30 07:56:46 +00:00
|
|
|
type DrawConfig struct {
|
2023-08-10 10:50:50 +00:00
|
|
|
AllowLayers map[int]struct{}
|
2023-07-30 07:56:46 +00:00
|
|
|
PrintLayout bool
|
|
|
|
PrintLayer bool
|
|
|
|
}
|
|
|
|
|
2023-07-22 22:04:21 +00:00
|
|
|
func Draw(
|
|
|
|
layouts map[string]map[string][]QMKKeyDictionary,
|
|
|
|
keymap QMKKeymap,
|
2023-07-30 07:56:46 +00:00
|
|
|
cfg DrawConfig,
|
2023-07-22 22:04:21 +00:00
|
|
|
) string {
|
2023-07-23 00:06:12 +00:00
|
|
|
layoutsStr := make([]string, 0, len(layouts))
|
2023-07-22 22:04:21 +00:00
|
|
|
|
2023-07-23 00:06:12 +00:00
|
|
|
// Each keyboard has many layouts
|
2023-07-22 22:04:21 +00:00
|
|
|
for layout := range layouts {
|
|
|
|
if keymap.Layout != layout {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
keys, ok := layouts[layout]["layout"]
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-07-30 07:56:46 +00:00
|
|
|
layoutStr := ""
|
|
|
|
if cfg.PrintLayout {
|
|
|
|
layoutStr += fmt.Sprintf("Layout %s\n", layout)
|
|
|
|
}
|
2023-07-23 00:06:12 +00:00
|
|
|
|
2023-07-22 22:04:21 +00:00
|
|
|
// Preprocess keys
|
|
|
|
// Y aka row -> X aka col
|
2023-07-22 23:33:10 +00:00
|
|
|
var newMaxX, newMaxY int
|
2023-07-22 22:04:21 +00:00
|
|
|
for i := range keys {
|
|
|
|
if int(keys[i].W) == 0 {
|
|
|
|
keys[i].W = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
if int(keys[i].H) == 0 {
|
|
|
|
keys[i].H = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Because 0.25
|
|
|
|
keys[i].NewX = int(keys[i].X * scaleX)
|
|
|
|
keys[i].NewY = int(keys[i].Y * scaleY)
|
|
|
|
keys[i].NewW = int(keys[i].W * scaleX)
|
|
|
|
keys[i].NewH = int(keys[i].H * scaleY)
|
|
|
|
|
2023-07-22 23:33:10 +00:00
|
|
|
if keys[i].NewX+keys[i].NewW > newMaxX {
|
|
|
|
newMaxX = keys[i].NewX + keys[i].NewW
|
2023-07-22 22:04:21 +00:00
|
|
|
}
|
|
|
|
|
2023-07-22 23:33:10 +00:00
|
|
|
if keys[i].NewY+keys[i].NewH > newMaxY {
|
|
|
|
newMaxY = keys[i].NewY + keys[i].NewH
|
2023-07-22 22:04:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-23 11:28:18 +00:00
|
|
|
if newMaxX == 0 || newMaxY == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-07-23 09:01:42 +00:00
|
|
|
// Each keymap has many layers
|
2023-07-23 00:06:12 +00:00
|
|
|
layersStr := make([]string, 0, len(keymap.Layers))
|
2023-07-22 23:55:16 +00:00
|
|
|
for iLayer, layer := range keymap.Layers {
|
2023-08-10 10:50:50 +00:00
|
|
|
if len(cfg.AllowLayers) > 0 {
|
|
|
|
// Only check if valid
|
|
|
|
if _, ok := cfg.AllowLayers[iLayer]; !ok {
|
|
|
|
// Skip if not in list
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-24 06:11:16 +00:00
|
|
|
// PreProcess table with space
|
2023-07-24 19:07:12 +00:00
|
|
|
table := make([][]string, newMaxY+1)
|
|
|
|
for i := 0; i <= newMaxY; i++ {
|
2023-07-23 11:28:18 +00:00
|
|
|
// Padding 1 in the right
|
|
|
|
table[i] = make([]string, newMaxX+1)
|
2023-07-24 05:44:46 +00:00
|
|
|
for j := 0; j <= newMaxX; j++ {
|
|
|
|
table[i][j] = " "
|
|
|
|
}
|
2023-07-22 22:04:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fill layout
|
|
|
|
count := 0
|
|
|
|
for _, key := range keys {
|
|
|
|
keyStr := layer[count]
|
|
|
|
|
2023-07-28 12:29:28 +00:00
|
|
|
// Convert keyStr
|
2023-08-10 10:10:16 +00:00
|
|
|
isRaw := false
|
|
|
|
for _, m := range mapRawBinding {
|
|
|
|
if _, ok := m[keyStr]; ok {
|
|
|
|
isRaw = true
|
|
|
|
keyStr = m[keyStr]
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !isRaw {
|
|
|
|
for _, m := range mapTransform {
|
|
|
|
for from, to := range m {
|
|
|
|
keyStr = strings.ReplaceAll(keyStr, from, to)
|
|
|
|
}
|
2023-07-28 12:29:28 +00:00
|
|
|
}
|
2023-07-22 22:49:09 +00:00
|
|
|
}
|
|
|
|
|
2023-07-22 23:33:10 +00:00
|
|
|
// Padding to center key
|
2023-07-23 09:01:42 +00:00
|
|
|
// Why / 2, why - 1 ?
|
|
|
|
// Base on my feeling of course
|
|
|
|
padding := (key.NewW-len(keyStr))/2 - 1
|
2023-07-22 23:45:18 +00:00
|
|
|
if padding <= 0 {
|
2023-07-22 23:33:10 +00:00
|
|
|
padding = 1
|
|
|
|
}
|
2023-07-22 23:07:23 +00:00
|
|
|
|
2023-08-10 10:21:17 +00:00
|
|
|
if len(keyStr)+2*padding > key.NewW {
|
|
|
|
// Make it smaller
|
|
|
|
for _, m := range mapBindingTiny {
|
|
|
|
if _, ok := m[keyStr]; ok {
|
|
|
|
keyStr = m[keyStr]
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Re calc padding
|
|
|
|
padding = (key.NewW-len(keyStr))/2 - 1
|
|
|
|
if padding <= 0 {
|
|
|
|
padding = 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-23 09:31:16 +00:00
|
|
|
// Draw strategy
|
2023-07-24 05:44:46 +00:00
|
|
|
// Draw 4 + in corner
|
|
|
|
// Draw - on top and bottom
|
|
|
|
// Draw | on left and right
|
2023-07-24 19:07:12 +00:00
|
|
|
for i := key.NewY; i <= key.NewY+key.NewH; i++ {
|
2023-07-23 11:28:18 +00:00
|
|
|
for j := key.NewX; j <= key.NewX+key.NewW; j++ {
|
2023-07-24 19:07:12 +00:00
|
|
|
if i == key.NewY || i == key.NewY+key.NewH {
|
2023-07-23 11:28:18 +00:00
|
|
|
if j == key.NewX || j == key.NewX+key.NewW {
|
2023-08-10 10:21:17 +00:00
|
|
|
// Draw corner
|
2023-07-22 22:04:21 +00:00
|
|
|
table[i][j] = "+"
|
2023-07-24 05:44:46 +00:00
|
|
|
} else if table[i][j] != "+" {
|
2023-08-10 10:21:17 +00:00
|
|
|
// Draw top/bottom
|
2023-07-22 22:04:21 +00:00
|
|
|
table[i][j] = "-"
|
|
|
|
}
|
|
|
|
} else if i == key.NewY+key.NewH/2 {
|
|
|
|
// Write key in the middle
|
2023-07-23 11:28:18 +00:00
|
|
|
if j == key.NewX || j == key.NewX+key.NewW {
|
2023-08-10 10:21:17 +00:00
|
|
|
// Draw left/right
|
2023-07-22 22:04:21 +00:00
|
|
|
table[i][j] = "|"
|
2023-07-24 05:44:46 +00:00
|
|
|
} else if len(keyStr) > 0 && j > key.NewX+padding && j < key.NewX+len(keyStr)+padding+1 && j <= key.NewX+key.NewW-padding {
|
2023-07-23 09:31:16 +00:00
|
|
|
// Only handle ASCII keyStr
|
2023-07-22 23:45:18 +00:00
|
|
|
table[i][j] = string(keyStr[j-key.NewX-padding-1])
|
2023-07-22 22:04:21 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-07-23 11:28:18 +00:00
|
|
|
if j == key.NewX || j == key.NewX+key.NewW {
|
|
|
|
table[i][j] = "|"
|
|
|
|
}
|
2023-07-22 22:04:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
count++
|
|
|
|
}
|
|
|
|
|
2023-07-24 06:11:16 +00:00
|
|
|
// Print
|
2023-07-30 07:56:46 +00:00
|
|
|
layerStr := ""
|
|
|
|
if cfg.PrintLayer {
|
|
|
|
layerStr += fmt.Sprintf("Layer %d\n", iLayer)
|
|
|
|
}
|
|
|
|
|
2023-07-24 19:07:12 +00:00
|
|
|
for i := range table {
|
|
|
|
for j := range table[i] {
|
|
|
|
layerStr += table[i][j]
|
2023-07-22 22:04:21 +00:00
|
|
|
}
|
2023-07-23 00:06:12 +00:00
|
|
|
layerStr += "\n"
|
2023-07-22 22:04:21 +00:00
|
|
|
}
|
2023-07-23 00:06:12 +00:00
|
|
|
layersStr = append(layersStr, layerStr)
|
2023-07-22 22:04:21 +00:00
|
|
|
}
|
|
|
|
|
2023-07-24 06:11:16 +00:00
|
|
|
// Print
|
2023-07-23 00:06:12 +00:00
|
|
|
layoutStr += strings.Join(layersStr, "\n")
|
|
|
|
layoutsStr = append(layoutsStr, layoutStr)
|
2023-07-22 22:04:21 +00:00
|
|
|
}
|
|
|
|
|
2023-07-23 00:06:12 +00:00
|
|
|
return strings.Join(layoutsStr, "\n")
|
2023-07-22 22:04:21 +00:00
|
|
|
}
|