f77: Add jackhill's layout
[jackhill/qmk/firmware.git] / keyboards / xwhatsit / util / util / generate_layout.py
1 #!/usr/bin/python2
2
3 # Copyright 2020 Purdea Andrei
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 import re, glob, os, subprocess, tempfile, json
19
20 def handle_layouts(layouth_fn, layoutc_fn, infojson_fn, config_fn):
21 config = open(config_fn, "r").read()
22 cols = int(re.findall(r"#define\s+MATRIX_COLS\s+([0-9]+)\n", config)[0])
23 rows = int(re.findall(r"#define\s+MATRIX_ROWS\s+([0-9]+)\n", config)[0])
24 extra_direct_rows_l_str = re.findall(r"#define\s+MATRIX_EXTRA_DIRECT_ROWS\s+([0-9]+)\n", config)
25 if extra_direct_rows_l_str:
26 extra_direct_rows = int(extra_direct_rows_l_str[0])
27 else:
28 extra_direct_rows = 0
29
30 f = open(infojson_fn, "r")
31 js = json.loads(f.read())['layouts']
32 f.close()
33
34 d = open(layouth_fn, "r").read().replace("\\\n", " ")
35 dd = re.findall(r'#define\s+(LAYOUT[a-zA-Z0-9_]*)\s*\(([^\)]*)\)', d)
36 temp_fn = ".__temp.c"
37 separator = "%%%%%%"
38 f = open(temp_fn, "w")
39 f.write("#include \"" + layouth_fn + "\"\n")
40 for l in dd:
41 le = len(l[1].split(","))
42 f.write(separator + l[0] + separator + "\n" + l[0] + "(" + (",".join([str(i) for i in range(le)])) + ")\n")
43 f.close()
44 i = os.path.split(os.path.abspath(layouth_fn))[0]
45 includes = []
46 while True:
47 includes.append(i)
48 i, j = os.path.split(i)
49 if j == "keyboards" or not i:
50 break
51 for i in "-Iusers/default -I. -Itmk_core -Iquantum -Iquantum/keymap_extras -Iquantum/audio -Iquantum/process_keycode -Iquantum/api -Idrivers -Idrivers/avr -Itmk_core/protocol -Itmk_core/common -Itmk_core/common/avr -Itmk_core/protocol/lufa -Ilib/lufa -Idrivers/avr".split(" "):
52 if i.startswith("-I"):
53 includes.append("../../../../" + i[2:])
54 p = subprocess.Popen(["gcc", "-E"] + ["-I" + i for i in includes] + ["-include", os.path.join(os.path.split(os.path.abspath(layouth_fn))[0], "config.h"), temp_fn], stdout=subprocess.PIPE)
55 data = p.communicate()[0].split(separator)
56 os.unlink(temp_fn)
57 del data[0]
58 laynames = []
59 keybname = re.sub(r'[^a-zA-Z0-9_]', '_', layoutc_fn)
60 for i in range(0, len(data), 2):
61 lname = data[i]
62 desc = "}".join(data[i+1].split("{", 1)[1].split("}")[:-1])
63 desc = [i.replace("{", "").replace("}", "") for i in re.findall("\{[^}]*\}", desc)]
64 desc = [[j.strip() for j in i.split(",")] for i in desc]
65 arr = []
66 for row in range(len(desc)):
67 for col in range(len(desc[row])):
68 if desc[row][col] != "KC_NO":
69 ind = int(desc[row][col])
70 while len(arr) <= ind:
71 arr.append('')
72 arr[ind] = (row, col)
73 layname = keybname + "_" + re.sub(r'[^a-zA-Z0-9_]', '_', lname)
74 print("struct key_def " + layname + "_keys[] = {")
75 for i in range(len(arr)):
76 item = js[lname]['layout'][i]
77 x = item['x']
78 y = item['y']
79 w = item['w'] if 'w' in item else 1
80 h = item['h'] if 'h' in item else 1
81 if len(arr) <= i:
82 raise BaseException("Error index " + str(i) + " in array " + str(arr))
83 if len(arr[i]) < 2:
84 raise BaseException("Error array must have at least two elements: " + str(arr[i]) + " (full arr = " + str(arr) + ")")
85 print (" { .row = %d, .col = %d, .x = %f, .y = %f, .w = %f, .h = %f }," % (arr[i][0], arr[i][1], x, y, w, h))
86 print("};")
87 laynames.append((layname, lname))
88 print("struct lay_def " + keybname + "_lays[] = {")
89 for layname, lname in sorted(laynames):
90 print(" {")
91 print(" .lay_name = \"" + lname + "\",")
92 print(" .n_keys = sizeof(" + layname + "_keys) / sizeof(" + layname + "_keys[0]),")
93 print(" .keys = " + layname + "_keys,")
94 print(" },")
95 print("};")
96 return keybname, cols, rows, extra_direct_rows
97
98
99 def find_layouts(starting_dir):
100 print("#include \"kbd_defs.h\"")
101 keebs = []
102 for root, dirs, files in sorted(os.walk(starting_dir)):
103 for fil in sorted(files):
104 layouth_fn = os.path.join(root, fil)
105 if layouth_fn.endswith(".h"):
106 spl1 = os.path.split(layouth_fn[:-2])
107 spl2 = os.path.split(spl1[0])
108 if spl1[1] == spl2[1]:
109 infojson_fn = os.path.join(spl2[0], "info.json")
110 config_fn = os.path.join(spl1[0], "config.h")
111 layoutc_fn = "keyboards/xwhatsit" + layouth_fn[len(starting_dir):-2] + ".c"
112 keybname, cols, rows, extra_direct_rows = handle_layouts(layouth_fn, layoutc_fn, infojson_fn, config_fn)
113 keebs.append((keybname, layoutc_fn, cols, rows, extra_direct_rows))
114 print("struct kbd_def keyboards[] = {")
115 for keybname, layoutc_fn, cols, rows, extra_direct_rows in sorted(keebs):
116 print(" {")
117 print(" .kbd_name = \"" + layoutc_fn + "\",")
118 print(" .n_layouts = sizeof(" + keybname + "_lays)/sizeof(" + keybname + "_lays[0]),")
119 print(" .layouts = " + keybname + "_lays,")
120 print(" .cols = %d," % (cols,))
121 print(" .rows = %d," % (rows,))
122 print(" .extra_direct_rows = %d," % (extra_direct_rows,))
123 print(" },")
124 print("};")
125 print("int n_keyboards = sizeof(keyboards)/sizeof(keyboards[0]);")
126
127
128 print("""/* Copyright 2020 Purdea Andrei
129 *
130 * This program is free software: you can redistribute it and/or modify
131 * it under the terms of the GNU General Public License as published by
132 * the Free Software Foundation, either version 2 of the License, or
133 * (at your option) any later version.
134 *
135 * This program is distributed in the hope that it will be useful,
136 * but WITHOUT ANY WARRANTY; without even the implied warranty of
137 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
138 * GNU General Public License for more details.
139 *
140 * You should have received a copy of the GNU General Public License
141 * along with this program. If not, see <http://www.gnu.org/licenses/>.
142 */
143 """)
144
145 find_layouts("../..")