2022-12-27 01:17:54 -08:00
|
|
|
#!/usr/bin/env python3
|
2022-12-25 08:54:16 -08:00
|
|
|
"""
|
|
|
|
Generate C code for the common configuration of the RBG matrix feature of QMK
|
|
|
|
|
|
|
|
Reference: https://docs.qmk.fm/#/feature_rgb_matrix?id=common-configuration
|
|
|
|
|
|
|
|
To use adjust `ansi` variable, run it and use the printed output.
|
|
|
|
|
|
|
|
All LEDs are set as type LED_FLAG_KEYLIGHT. That's good enough for us.
|
|
|
|
All our LEDs are behind keys. However, LED_FLAG_MODIFIER might be useful for
|
|
|
|
some keys. Not sure what that means, though.
|
|
|
|
"""
|
|
|
|
|
|
|
|
from collections import OrderedDict
|
|
|
|
|
|
|
|
# Rows and columns in the electrical keyboard matrix.
|
|
|
|
# Equivalent to QMK's macros: MATRIX_ROWS and MATRIX_COLS
|
2022-12-27 00:44:28 -08:00
|
|
|
# Keyboard
|
2022-12-25 08:54:16 -08:00
|
|
|
MATRIX_ROWS = 8
|
|
|
|
MATRIX_COLS = 16
|
2023-07-10 13:35:45 -07:00
|
|
|
# Macropad
|
2022-12-27 00:44:28 -08:00
|
|
|
#MATRIX_ROWS = 4
|
|
|
|
#MATRIX_COLS = 8
|
2022-12-25 08:54:16 -08:00
|
|
|
|
|
|
|
LED_FLAG_NONE = 0x00
|
|
|
|
LED_FLAG_MODIFIER = 0x01
|
|
|
|
LED_FLAG_UNDERGLOW = 0x02
|
|
|
|
LED_FLAG_KEYLIGHT = 0x04
|
|
|
|
LED_FLAG_INDICATOR = 0x08
|
|
|
|
|
|
|
|
# This structure is (manually) taken from a picture of the LED positions.
|
|
|
|
# The coordinates don't need to be translated or scaled. This script takes care of that.
|
|
|
|
# I loaded the PDF into GIMP and just took the coordinates.
|
|
|
|
# id: LED id, of where it's connected to the LED controller
|
|
|
|
# x: x coordinate of the LED
|
|
|
|
# y: y coordinate of the LED
|
|
|
|
# matrix: The keyboard matrix coordinate of the key this LED belongs to.
|
|
|
|
# Only one LED per key needs this. Other's can keep it unset.
|
|
|
|
ansi = [
|
|
|
|
{ "id": "26", "x":86, "y": 160, "matrix": (5,7) }, # ESC
|
|
|
|
{ "id": "24", "x":134, "y": 160 }, # ESC
|
|
|
|
{ "id": "22", "x":200, "y": 154, "matrix": (5,3) },
|
|
|
|
|
|
|
|
{ "id": "20", "x":275, "y": 154, "matrix": (5,2) }, # Each 75 apart in x
|
|
|
|
{ "id": "19", "x":350, "y": 154, "matrix": (4,6) },
|
|
|
|
{ "id": "21", "x":425, "y": 154, "matrix": (4,3) },
|
|
|
|
{ "id": "23", "x":500, "y": 154, "matrix": (10,4) },
|
|
|
|
{ "id": "25", "x":575, "y": 154, "matrix": (10,3) },
|
|
|
|
{ "id": "27", "x":650, "y": 154, "matrix": (10,2) },
|
|
|
|
{ "id": "68", "x":725, "y": 154, "matrix": (15,1) },
|
|
|
|
{ "id": "75", "x":800, "y": 154, "matrix": (11,3) },
|
|
|
|
{ "id": "69", "x":875, "y": 154, "matrix": (8,4) },
|
|
|
|
|
|
|
|
{ "id": "67", "x":935, "y": 158, "matrix": (8,6) }, # PrtScr
|
|
|
|
{ "id": "72", "x":960, "y": 158 }, # PrtScr
|
2023-03-01 23:37:26 -08:00
|
|
|
{ "id": "71", "x":1022, "y": 154, "matrix": (13,3) },# F12
|
2023-08-09 23:01:58 -07:00
|
|
|
{ "id": "73", "x":1088, "y": 160 }, # Del
|
|
|
|
{ "id": "74", "x":1135, "y": 160, "matrix": (1,0) },# Del
|
2022-12-25 08:54:16 -08:00
|
|
|
|
|
|
|
# Second row
|
|
|
|
{ "id": "17", "x":97, "y": 216, "matrix": (2,4) }, # Each 75 apart in x
|
|
|
|
{ "id": "16", "x":172, "y": 216, "matrix": (2,5) },
|
|
|
|
{ "id": "14", "x":247, "y": 216, "matrix": (5,5) },
|
|
|
|
{ "id": "13", "x":322, "y": 216, "matrix": (4,5) },
|
|
|
|
{ "id": "12", "x":397, "y": 216, "matrix": (6,5) },
|
|
|
|
{ "id": "10", "x":472, "y": 216, "matrix": (6,4) },
|
|
|
|
{ "id": "15", "x":547, "y": 216, "matrix": (7,4) },
|
|
|
|
{ "id": "11", "x":622, "y": 216, "matrix": (7,5) },
|
|
|
|
{ "id": "18", "x":697, "y": 216, "matrix": (10,5) },
|
|
|
|
{ "id": "70", "x":772, "y": 216, "matrix": (8,5) },
|
|
|
|
{ "id": "62", "x":847, "y": 216, "matrix": (13,4) },
|
|
|
|
{ "id": "64", "x":922, "y": 216, "matrix": (13,2) },
|
|
|
|
{ "id": "63", "x":997, "y": 216, "matrix": (14,4) },
|
|
|
|
|
2023-08-09 23:01:58 -07:00
|
|
|
{ "id": "65", "x":1067, "y": 224 }, # Backspace
|
|
|
|
{ "id": "66", "x":1128, "y": 224, "matrix": (14,5) }, # Backspace
|
2022-12-25 08:54:16 -08:00
|
|
|
|
|
|
|
# Third row
|
|
|
|
{ "id": "2", "x":90, "y": 298, "matrix": (2,3) }, # Tab
|
|
|
|
{ "id": "1", "x":140, "y": 298 }, # Tab
|
|
|
|
|
|
|
|
{ "id": "6", "x":207, "y": 290, "matrix": (2,0) }, # Each 75 apart in x
|
|
|
|
{ "id": "4", "x":282, "y": 290, "matrix": (5,6) },
|
|
|
|
{ "id": "3", "x":357, "y": 290, "matrix": (4,2) },
|
|
|
|
{ "id": "5", "x":432, "y": 290, "matrix": (6,6) },
|
|
|
|
{ "id": "8", "x":507, "y": 290, "matrix": (6,3) },
|
|
|
|
{ "id": "9", "x":582, "y": 290, "matrix": (7,3) },
|
|
|
|
{ "id": "7", "x":657, "y": 290, "matrix": (7,6) },
|
|
|
|
{ "id": "59", "x":732, "y": 290, "matrix": (10,6) },
|
|
|
|
{ "id": "60", "x":807, "y": 290, "matrix": (8,3) },
|
|
|
|
{ "id": "61", "x":882, "y": 290, "matrix": (13,5) },
|
|
|
|
{ "id": "58", "x":957, "y": 290, "matrix": (13,6) },
|
|
|
|
{ "id": "55", "x":1032, "y": 290, "matrix": (14,6) },
|
|
|
|
|
|
|
|
{ "id": "56", "x":1115, "y": 292, "matrix": (8,2) },
|
|
|
|
|
|
|
|
# Forth row
|
2023-08-09 23:01:58 -07:00
|
|
|
{ "id": "45", "x":94, "y": 374, "matrix": (4,4) }, # Caps
|
|
|
|
{ "id": "39", "x":123, "y": 367 }, # Caps
|
|
|
|
{ "id": "43", "x":150, "y": 374 }, # Caps
|
2022-12-25 08:54:16 -08:00
|
|
|
|
|
|
|
{ "id": "37", "x":227, "y": 365, "matrix": (2,7) }, # Each 75 apart in x
|
|
|
|
{ "id": "42", "x":302, "y": 365, "matrix": (5,4) },
|
|
|
|
{ "id": "38", "x":377, "y": 365, "matrix": (14,7) },
|
|
|
|
{ "id": "44", "x":452, "y": 365, "matrix": (6,7) },
|
|
|
|
{ "id": "40", "x":527, "y": 365, "matrix": (6,2) },
|
|
|
|
{ "id": "41", "x":602, "y": 365, "matrix": (7,2) },
|
|
|
|
{ "id": "50", "x":677, "y": 365, "matrix": (7,7) },
|
|
|
|
{ "id": "51", "x":752, "y": 365, "matrix": (10,7) },
|
|
|
|
{ "id": "52", "x":827, "y": 365, "matrix": (8,7) },
|
|
|
|
{ "id": "49", "x":902, "y": 365, "matrix": (13,7) },
|
|
|
|
{ "id": "53", "x":977, "y": 365, "matrix": (14,0) },
|
|
|
|
|
2023-08-09 23:01:58 -07:00
|
|
|
{ "id": "54", "x":1050, "y": 365 }, # Enter
|
|
|
|
{ "id": "57", "x":1131, "y": 373, "matrix": (14,1) }, # Enter
|
2022-12-25 08:54:16 -08:00
|
|
|
|
|
|
|
# Fifth row
|
2023-08-09 23:01:58 -07:00
|
|
|
{ "id": "33", "x":91, "y": 448, "matrix": (9,1) }, # Shift
|
|
|
|
{ "id": "31", "x":113, "y": 448 }, # Shift
|
2022-12-25 08:54:16 -08:00
|
|
|
{ "id": "29", "x":191, "y": 440 }, # Shift
|
|
|
|
|
|
|
|
{ "id": "28", "x":266, "y": 440, "matrix": (5,1) }, # Each 75 apart in x
|
|
|
|
{ "id": "30", "x":341, "y": 440, "matrix": (5,0) },
|
|
|
|
{ "id": "32", "x":416, "y": 440, "matrix": (0,0) },
|
|
|
|
{ "id": "34", "x":491, "y": 440, "matrix": (6,0) },
|
|
|
|
{ "id": "36", "x":566, "y": 440, "matrix": (6,1) },
|
|
|
|
{ "id": "77", "x":641, "y": 440, "matrix": (7,1) },
|
|
|
|
{ "id": "78", "x":716, "y": 440, "matrix": (7,0) },
|
|
|
|
{ "id": "79", "x":791, "y": 440, "matrix": (10,0) },
|
|
|
|
{ "id": "76", "x":866, "y": 440, "matrix": (8,0) },
|
|
|
|
{ "id": "80", "x":941, "y": 440, "matrix": (13,0) },
|
|
|
|
|
2023-02-08 00:24:48 -08:00
|
|
|
{ "id": "81", "x":1013, "y": 445 }, # Shift
|
2023-08-09 23:01:58 -07:00
|
|
|
{ "id": "83", "x":1041, "y": 445 }, # Shift
|
2022-12-25 08:54:16 -08:00
|
|
|
{ "id": "84", "x":1106, "y": 445 }, # Shift
|
2023-08-09 23:01:58 -07:00
|
|
|
{ "id": "93", "x":1127, "y": 445, "matrix": (9,0) }, # Shift
|
2022-12-25 08:54:16 -08:00
|
|
|
|
|
|
|
# Sixth row
|
|
|
|
{ "id": "35", "x":89, "y": 522, "matrix": (12,1) }, # CTRL
|
|
|
|
{ "id": "46", "x":124, "y": 522 }, # CTRL
|
|
|
|
{ "id": "94", "x":191, "y": 515, "matrix": (2,2) },
|
|
|
|
{ "id": "47", "x":266, "y": 515, "matrix": (1,3) },
|
|
|
|
{ "id": "48", "x":341, "y": 515, "matrix": (3,1) },
|
2023-08-09 23:01:58 -07:00
|
|
|
{ "id": "95", "x":415, "y": 522, "matrix": (4,1) }, # Space
|
2022-12-25 08:54:16 -08:00
|
|
|
{ "id": "96", "x":475, "y": 522 }, # Space
|
2023-08-09 23:01:58 -07:00
|
|
|
{ "id": "97", "x":535, "y": 522 }, # Space
|
2022-12-25 08:54:16 -08:00
|
|
|
{ "id": "86", "x":595, "y": 522 }, # Space
|
|
|
|
{ "id": "87", "x":655, "y": 522 }, # Space
|
|
|
|
{ "id": "88", "x":715, "y": 522 }, # Space
|
|
|
|
{ "id": "85", "x":791, "y": 515, "matrix": (3,0) },
|
|
|
|
{ "id": "89", "x":865, "y": 515, "matrix": (12,0) },
|
|
|
|
{ "id": "90", "x":945, "y": 542, "matrix": (11,6) },
|
2023-03-01 23:29:41 -08:00
|
|
|
{ "id": "91", "x":1033, "y": 534, "matrix": (8,1) }, # Down
|
|
|
|
{ "id": "82", "x":1033, "y": 510, "matrix": (13,1) }, # Up
|
2022-12-25 08:54:16 -08:00
|
|
|
{ "id": "92", "x":1120, "y": 542, "matrix": (15,2) },
|
|
|
|
]
|
|
|
|
|
2023-07-10 13:35:45 -07:00
|
|
|
macropad = [
|
2022-12-28 00:57:12 -08:00
|
|
|
{ "id": "6", "x":1332, "y": 158, "matrix": (1,2) },
|
|
|
|
{ "id": "3", "x":1395, "y": 158, "matrix": (2,2) },
|
|
|
|
{ "id": "23", "x":1460, "y": 158, "matrix": (4,3) },
|
|
|
|
{ "id": "18", "x":1523, "y": 158, "matrix": (4,2) },
|
2022-12-25 08:54:16 -08:00
|
|
|
|
2022-12-28 00:57:12 -08:00
|
|
|
{ "id": "5", "x":1332, "y": 219, "matrix": (0,0) },
|
2022-12-27 00:44:28 -08:00
|
|
|
{ "id": "1", "x":1395, "y": 219, "matrix": (4,0) },
|
2022-12-28 00:57:12 -08:00
|
|
|
{ "id": "21", "x":1460, "y": 219, "matrix": (1,1) },
|
|
|
|
{ "id": "19", "x":1523, "y": 219, "matrix": (6,1) },
|
2022-12-25 08:54:16 -08:00
|
|
|
|
2022-12-28 00:57:12 -08:00
|
|
|
{ "id": "8", "x":1332, "y": 294, "matrix": (1,0) },
|
2022-12-27 00:44:28 -08:00
|
|
|
{ "id": "2", "x":1395, "y": 294, "matrix": (5,0) },
|
2022-12-28 00:57:12 -08:00
|
|
|
{ "id": "22", "x":1460, "y": 294, "matrix": (2,1) },
|
2023-01-31 01:25:06 -08:00
|
|
|
{ "id": "17", "x":1523, "y": 294, "matrix": (5,2) },
|
2022-12-28 00:57:12 -08:00
|
|
|
|
|
|
|
{ "id": "7", "x":1332, "y": 368, "matrix": (2,0) },
|
|
|
|
{ "id": "4", "x":1395, "y": 368, "matrix": (6,0) },
|
|
|
|
{ "id": "24", "x":1460, "y": 368, "matrix": (3,1) },
|
|
|
|
{ "id": "20", "x":1523, "y": 368, "matrix": (7,1) },
|
|
|
|
|
|
|
|
{ "id": "10", "x":1332, "y": 443, "matrix": (3,0) },
|
|
|
|
{ "id": "12", "x":1395, "y": 443, "matrix": (7,0) },
|
|
|
|
{ "id": "16", "x":1460, "y": 443, "matrix": (4,1) },
|
|
|
|
{ "id": "14", "x":1523, "y": 443, "matrix": (6,2) },
|
|
|
|
|
|
|
|
{ "id": "9", "x":1332, "y": 519, "matrix": (0,1) },
|
|
|
|
{ "id": "11", "x":1395, "y": 519, "matrix": (7,2) },
|
|
|
|
{ "id": "15", "x":1460, "y": 519, "matrix": (5,1) },
|
|
|
|
{ "id": "13", "x":1523, "y": 519, "matrix": (0,2) },
|
2022-12-25 08:54:16 -08:00
|
|
|
]
|
|
|
|
|
|
|
|
# Recommended by QMK to be the (x,y) range of position values
|
|
|
|
LED_MAX = (224.0, 64.0)
|
|
|
|
|
2023-01-10 00:26:09 -08:00
|
|
|
NO_LED = 255
|
|
|
|
|
2022-12-25 08:54:16 -08:00
|
|
|
# Map LEDs to keyboard matrix and normalize LED coordinates
|
|
|
|
def normalize(layout):
|
2023-01-10 00:26:09 -08:00
|
|
|
led_to_el = [[NO_LED for _ in range(MATRIX_COLS)] for _ in range(MATRIX_ROWS)]
|
2022-12-25 08:54:16 -08:00
|
|
|
# Find smallest (offset) and largest (max) values
|
|
|
|
offset_x = layout[0]['x']
|
|
|
|
offset_y = layout[0]['y']
|
|
|
|
max_x = layout[-1]['x']
|
|
|
|
max_y = layout[-1]['y']
|
|
|
|
for v in layout:
|
|
|
|
if v['x'] < offset_x:
|
|
|
|
offset_x = v['x']
|
|
|
|
if v['y'] < offset_y:
|
|
|
|
offset_y = v['y']
|
|
|
|
if v['x'] > max_x:
|
|
|
|
max_x = v['x']
|
|
|
|
if v['y'] > max_y:
|
|
|
|
max_y = v['y']
|
|
|
|
# Ratio of coordinates in the input data vs QMK's reference rectangle
|
|
|
|
x_ratio = LED_MAX[0] / (max_x - offset_x)
|
|
|
|
y_ratio = LED_MAX[1] / (max_y - offset_y)
|
|
|
|
|
|
|
|
# Normalize LED coordinates by scaling and translating
|
|
|
|
normalized = OrderedDict()
|
|
|
|
for v in sorted(layout, key=lambda item: int(item['id'])):
|
|
|
|
x = x_ratio * (v['x'] - offset_x)
|
|
|
|
y = y_ratio * (v['y'] - offset_y)
|
|
|
|
|
|
|
|
normalized[int(v['id'])] = (x, y)
|
|
|
|
|
|
|
|
if 'matrix' in v:
|
|
|
|
if not v['matrix'] or v['matrix'] == ():
|
|
|
|
continue
|
|
|
|
(matrix_x,matrix_y) = v['matrix']
|
|
|
|
# Map LED IDs to keyboard matrix
|
2023-01-10 00:26:09 -08:00
|
|
|
# Turn LED index into 0-indexed
|
|
|
|
led_to_el[matrix_y][matrix_x] = int(v['id']) - 1
|
2022-12-25 08:54:16 -08:00
|
|
|
return led_to_el, normalized
|
|
|
|
|
|
|
|
# Turn the data to C code that can be used in QMK's keymap.c
|
|
|
|
def print_matrix(layout, led_to_el, normalized):
|
2022-12-25 09:24:17 -08:00
|
|
|
print("led_config_t g_led_config = { {")
|
2022-12-25 08:54:16 -08:00
|
|
|
print(" // Key Matrix to LED Index")
|
|
|
|
for row in led_to_el:
|
|
|
|
print(" {", end='')
|
|
|
|
for col in row:
|
2023-01-10 01:53:33 -08:00
|
|
|
if col == 255:
|
|
|
|
col = 'NO_LED'
|
|
|
|
print(f"{col: >6}, ", end='')
|
2022-12-25 08:54:16 -08:00
|
|
|
print("},")
|
|
|
|
|
|
|
|
print("}, {")
|
2022-12-27 01:18:38 -08:00
|
|
|
print(" // LED Index to Physical Position")
|
2022-12-27 00:44:28 -08:00
|
|
|
for (i, (led_id, (x, y))) in enumerate(normalized.items()):
|
|
|
|
coords = f" {{ {int(x): >3}, {int(y): >3} }},"
|
|
|
|
print(f"{coords: <15} // LED {led_id}")
|
2022-12-25 08:54:16 -08:00
|
|
|
|
|
|
|
print("}, {")
|
|
|
|
print(" // LED Index to Flag")
|
|
|
|
print(" ", end='')
|
|
|
|
for i in range(len(layout)):
|
|
|
|
# TODO: Support other LED flags
|
|
|
|
print(LED_FLAG_KEYLIGHT, end='')
|
|
|
|
if i + 1 == len(layout):
|
|
|
|
print()
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
print(", ", end='')
|
|
|
|
if (i + 1) % 16 == 0:
|
|
|
|
print("\n ", end='')
|
2022-12-25 09:24:17 -08:00
|
|
|
print("} };")
|
2022-12-25 08:54:16 -08:00
|
|
|
|
|
|
|
def main(data):
|
|
|
|
# Normalize data and convert to C code
|
|
|
|
led_to_el, normalized = normalize(data)
|
|
|
|
print_matrix(data, led_to_el, normalized)
|
|
|
|
|
|
|
|
# Draw led positions to visually check them with the reference design
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
a = [[x, y] for _i, (x, y) in normalized.items()]
|
|
|
|
scatter = plt.scatter(*zip(*a))
|
|
|
|
ax = scatter.axes
|
|
|
|
ax.invert_yaxis()
|
|
|
|
plt.show()
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
# Can choose which dataset to process
|
|
|
|
main(ansi)
|