1#! /usr/bin/awk -f
2#	$OpenBSD: makemap.awk,v 1.6 2005/05/23 21:33:03 miod Exp $
3#
4# Copyright (c) 2005, Miodrag Vallat
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18# DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25# POSSIBILITY OF SUCH DAMAGE.
26#
27#
28# This script attempts to convert, with minimal hacks and losses, the
29# regular PS/2 keyboard (pckbd) layout tables into USB keyboard (ukbd)
30# layout tables.
31#
32
33BEGIN {
34	rcsid = "$OpenBSD: makemap.awk,v 1.6 2005/05/23 21:33:03 miod Exp $"
35	ifdepth = 0
36	ignore = 0
37	declk = 0
38	haskeys = 0
39	kbfr = 0
40
41	# PS/2 id -> UKBD conversion table, or "sanity lossage 102"
42	# (101 is for GSC keyboards!)
43	for (i = 0; i < 256; i++)
44		conv[i] = -1
45
46	conv[1] = 41
47	conv[2] = 30
48	conv[3] = 31
49	conv[4] = 32
50	conv[5] = 33
51	conv[6] = 34
52	conv[7] = 35
53	conv[8] = 36
54	conv[9] = 37
55	conv[10] = 38
56	conv[11] = 39
57	conv[12] = 45
58	conv[13] = 46
59	conv[14] = 42
60	conv[15] = 43
61	conv[16] = 20
62	conv[17] = 26
63	conv[18] = 8
64	conv[19] = 21
65	conv[20] = 23
66	conv[21] = 28
67	conv[22] = 24
68	conv[23] = 12
69	conv[24] = 18
70	conv[25] = 19
71	conv[26] = 47
72	conv[27] = 48
73	conv[28] = 40
74	conv[29] = 224
75	conv[30] = 4
76	conv[31] = 22
77	conv[32] = 7
78	conv[33] = 9
79	conv[34] = 10
80	conv[35] = 11
81	conv[36] = 13
82	conv[37] = 14
83	conv[38] = 15
84	conv[39] = 51
85	conv[40] = 52
86	conv[41] = 53
87	conv[42] = 225
88	conv[43] = 50
89	conv[44] = 29
90	conv[45] = 27
91	conv[46] = 6
92	conv[47] = 25
93	conv[48] = 5
94	conv[49] = 17
95	conv[50] = 16
96	conv[51] = 54
97	conv[52] = 55
98	conv[53] = 56
99	conv[54] = 229
100	conv[55] = 85
101	conv[56] = 226
102	conv[57] = 44
103	conv[58] = 57
104	conv[59] = 58
105	conv[60] = 59
106	conv[61] = 60
107	conv[62] = 61
108	conv[63] = 62
109	conv[64] = 63
110	conv[65] = 64
111	conv[66] = 65
112	conv[67] = 66
113	conv[68] = 67
114	conv[69] = 83
115	conv[70] = 71
116	conv[71] = 95
117	conv[72] = 96
118	conv[73] = 97
119	conv[74] = 86
120	conv[75] = 92
121	conv[76] = 93
122	conv[77] = 94
123	conv[78] = 87
124	conv[79] = 89
125	conv[80] = 90M
126	conv[81] = 91
127	conv[82] = 98
128	conv[83] = 99
129	conv[86] = 100
130	conv[87] = 68
131	conv[88] = 69
132	conv[112] = 135
133	conv[115] = 136
134	conv[121] = 137
135	conv[123] = 138
136	conv[125] = 139
137	conv[127] = 72
138	conv[156] = 88
139	conv[157] = 228
140	conv[170] = 70
141	conv[181] = 84
142	conv[184] = 230
143	# 198 is #if 0 in the PS/2 map...
144	conv[199] = 74
145	conv[200] = 82
146	conv[201] = 75
147	conv[203] = 80
148	conv[205] = 79
149	conv[207] = 77
150	conv[208] = 81
151	conv[209] = 78
152	conv[210] = 73
153	conv[211] = 99
154	conv[219] = 227
155	conv[220] = 231
156	conv[221] = 101
157}
158NR == 1 {
159	VERSION = $0
160	gsub("\\$", "", VERSION)
161	gsub("\\$", "", rcsid)
162
163	printf("/*\t\$OpenBSD\$\t*/\n\n")
164	printf("/*\n")
165	printf(" * THIS FILE IS AUTOMAGICALLY GENERATED.  DO NOT EDIT.\n")
166	printf(" *\n")
167	printf(" * generated by:\n")
168	printf(" *\t%s\n", rcsid)
169	printf(" * generated from:\n")
170	printf(" */\n")
171	print VERSION
172
173	next
174}
175
176#
177# A very limited #if ... #endif parser. We only want to correctly detect
178# ``#if 0'' constructs, so as not to process their contents. This is necessary
179# since our output is out-of-order from our input.
180#
181# Note that this does NOT handle ``#ifdef notyet'' correctly - please only use
182# ``#if 0'' constructs in the input.
183#
184
185/^#if/ {
186	ignores[ifdepth] = ignore
187	if ($2 == "0")
188		ignore = 1
189	else
190		ignore = 0
191	ifdepth++
192	if (ignore)
193		next
194}
195/^#endif/ {
196	oldignore = ignore
197	ifdepth--
198	ignore = ignores[ifdepth]
199	ignores[ifdepth] = 0
200	if (oldignore)
201		next
202}
203
204$1 == "#include" {
205	if (ignore)
206		next
207	if ($2 == "<dev/pckbc/wskbdmap_mfii.h>")
208		print "#include <dev/usb/usb_port.h>"
209	else
210		printf("#include %s\n", $2)
211
212	next
213}
214$1 == "#define" || $1 == "#undef" {
215	if (ignore)
216		next
217	print $0
218	next
219}
220
221# Don't bother converting the DEC LK layout.
222/declk\[/ {
223	declk = 1
224	next
225}
226/declk/ {
227	next
228}
229
230/pckbd/ {
231	gsub("pckbd", "ukbd", $0)
232	mapname = $4
233}
234
235/KC/ {
236	if (ignore)
237		next
238
239	if (declk)
240		next
241
242	haskeys = 1
243
244	sidx = substr($1, 4, length($1) - 5)
245	orig = int(sidx)
246	id = conv[orig]
247
248	# 183 is another Print Screen...
249	if (orig == 183)
250		next
251
252	if (id == -1) {
253		printf("/* initially KC(%d),", orig)
254		for (f = 2; f <= NF; f++) {
255			if ($f != "/*" && $f != "*/")
256				printf("\t%s", $f)
257		}
258		printf("\t*/\n")
259	} else {
260		lines[id] = sprintf("    KC(%d),\t", id)
261		#
262		# This makes sure that the non-comment part of the output
263		# ends up with a trailing comma. This is necessary since
264		# the last line of an input block might not have a trailing
265		# comma, but might not be the last line of an output block
266		# due to sorting.
267		#
268		comma = 0
269		for (f = 2; f <= NF; f++) {
270			l = length($f)
271			if ($f == "/*")
272				comma++
273			if (comma == 0 && substr($f, l) != ",") {
274				lines[id] = sprintf("%s%s,", lines[id], $f)
275				l++
276			} else {
277				lines[id] = sprintf("%s%s", lines[id], $f)
278			}
279			if (comma == 0 && f != NF) {
280				if (l < 2 * 8)
281					lines[id] = lines[id] "\t"
282				if (l < 8)
283					lines[id] = lines[id] "\t"
284			}
285			if ($f == "*/")
286				comma--
287		}
288	}
289
290	next
291}
292/};/ {
293	if (ignore)
294		next
295
296	if (declk) {
297		declk = 0
298		next
299	}
300
301	if (haskeys) {
302		# Duplicate 42 (backspace) as 76 and 50 (backslash bar) as 49
303		if (!lines[76]) {
304			lines[76] = lines[42]
305			sub("42", "76", lines[76])
306		}
307		if (!lines[49]) {
308			lines[49] = lines[50]
309			sub("50", "49", lines[49])
310		}
311
312		for (i = 0; i < 256; i++)
313			if (lines[i]) {
314				print lines[i]
315				lines[i] = ""
316			}
317
318		haskeys = 0
319
320		#
321		# Apple black USB keyboards use a slightly different
322		# layout. We define them here.
323		#
324		if (mapname == "ukbd_keydesc_fr[]") {
325			print $0
326			print "\nstatic const keysym_t ukbd_keydesc_fr_apple[] = {"
327			print "    KC(5),\tKS_b,\t\tKS_B,\t\tKS_ssharp,"
328			print "    KC(8),\tKS_e,\t\tKS_E,\t\tKS_ecircumflex,\tKS_Ecircumflex,"
329			print "    KC(11),\tKS_h,\t\tKS_H,\t\tKS_Igrave,\tKS_Icircumflex,"
330			print "    KC(12),\tKS_i,\t\tKS_I,\t\tKS_icircumflex,\tKS_idiaeresis,"
331			print "    KC(13),\tKS_j,\t\tKS_J,\t\tKS_Idiaeresis,\tKS_Iacute,"
332			print "    KC(14),\tKS_k,\t\tKS_K,\t\tKS_Egrave,\tKS_Ediaeresis,"
333			print "    KC(15),\tKS_l,\t\tKS_L,\t\tKS_voidSymbol,\tKS_bar,"
334			print "    KC(16),\tKS_comma,\tKS_question,\tKS_voidSymbol,\tKS_questiondown,"
335			print "    KC(17),\tKS_n,\t\tKS_N,\t\tKS_asciitilde,"
336			print "    KC(20),\tKS_a,\t\tKS_A,\t\tKS_ae,\t\tKS_AE,"
337			print "    KC(21),\tKS_r,\t\tKS_R,\t\tKS_registered,\tKS_comma,"
338			print "    KC(22),\tKS_s,\t\tKS_S,\t\tKS_Ograve,"
339			print "    KC(26),\tKS_z,\t\tKS_Z,\t\tKS_Acircumflex,\tKS_Aring,"
340			print "    KC(28),\tKS_y,\t\tKS_Y,\t\tKS_Uacute,"
341			print "    KC(31),\tKS_eacute,\tKS_2,\t\tKS_ediaeresis,"
342			print "    KC(32),\tKS_quotedbl,\tKS_3,"
343			print "    KC(33),\tKS_apostrophe,\tKS_4,"
344			print "    KC(34),\tKS_parenleft,\tKS_5,\t\tKS_braceleft,\tKS_bracketleft,"
345			print "    KC(35),\tKS_section,\tKS_6,"
346			print "    KC(36),\tKS_egrave,\tKS_7,\t\tKS_guillemotleft,"
347			print "\t\t\t\t\t\tKS_guillemotright,"
348			print "    KC(37),\tKS_exclam,\tKS_8,"
349			print "    KC(38),\tKS_ccedilla,\tKS_9,\t\tKS_Ccedilla,\tKS_Aacute,"
350			print "    KC(37),\tKS_exclam,\tKS_8,\t\tKS_exclamdown,\tKS_Ucircumflex,"
351			print "    KC(39),\tKS_agrave,\tKS_0,\t\tKS_oslash,\tKS_Ooblique,"
352			print "    KC(45),\tKS_parenright,\tKS_degree,\tKS_braceright,\tKS_bracketright,"
353			print "    KC(46),\tKS_minus,\tKS_underscore,"
354			print "    KC(47),\tKS_dead_circumflex, KS_dead_diaeresis,"
355			print "\t\t\t\t\t\tKS_ocircumflex,\tKS_Ocircumflex,"
356			print "    KC(48),\tKS_dollar,\tKS_asterisk,\tKS_cent,\tKS_yen,"
357			print "    KC(50),\tKS_grave,\tKS_sterling,\tKS_at,\t\tKS_numbersign,"
358			print "    KC(51),\tKS_m,\t\tKS_M,\t\tKS_mu,\t\tKS_Oacute,"
359			print "    KC(52),\tKS_ugrave,\tKS_percent,\tKS_Ugrave,"
360			print "    KC(53),\tKS_at,\t\tKS_numbersign,"
361			print "    KC(55),\tKS_colon,\tKS_slash,\tKS_voidSymbol,\tKS_backslash,"
362			print "    KC(56),\tKS_equal,\tKS_plus,"
363			print "    KC(103),\tKS_KP_Equal,"
364			print "    KC(231),\tKS_Mode_switch,\tKS_Multi_key,"
365		} else
366		if (mapname == "ukbd_keydesc_pt[]") {
367			print $0
368			print "\nstatic const keysym_t ukbd_keydesc_pt_apple[] = {"
369			print "/*  pos\t\tnormal\t\tshifted */"
370			print "    KC(46),\tKS_plus,\tKS_asterisk,"
371			print "    KC(47),\tKS_masculine,\tKS_ordfeminine,"
372			print "    KC(50),\tKS_backslash,\tKS_bar,"
373			print "    KC(52),\tKS_dead_tilde,\tKS_dead_circumflex"
374		}
375	}
376}
377/KB_FR/ {
378	print $0
379	if (kbfr++ == 0) {
380		print "\tKBD_MAP(KB_FR | KB_APPLE,\tKB_FR,\tukbd_keydesc_fr_apple),"
381	} else {
382		print "\tKBD_MAP(KB_FR | KB_APPLE | KB_SWAPCTRLCAPS,\tKB_FR | KB_APPLE,"
383		print "\t\tukbd_keydesc_swapctrlcaps),"
384	}
385	next
386}
387/KB_PT/ {
388	print $0
389	print "\tKBD_MAP(KB_PT | KB_APPLE,\tKB_PT,\tukbd_keydesc_pt_apple),"
390	next
391}
392{
393	if (ignore)
394		next
395	if (declk)
396		next
397	print $0
398}
399