xref: /haiku/src/bin/keymap/Keymap.cpp (revision b30304acc8c37e678a1bf66976d15bdab103f931)
1 /*
2  *	Copyright (c) 2004-2006, Haiku, Inc.
3  *
4  *  This software is part of the Haiku distribution and is covered
5  *  by the Haiku license.
6  *
7  *  Author: Jérôme Duval
8  */
9 
10 
11 #include "Keymap.h"
12 
13 #include <ByteOrder.h>
14 #include <File.h>
15 #include <FindDirectory.h>
16 #include <Path.h>
17 #include <String.h>
18 
19 #include <stdlib.h>
20 #include <string.h>
21 #include <regex.h>
22 
23 
24 #define CHARS_TABLE_MAXSIZE  10000
25 
26 
27 void
28 dump_map(FILE* file, const char* name, int32* map)
29 {
30 	fprintf(file, "\t%s:{\n", name);
31 
32 	for (uint32 i = 0; i < 16; i++) {
33 		fprintf(file, "\t\t");
34 		for (uint32 j = 0; j < 8; j++) {
35 			fprintf(file, "0x%04lx,%s", map[i * 8 + j], j < 7 ? " " : "");
36 		}
37 		fprintf(file, "\n");
38 	}
39 	fprintf(file, "\t},\n");
40 }
41 
42 
43 void
44 dump_keys(FILE* file, const char* name, int32* keys)
45 {
46 	fprintf(file, "\t%s:{\n", name);
47 
48 	for (uint32 i = 0; i < 4; i++) {
49 		fprintf(file, "\t\t");
50 		for (uint32 j = 0; j < 8; j++) {
51 			fprintf(file, "0x%04lx,%s", keys[i * 8 + j], j < 7 ? " " : "");
52 		}
53 		fprintf(file, "\n");
54 	}
55 	fprintf(file, "\t},\n");
56 }
57 
58 
59 //	#pragma mark -
60 
61 
62 Keymap::Keymap()
63 	:
64 	fChars(NULL),
65 	fCharsSize(0)
66 {
67 	memset(&fKeys, 0, sizeof(fKeys));
68 }
69 
70 
71 Keymap::~Keymap()
72 {
73 	delete[] fChars;
74 }
75 
76 
77 void
78 Keymap::GetKey(char *chars, int32 offset, char* string)
79 {
80 	int size = chars[offset++];
81 	char str[32];
82 	memset(str, 0, 32);
83 	memset(string, 0, 32);
84 
85 	switch (size) {
86 		case 0:
87 			// Not mapped
88 			sprintf(str, "''");
89 			break;
90 
91 		case 1:
92 			// 1-byte UTF-8/ASCII character
93 			if ((uint8)chars[offset] < 0x20
94 				|| (uint8)chars[offset] > 0x7e)
95 				sprintf(str, "0x%02x", (uint8)chars[offset]);
96 			else
97 				sprintf(str, "'%s%c'",
98 					(chars[offset] == '\\' || chars[offset] == '\'') ? "\\" : "", chars[offset]);
99 			break;
100 
101 		default:
102 			// n-byte UTF-8/ASCII character
103 			sprintf(str, "0x");
104 			for (int i = 0; i < size; i++) {
105 				sprintf(str + 2*(i+1), "%02x", (uint8)chars[offset+i]);
106 			}
107 			break;
108 	}
109 
110 	strncpy(string, str, strlen(str) < 12 ? strlen(str) : 12);
111 		// TODO: Huh?
112 }
113 
114 
115 void
116 Keymap::Dump()
117 {
118 	printf("#!/bin/keymap -l\n"
119 		"#\n"
120 		"#\tRaw key numbering for 101 keyboard...\n"
121 		"#                                                                                        [sys]       [brk]\n"
122 		"#                                                                                         0x7e        0x7f\n"
123 		"# [esc]       [ f1] [ f2] [ f3] [ f4] [ f5] [ f6] [ f7] [ f8] [ f9] [f10] [f11] [f12]    [prn] [scr] [pau]\n"
124 		"#  0x01        0x02  0x03  0x04  0x05  0x06  0x07  0x08  0x09  0x0a  0x0b  0x0c  0x0d     0x0e  0x0f  0x10     K E Y P A D   K E Y S\n"
125 		"#\n"
126 		"# [ ` ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 0 ] [ - ] [ = ] [bck]    [ins] [hme] [pup]    [num] [ / ] [ * ] [ - ]\n"
127 		"#  0x11  0x12  0x13  0x14  0x15  0x16  0x17  0x18  0x19  0x1a  0x1b  0x1c  0x1d  0x1e     0x1f  0x20  0x21     0x22  0x23  0x24  0x25\n"
128 		"#\n"
129 		"# [tab] [ q ] [ w ] [ e ] [ r ] [ t ] [ y ] [ u ] [ i ] [ o ] [ p ] [ [ ] [ ] ] [ \\ ]    [del] [end] [pdn]    [ 7 ] [ 8 ] [ 9 ] [ + ]\n"
130 		"#  0x26  0x27  0x28  0x29  0x2a  0x2b  0x2c  0x2d  0x2e  0x2f  0x30  0x31  0x32  0x33     0x34  0x35  0x36     0x37  0x38  0x39  0x3a\n"
131 		"#\n"
132 		"# [cap] [ a ] [ s ] [ d ] [ f ] [ g ] [ h ] [ j ] [ k ] [ l ] [ ; ] [ ' ] [  enter  ]                         [ 4 ] [ 5 ] [ 6 ]\n"
133 		"#  0x3b  0x3c  0x3d  0x3e  0x3f  0x40  0x41  0x42  0x43  0x44  0x45  0x46     0x47                             0x48  0x49  0x4a\n"
134 		"#\n"
135 		"# [shift]     [ z ] [ x ] [ c ] [ v ] [ b ] [ n ] [ m ] [ , ] [ . ] [ / ]     [shift]          [ up]          [ 1 ] [ 2 ] [ 3 ] [ent]\n"
136 		"#   0x4b       0x4c  0x4d  0x4e  0x4f  0x50  0x51  0x52  0x53  0x54  0x55       0x56            0x57           0x58  0x59  0x5a  0x5b\n"
137 		"#\n"
138 		"# [ctr]             [cmd]             [  space  ]             [cmd]             [ctr]    [lft] [dwn] [rgt]    [ 0 ] [ . ]\n"
139 		"#  0x5c              0x5d                 0x5e                 0x5f              0x60     0x61  0x62  0x63     0x64  0x65\n"
140 		"#\n"
141 		"#\tNOTE: On a Microsoft Natural Keyboard:\n"
142 		"#\t\t\tleft option  = 0x66\n"
143 		"#\t\t\tright option = 0x67\n"
144 		"#\t\t\tmenu key     = 0x68\n"
145 		"#\tNOTE: On an Apple Extended Keyboard:\n"
146 		"#\t\t\tleft option  = 0x66\n"
147 		"#\t\t\tright option = 0x67\n"
148 		"#\t\t\tkeypad '='   = 0x6a\n"
149 		"#\t\t\tpower key    = 0x6b\n");
150 
151 	printf("Version = %ld\n", fKeys.version);
152 	printf("CapsLock = 0x%02lx\n", fKeys.caps_key);
153 	printf("ScrollLock = 0x%02lx\n", fKeys.scroll_key);
154 	printf("NumLock = 0x%02lx\n", fKeys.num_key);
155 	printf("LShift = 0x%02lx\n", fKeys.left_shift_key);
156 	printf("RShift = 0x%02lx\n", fKeys.right_shift_key);
157 	printf("LCommand = 0x%02lx\n", fKeys.left_command_key);
158 	printf("RCommand = 0x%02lx\n", fKeys.right_command_key);
159 	printf("LControl = 0x%02lx\n", fKeys.left_control_key);
160 	printf("RControl = 0x%02lx\n", fKeys.right_control_key);
161 	printf("LOption = 0x%02lx\n", fKeys.left_option_key);
162 	printf("ROption = 0x%02lx\n", fKeys.right_option_key);
163 	printf("Menu = 0x%02lx\n", fKeys.menu_key);
164 	printf("#\n"
165 		"# Lock settings\n"
166 		"# To set NumLock, do the following:\n"
167 		"#   LockSettings = NumLock\n"
168 		"#\n"
169 		"# To set everything, do the following:\n"
170 		"#   LockSettings = CapsLock NumLock ScrollLock\n"
171 		"#\n");
172 	printf("LockSettings = ");
173 	if (fKeys.lock_settings & B_CAPS_LOCK)
174 		printf("CapsLock ");
175 	if (fKeys.lock_settings & B_NUM_LOCK)
176 		printf("NumLock ");
177 	if (fKeys.lock_settings & B_SCROLL_LOCK)
178 		printf("ScrollLock ");
179 	printf("\n");
180 	printf("# Legend:\n"
181 		"#   n = Normal\n"
182 		"#   s = Shift\n"
183 		"#   c = Control\n"
184 		"#   C = CapsLock\n"
185 		"#   o = Option\n"
186 		"# Key      n        s        c        o        os       C        Cs       Co       Cos     \n");
187 
188 	for (int idx = 0; idx < 128; idx++) {
189 		char normalKey[32];
190 		char shiftKey[32];
191 		char controlKey[32];
192 		char optionKey[32];
193 		char optionShiftKey[32];
194 		char capsKey[32];
195 		char capsShiftKey[32];
196 		char optionCapsKey[32];
197 		char optionCapsShiftKey[32];
198 
199 		GetKey(fChars, fKeys.normal_map[idx], normalKey);
200 		GetKey(fChars, fKeys.shift_map[idx], shiftKey);
201 		GetKey(fChars, fKeys.control_map[idx], controlKey);
202 		GetKey(fChars, fKeys.option_map[idx], optionKey);
203 		GetKey(fChars, fKeys.option_shift_map[idx], optionShiftKey);
204 		GetKey(fChars, fKeys.caps_map[idx], capsKey);
205 		GetKey(fChars, fKeys.caps_shift_map[idx], capsShiftKey);
206 		GetKey(fChars, fKeys.option_caps_map[idx], optionCapsKey);
207 		GetKey(fChars, fKeys.option_caps_shift_map[idx], optionCapsShiftKey);
208 
209 		printf("Key 0x%02x = %-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s\n", idx, normalKey, shiftKey, controlKey,
210 			optionKey, optionShiftKey, capsKey, capsShiftKey, optionCapsKey, optionCapsShiftKey);
211 	}
212 
213 	int32* deadOffsets[] = {
214 		fKeys.acute_dead_key,
215 		fKeys.grave_dead_key,
216 		fKeys.circumflex_dead_key,
217 		fKeys.dieresis_dead_key,
218 		fKeys.tilde_dead_key
219 	};
220 
221 	char labels[][12] = {
222 		"Acute",
223 		"Grave",
224 		"Circumflex",
225 		"Diaeresis",
226 		"Tilde"
227 	};
228 
229 	uint32 deadTables[] = {
230 		fKeys.acute_tables,
231 		fKeys.grave_tables,
232 		fKeys.circumflex_tables,
233 		fKeys.dieresis_tables,
234 		fKeys.tilde_tables
235 	};
236 
237 	for (int i = 0; i<5; i++) {
238 		for (int idx = 0; idx < 32; idx++ ) {
239 			char deadKey[32];
240 			char secondKey[32];
241 			GetKey(fChars, deadOffsets[i][idx++], deadKey);
242 			GetKey(fChars, deadOffsets[i][idx], secondKey);
243 			printf("%s %-9s = %-9s\n", labels[i], deadKey, secondKey);
244 		}
245 
246 		printf("%sTab = ", labels[i]);
247 
248 		if (deadTables[i] & B_NORMAL_TABLE)
249 			printf("Normal ");
250 		if (deadTables[i] & B_SHIFT_TABLE)
251 			printf("Shift ");
252 		if (deadTables[i] & B_CONTROL_TABLE)
253 			printf("Control ");
254 		if (deadTables[i] & B_OPTION_TABLE)
255 			printf("Option ");
256 		if (deadTables[i] & B_OPTION_SHIFT_TABLE)
257 			printf("Option-Shift ");
258 		if (deadTables[i] & B_CAPS_TABLE)
259 			printf("CapsLock ");
260 		if (deadTables[i] & B_CAPS_SHIFT_TABLE)
261 			printf("CapsLock-Shift ");
262 		if (deadTables[i] & B_OPTION_CAPS_TABLE)
263 			printf("CapsLock-Option ");
264 		if (deadTables[i] & B_OPTION_CAPS_SHIFT_TABLE)
265 			printf("CapsLock-Option-Shift ");
266 		printf("\n");
267 	}
268 }
269 
270 
271 status_t
272 Keymap::LoadCurrent()
273 {
274 #ifdef __BEOS__
275 	key_map *keys = NULL;
276 	get_key_map(&keys, &fChars);
277 	if (!keys)
278 		return B_ERROR;
279 
280 	memcpy(&fKeys, keys, sizeof(fKeys));
281 	free(keys);
282 	return B_OK;
283 
284 #else	// ! __BEOS__
285 	fprintf(stderr, "Unsupported operation on this platform!\n");
286 	exit(1);
287 #endif	// ! __BEOS__
288 }
289 
290 
291 /*!
292 	Load a map from a file.
293 
294 	file format in big endian:
295 		struct key_map
296 		uint32 size of following charset
297 		charset (offsets go into this with size of character followed by character)
298 */
299 status_t
300 Keymap::Load(entry_ref &ref)
301 {
302 	status_t err;
303 
304 	BFile file(&ref, B_READ_ONLY);
305 	if ((err = file.InitCheck()) != B_OK)
306 		return err;
307 
308 	if (file.Read(&fKeys, sizeof(fKeys)) < (ssize_t)sizeof(fKeys))
309 		return B_BAD_VALUE;
310 
311 	for (uint32 i = 0; i < sizeof(fKeys) / 4; i++) {
312 		((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]);
313 	}
314 
315 	if (fKeys.version != 3)
316 		return KEYMAP_ERROR_UNKNOWN_VERSION;
317 
318 	if (file.Read(&fCharsSize, sizeof(uint32)) < (ssize_t)sizeof(uint32))
319 		return B_BAD_VALUE;
320 
321 	fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize);
322 	if (!fChars)
323 		delete[] fChars;
324 	fChars = new char[fCharsSize];
325 	if ((unsigned)file.Read(fChars, fCharsSize) != fCharsSize)
326 		return B_BAD_VALUE;
327 
328 	return B_OK;
329 }
330 
331 
332 void
333 Keymap::ComputeChars(const char *buffer, struct re_registers &regs, int i, int &offset)
334 {
335 	char *current = &fChars[offset + 1];
336 	char hexChars[12];
337 	uint32 length = 0;
338 	if (strncmp(buffer + regs.start[i], "''", regs.end[i] - regs.start[i]) == 0)
339 		length = 0;
340 	else if (sscanf(buffer + regs.start[i], "'%s'", current) > 0) {
341 		if (current[0] == '\\')
342 			current[0] = current[1];
343 		else if (current[0] == '\'')
344 			current[0] = ' ';
345 		length = 1;
346 	} else if (sscanf(buffer + regs.start[i], "0x%s", hexChars) > 0) {
347 		length = strlen(hexChars) / 2;
348 		for (uint32 j = 0; j < length; j++)
349 			sscanf(hexChars + 2*j, "%02hhx", current + j);
350 	}
351 	fChars[offset] = length;
352 	offset += length + 1;
353 }
354 
355 
356 void
357 Keymap::ComputeTables(const char *buffer, struct re_registers &regs, uint32 &table)
358 {
359 	for (int32 i=1; i<=9; i++) {
360 		if (regs.end[i] - regs.start[i] <= 0)
361 			break;
362 		if (strncmp(buffer + regs.start[i], "Normal", regs.end[i] - regs.start[i]) == 0)
363 			table |= B_NORMAL_TABLE;
364 		else if (strncmp(buffer + regs.start[i], "Shift", regs.end[i] - regs.start[i]) == 0)
365 			table |= B_SHIFT_TABLE;
366 		else if (strncmp(buffer + regs.start[i], "Control", regs.end[i] - regs.start[i]) == 0)
367 			table |= B_CONTROL_TABLE;
368 		else if (strncmp(buffer + regs.start[i], "Option", regs.end[i] - regs.start[i]) == 0)
369 			table |= B_OPTION_TABLE;
370 		else if (strncmp(buffer + regs.start[i], "Option-Shift", regs.end[i] - regs.start[i]) == 0)
371 			table |= B_OPTION_SHIFT_TABLE;
372 		else if (strncmp(buffer + regs.start[i], "CapsLock", regs.end[i] - regs.start[i]) == 0)
373 			table |= B_CAPS_TABLE;
374 		else if (strncmp(buffer + regs.start[i], "CapsLock-Shift", regs.end[i] - regs.start[i]) == 0)
375 			table |= B_CAPS_SHIFT_TABLE;
376 		else if (strncmp(buffer + regs.start[i], "CapsLock-Option", regs.end[i] - regs.start[i]) == 0)
377 			table |= B_OPTION_CAPS_TABLE;
378 		else if (strncmp(buffer + regs.start[i], "CapsLock-Option-Shift", regs.end[i] - regs.start[i]) == 0)
379 			table |= B_OPTION_CAPS_SHIFT_TABLE;
380 	}
381 }
382 
383 
384 status_t
385 Keymap::LoadSourceFromRef(entry_ref &ref)
386 {
387 	status_t err;
388 
389 	BFile file(&ref, B_READ_ONLY);
390 	if ((err = file.InitCheck()) != B_OK)
391 		return err;
392 
393 	int fd = file.Dup();
394 	FILE* f = fdopen(fd, "r");
395 	if (f != NULL) {
396 		err = LoadSource(f);
397 		fclose(f);
398 	} else
399 		err = B_FILE_ERROR;
400 
401 	return err;
402 }
403 
404 
405 // i couldn't put patterns and pattern bufs on the stack without segfaulting
406 // regexp patterns
407 const char versionPattern[] = "Version[[:space:]]+=[[:space:]]+\\([[:digit:]]+\\)";
408 const char capslockPattern[] = "CapsLock[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
409 const char scrolllockPattern[] = "ScrollLock[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
410 const char numlockPattern[] = "NumLock[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
411 const char lshiftPattern[] = "LShift[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
412 const char rshiftPattern[] = "RShift[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
413 const char lcommandPattern[] = "LCommand[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
414 const char rcommandPattern[] = "RCommand[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
415 const char lcontrolPattern[] = "LControl[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
416 const char rcontrolPattern[] = "RControl[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
417 const char loptionPattern[] = "LOption[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
418 const char roptionPattern[] = "ROption[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
419 const char menuPattern[] = "Menu[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\)";
420 const char locksettingsPattern[] = "LockSettings[[:space:]]+=[[:space:]]+\\([[:alnum:]]*\\)"
421 						"[[:space:]]*\\([[:alnum:]]*\\)"
422 						"[[:space:]]*\\([[:alnum:]]*\\)[[:space:]]*";
423 const char keyPattern[] = "Key[[:space:]]+\\([[:alnum:]]+\\)[[:space:]]+="
424 						"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
425 						"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
426 						"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
427 						"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
428 						"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
429 						"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
430 						"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
431 						"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
432 						"[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)"
433 						"[[:space:]]+";
434 
435 
436 const char acutePattern[] = "Acute[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+";
437 const char gravePattern[] = "Grave[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+";
438 const char circumflexPattern[] = "Circumflex[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+";
439 const char diaeresisPattern[] = "Diaeresis[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+";
440 const char tildePattern[] = "Tilde[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+=[[:space:]]+\\([[:alnum:]]+\\|'.*'\\)[[:space:]]+";
441 const char acutetabPattern[] = "AcuteTab[[:space:]]+="
442 						"[[:space:]]+\\([[:alnum:]-]*\\)"
443 						"[[:space:]]*\\([[:alnum:]-]*\\)"
444 						"[[:space:]]*\\([[:alnum:]-]*\\)"
445 						"[[:space:]]*\\([[:alnum:]-]*\\)"
446 						"[[:space:]]*\\([[:alnum:]-]*\\)"
447 						"[[:space:]]*\\([[:alnum:]-]*\\)"
448 						"[[:space:]]*\\([[:alnum:]-]*\\)"
449 						"[[:space:]]*\\([[:alnum:]-]*\\)"
450 						"[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ;
451 const char gravetabPattern[] = "GraveTab[[:space:]]+="
452 						"[[:space:]]+\\([[:alnum:]-]*\\)"
453 						"[[:space:]]*\\([[:alnum:]-]*\\)"
454 						"[[:space:]]*\\([[:alnum:]-]*\\)"
455 						"[[:space:]]*\\([[:alnum:]-]*\\)"
456 						"[[:space:]]*\\([[:alnum:]-]*\\)"
457 						"[[:space:]]*\\([[:alnum:]-]*\\)"
458 						"[[:space:]]*\\([[:alnum:]-]*\\)"
459 						"[[:space:]]*\\([[:alnum:]-]*\\)"
460 						"[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ;
461 const char circumflextabPattern[] = "CircumflexTab[[:space:]]+="
462 						"[[:space:]]+\\([[:alnum:]-]*\\)"
463 						"[[:space:]]*\\([[:alnum:]-]*\\)"
464 						"[[:space:]]*\\([[:alnum:]-]*\\)"
465 						"[[:space:]]*\\([[:alnum:]-]*\\)"
466 						"[[:space:]]*\\([[:alnum:]-]*\\)"
467 						"[[:space:]]*\\([[:alnum:]-]*\\)"
468 						"[[:space:]]*\\([[:alnum:]-]*\\)"
469 						"[[:space:]]*\\([[:alnum:]-]*\\)"
470 						"[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ;
471 const char diaeresistabPattern[] = "DiaeresisTab[[:space:]]+="
472 						"[[:space:]]+\\([[:alnum:]-]*\\)"
473 						"[[:space:]]*\\([[:alnum:]-]*\\)"
474 						"[[:space:]]*\\([[:alnum:]-]*\\)"
475 						"[[:space:]]*\\([[:alnum:]-]*\\)"
476 						"[[:space:]]*\\([[:alnum:]-]*\\)"
477 						"[[:space:]]*\\([[:alnum:]-]*\\)"
478 						"[[:space:]]*\\([[:alnum:]-]*\\)"
479 						"[[:space:]]*\\([[:alnum:]-]*\\)"
480 						"[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ;
481 const char tildetabPattern[] = "TildeTab[[:space:]]+="
482 						"[[:space:]]+\\([[:alnum:]-]*\\)"
483 						"[[:space:]]*\\([[:alnum:]-]*\\)"
484 						"[[:space:]]*\\([[:alnum:]-]*\\)"
485 						"[[:space:]]*\\([[:alnum:]-]*\\)"
486 						"[[:space:]]*\\([[:alnum:]-]*\\)"
487 						"[[:space:]]*\\([[:alnum:]-]*\\)"
488 						"[[:space:]]*\\([[:alnum:]-]*\\)"
489 						"[[:space:]]*\\([[:alnum:]-]*\\)"
490 						"[[:space:]]*\\([[:alnum:]-]*\\)[[:space:]]*" ;
491 
492 
493 // re_pattern_buffer buffers
494 struct re_pattern_buffer versionBuf;
495 struct re_pattern_buffer capslockBuf;
496 struct re_pattern_buffer scrolllockBuf;
497 struct re_pattern_buffer numlockBuf;
498 struct re_pattern_buffer lshiftBuf;
499 struct re_pattern_buffer rshiftBuf;
500 struct re_pattern_buffer lcommandBuf;
501 struct re_pattern_buffer rcommandBuf;
502 struct re_pattern_buffer lcontrolBuf;
503 struct re_pattern_buffer rcontrolBuf;
504 struct re_pattern_buffer loptionBuf;
505 struct re_pattern_buffer roptionBuf;
506 struct re_pattern_buffer menuBuf;
507 struct re_pattern_buffer locksettingsBuf;
508 struct re_pattern_buffer keyBuf;
509 struct re_pattern_buffer acuteBuf;
510 struct re_pattern_buffer graveBuf;
511 struct re_pattern_buffer circumflexBuf;
512 struct re_pattern_buffer diaeresisBuf;
513 struct re_pattern_buffer tildeBuf;
514 struct re_pattern_buffer acutetabBuf;
515 struct re_pattern_buffer gravetabBuf;
516 struct re_pattern_buffer circumflextabBuf;
517 struct re_pattern_buffer diaeresistabBuf;
518 struct re_pattern_buffer tildetabBuf;
519 
520 status_t
521 Keymap::LoadSource(FILE * f)
522 {
523 	reg_syntax_t syntax = RE_CHAR_CLASSES;
524 	re_set_syntax(syntax);
525 
526 	const char* error;
527 	error = re_compile_pattern(versionPattern, strlen(versionPattern), &versionBuf);
528 	if (error)
529 		fprintf(stderr, error);
530 	error = re_compile_pattern(capslockPattern, strlen(capslockPattern), &capslockBuf);
531 	if (error)
532 		fprintf(stderr, error);
533 	error = re_compile_pattern(scrolllockPattern, strlen(scrolllockPattern), &scrolllockBuf);
534 	if (error)
535 		fprintf(stderr, error);
536 	error = re_compile_pattern(numlockPattern, strlen(numlockPattern), &numlockBuf);
537 	if (error)
538 		fprintf(stderr, error);
539 	error = re_compile_pattern(lshiftPattern, strlen(lshiftPattern), &lshiftBuf);
540 	if (error)
541 		fprintf(stderr, error);
542 	error = re_compile_pattern(rshiftPattern, strlen(rshiftPattern), &rshiftBuf);
543 	if (error)
544 		fprintf(stderr, error);
545 	error = re_compile_pattern(lcommandPattern, strlen(lcommandPattern), &lcommandBuf);
546 	if (error)
547 		fprintf(stderr, error);
548 	error = re_compile_pattern(rcommandPattern, strlen(rcommandPattern), &rcommandBuf);
549 	if (error)
550 		fprintf(stderr, error);
551 	error = re_compile_pattern(lcontrolPattern, strlen(lcontrolPattern), &lcontrolBuf);
552 	if (error)
553 		fprintf(stderr, error);
554 	error = re_compile_pattern(rcontrolPattern, strlen(rcontrolPattern), &rcontrolBuf);
555 	if (error)
556 		fprintf(stderr, error);
557 	error = re_compile_pattern(loptionPattern, strlen(loptionPattern), &loptionBuf);
558 	if (error)
559 		fprintf(stderr, error);
560 	error = re_compile_pattern(roptionPattern, strlen(roptionPattern), &roptionBuf);
561 	if (error)
562 		fprintf(stderr, error);
563 	error = re_compile_pattern(menuPattern, strlen(menuPattern), &menuBuf);
564 	if (error)
565 		fprintf(stderr, error);
566 	error = re_compile_pattern(locksettingsPattern, strlen(locksettingsPattern), &locksettingsBuf);
567 	if (error)
568 		fprintf(stderr, error);
569 	error = re_compile_pattern(keyPattern, strlen(keyPattern), &keyBuf);
570 	if (error)
571 		fprintf(stderr, error);
572 	error = re_compile_pattern(acutePattern, strlen(acutePattern), &acuteBuf);
573 	if (error)
574 		fprintf(stderr, error);
575 	error = re_compile_pattern(gravePattern, strlen(gravePattern), &graveBuf);
576 	if (error)
577 		fprintf(stderr, error);
578 	error = re_compile_pattern(circumflexPattern, strlen(circumflexPattern), &circumflexBuf);
579 	if (error)
580 		fprintf(stderr, error);
581 	error = re_compile_pattern(diaeresisPattern, strlen(diaeresisPattern), &diaeresisBuf);
582 	if (error)
583 		fprintf(stderr, error);
584 	error = re_compile_pattern(tildePattern, strlen(tildePattern), &tildeBuf);
585 	if (error)
586 		fprintf(stderr, error);
587 	error = re_compile_pattern(acutetabPattern, strlen(acutetabPattern), &acutetabBuf);
588 	if (error)
589 		fprintf(stderr, error);
590 	error = re_compile_pattern(gravetabPattern, strlen(gravetabPattern), &gravetabBuf);
591 	if (error)
592 		fprintf(stderr, error);
593 	error = re_compile_pattern(circumflextabPattern, strlen(circumflextabPattern), &circumflextabBuf);
594 	if (error)
595 		fprintf(stderr, error);
596 	error = re_compile_pattern(diaeresistabPattern, strlen(diaeresistabPattern), &diaeresistabBuf);
597 	if (error)
598 		fprintf(stderr, error);
599 	error = re_compile_pattern(tildetabPattern, strlen(tildetabPattern), &tildetabBuf);
600 	if (error)
601 		fprintf(stderr, error);
602 
603 	char buffer[1024];
604 
605 	delete[] fChars;
606 	fChars = new char[CHARS_TABLE_MAXSIZE];
607 	fCharsSize = CHARS_TABLE_MAXSIZE;
608 	int offset = 0;
609 	int acuteOffset = 0;
610 	int graveOffset = 0;
611 	int circumflexOffset = 0;
612 	int diaeresisOffset = 0;
613 	int tildeOffset = 0;
614 
615 	int32 *maps[] = {
616 		fKeys.normal_map,
617 		fKeys.shift_map,
618 		fKeys.control_map,
619 		fKeys.option_map,
620 		fKeys.option_shift_map,
621 		fKeys.caps_map,
622 		fKeys.caps_shift_map,
623 		fKeys.option_caps_map,
624 		fKeys.option_caps_shift_map
625 	};
626 
627 	while (fgets(buffer, 1024-1, f) != NULL) {
628 		if (buffer[0] == '#' || buffer[0] == '\n')
629 			continue;
630 
631 		struct re_registers regs;
632 		if (re_search(&versionBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
633 			sscanf(buffer + regs.start[1], "%ld", &fKeys.version);
634 		} else if (re_search(&capslockBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
635 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.caps_key);
636 		} else if (re_search(&scrolllockBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
637 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.scroll_key);
638 		} else if (re_search(&numlockBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
639 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.num_key);
640 		} else if (re_search(&lshiftBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
641 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.left_shift_key);
642 		} else if (re_search(&rshiftBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
643 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.right_shift_key);
644 		} else if (re_search(&lcommandBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
645 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.left_command_key);
646 		} else if (re_search(&rcommandBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
647 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.right_command_key);
648 		} else if (re_search(&lcontrolBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
649 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.left_control_key);
650 		} else if (re_search(&rcontrolBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
651 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.right_control_key);
652 		} else if (re_search(&loptionBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
653 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.left_option_key);
654 		} else if (re_search(&roptionBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
655 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.right_option_key);
656 		} else if (re_search(&menuBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
657 			sscanf(buffer + regs.start[1], "0x%lx", &fKeys.menu_key);
658 		} else if (re_search(&locksettingsBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
659 			fKeys.lock_settings = 0;
660 			for (int32 i = 1; i <= 3; i++) {
661 				if (regs.end[i] - regs.start[i] <= 0)
662 					break;
663 
664 				if (strncmp(buffer + regs.start[i], "CapsLock", regs.end[i] - regs.start[i]) == 0)
665 					fKeys.lock_settings |= B_CAPS_LOCK;
666 				else if (strncmp(buffer + regs.start[i], "NumLock", regs.end[i] - regs.start[i]) == 0)
667 					fKeys.lock_settings |= B_NUM_LOCK;
668 				else if (strncmp(buffer + regs.start[i], "ScrollLock", regs.end[i] - regs.start[i]) == 0)
669 					fKeys.lock_settings |= B_SCROLL_LOCK;
670 			}
671 		} else if (re_search(&keyBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
672 			uint32 keyCode;
673 			if (sscanf(buffer + regs.start[1], "0x%lx", &keyCode) > 0) {
674 				for (int i = 2; i <= 10; i++) {
675 					maps[i - 2][keyCode] = offset;
676 					ComputeChars(buffer, regs, i, offset);
677 				}
678 			}
679 		} else if (re_search(&acuteBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
680 			for (int i = 1; i <= 2; i++) {
681 				fKeys.acute_dead_key[acuteOffset++] = offset;
682 				ComputeChars(buffer, regs, i, offset);
683 			}
684 		} else if (re_search(&graveBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
685 			for (int i = 1; i <= 2; i++) {
686 				fKeys.grave_dead_key[graveOffset++] = offset;
687 				ComputeChars(buffer, regs, i, offset);
688 			}
689 		} else if (re_search(&circumflexBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
690 			for (int i = 1; i <= 2; i++) {
691 				fKeys.circumflex_dead_key[circumflexOffset++] = offset;
692 				ComputeChars(buffer, regs, i, offset);
693 			}
694 		} else if (re_search(&diaeresisBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
695 			for (int i = 1; i <= 2; i++) {
696 				fKeys.dieresis_dead_key[diaeresisOffset++] = offset;
697 				ComputeChars(buffer, regs, i, offset);
698 			}
699 		} else if (re_search(&tildeBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
700 			for (int i = 1; i <= 2; i++) {
701 				fKeys.tilde_dead_key[tildeOffset++] = offset;
702 				ComputeChars(buffer, regs, i, offset);
703 			}
704 		} else if (re_search(&acutetabBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
705 			ComputeTables(buffer, regs, fKeys.acute_tables);
706 		} else if (re_search(&gravetabBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
707 			ComputeTables(buffer, regs, fKeys.grave_tables);
708 		} else if (re_search(&circumflextabBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
709 			ComputeTables(buffer, regs, fKeys.circumflex_tables);
710 		} else if (re_search(&diaeresistabBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
711 			ComputeTables(buffer, regs, fKeys.dieresis_tables);
712 		} else if (re_search(&tildetabBuf, buffer, strlen(buffer), 0, strlen(buffer), &regs) >= 0) {
713 			ComputeTables(buffer, regs, fKeys.tilde_tables);
714 		}
715 	}
716 
717 	fCharsSize = offset;
718 
719 	if (fKeys.version != 3)
720 		return KEYMAP_ERROR_UNKNOWN_VERSION;
721 
722 	return B_OK;
723 }
724 
725 
726 //! we save a map to a file
727 status_t
728 Keymap::Save(entry_ref &ref)
729 {
730 	status_t err;
731 
732 	BFile file(&ref, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE );
733 	if ((err = file.InitCheck()) != B_OK)
734 		return err;
735 
736 	// convert to big endian
737 	for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) {
738 		((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]);
739 	}
740 
741 	ssize_t bytesWritten = file.Write(&fKeys, sizeof(fKeys));
742 
743 	// convert endian back
744 	for (uint32 i = 0; i < sizeof(fKeys) / sizeof(uint32); i++) {
745 		((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]);
746 	}
747 
748 	if (bytesWritten < (ssize_t)sizeof(fKeys))
749 		return B_ERROR;
750 	if (bytesWritten < B_OK)
751 		return bytesWritten;
752 
753 	uint32 charSize = B_HOST_TO_BENDIAN_INT32(fCharsSize);
754 
755 	bytesWritten = file.Write(&charSize, sizeof(uint32));
756 	if (bytesWritten < (ssize_t)sizeof(uint32))
757 		return B_ERROR;
758 	if (bytesWritten < B_OK)
759 		return bytesWritten;
760 
761 	bytesWritten = file.Write(fChars, fCharsSize);
762 	if (bytesWritten < (ssize_t)fCharsSize)
763 		return B_ERROR;
764 	if (bytesWritten < B_OK)
765 		return bytesWritten;
766 
767 	return B_OK;
768 }
769 
770 
771 /*!
772 	Save a keymap as C source file - this is used to get the default keymap
773 	into the input_server, for example.
774 */
775 void
776 Keymap::SaveAsHeader(entry_ref &ref, const char *mapName)
777 {
778 	BPath path;
779 	status_t err = path.SetTo(&ref);
780 	if (err < B_OK)
781 		return;
782 
783 	BString name = mapName;
784 	int slashidx = name.FindLast('/');
785 	if (slashidx > 0) {
786 		// prune off path
787 		name.Remove(0, slashidx + 1);
788 	}
789 	// prune ".keymap"
790 	name.Remove(name.FindLast('.'), 7);
791 
792 	FILE* file = fopen(path.Path(), "w");
793 
794 	fprintf(file, "/*\n"
795 		" * Haiku Keymap\n"
796 		" * This file is generated automatically. Don't edit!\n"
797 		" */\n\n");
798 	fprintf(file, "#include <InterfaceDefs.h>\n\n");
799 	fprintf(file, "const char *kSystemKeymapName = \"%s\";\n\n", name.String());
800 	fprintf(file, "const key_map kSystemKeymap = {\n");
801 	fprintf(file, "\tversion:%ld,\n", fKeys.version);
802 	fprintf(file, "\tcaps_key:0x%lx,\n", fKeys.caps_key);
803 	fprintf(file, "\tscroll_key:0x%lx,\n", fKeys.scroll_key);
804 	fprintf(file, "\tnum_key:0x%lx,\n", fKeys.num_key);
805 	fprintf(file, "\tleft_shift_key:0x%lx,\n", fKeys.left_shift_key);
806 	fprintf(file, "\tright_shift_key:0x%lx,\n", fKeys.right_shift_key);
807 	fprintf(file, "\tleft_command_key:0x%lx,\n", fKeys.left_command_key);
808 	fprintf(file, "\tright_command_key:0x%lx,\n", fKeys.right_command_key);
809 	fprintf(file, "\tleft_control_key:0x%lx,\n", fKeys.left_control_key);
810 	fprintf(file, "\tright_control_key:0x%lx,\n", fKeys.right_control_key);
811 	fprintf(file, "\tleft_option_key:0x%lx,\n", fKeys.left_option_key);
812 	fprintf(file, "\tright_option_key:0x%lx,\n", fKeys.right_option_key);
813 	fprintf(file, "\tmenu_key:0x%lx,\n", fKeys.menu_key);
814 	fprintf(file, "\tlock_settings:0x%lx,\n", fKeys.lock_settings);
815 
816 	dump_map(file, "control_map", fKeys.control_map);
817 	dump_map(file, "option_caps_shift_map", fKeys.option_caps_shift_map);
818 	dump_map(file, "option_caps_map", fKeys.option_caps_map);
819 	dump_map(file, "option_shift_map", fKeys.option_shift_map);
820 	dump_map(file, "option_map", fKeys.option_map);
821 	dump_map(file, "caps_shift_map", fKeys.caps_shift_map);
822 	dump_map(file, "caps_map", fKeys.caps_map);
823 	dump_map(file, "shift_map", fKeys.shift_map);
824 	dump_map(file, "normal_map", fKeys.normal_map);
825 
826 	dump_keys(file, "acute_dead_key", fKeys.acute_dead_key);
827 	dump_keys(file, "grave_dead_key", fKeys.grave_dead_key);
828 
829 	dump_keys(file, "circumflex_dead_key", fKeys.circumflex_dead_key);
830 	dump_keys(file, "dieresis_dead_key", fKeys.dieresis_dead_key);
831 	dump_keys(file, "tilde_dead_key", fKeys.tilde_dead_key);
832 
833 	fprintf(file, "\tacute_tables:0x%lx,\n", fKeys.acute_tables);
834 	fprintf(file, "\tgrave_tables:0x%lx,\n", fKeys.grave_tables);
835 	fprintf(file, "\tcircumflex_tables:0x%lx,\n", fKeys.circumflex_tables);
836 	fprintf(file, "\tdieresis_tables:0x%lx,\n", fKeys.dieresis_tables);
837 	fprintf(file, "\ttilde_tables:0x%lx,\n", fKeys.tilde_tables);
838 
839 	fprintf(file, "};\n\n");
840 
841 	fprintf(file, "const char kSystemKeyChars[] = {\n");
842 	for (uint32 i = 0; i < fCharsSize; i++) {
843 		if (i % 10 == 0) {
844 			if (i > 0)
845 				fprintf(file, "\n");
846 			fprintf(file, "\t");
847 		} else
848 			fprintf(file, " ");
849 
850 		fprintf(file, "0x%02x,", (uint8)fChars[i]);
851 	}
852 	fprintf(file, "\n};\n\n");
853 
854 	fprintf(file, "const uint32 kSystemKeyCharsSize = %ld;\n", fCharsSize);
855 	fclose(file);
856 }
857 
858 
859 /*!
860 	We need to know if a key is a modifier key to choose
861 	a valid key when several are pressed together
862 */
863 bool
864 Keymap::IsModifierKey(uint32 keyCode)
865 {
866 	return keyCode == fKeys.caps_key
867 		|| keyCode == fKeys.num_key
868 		|| keyCode == fKeys.left_shift_key
869 		|| keyCode == fKeys.right_shift_key
870 		|| keyCode == fKeys.left_command_key
871 		|| keyCode == fKeys.right_command_key
872 		|| keyCode == fKeys.left_control_key
873 		|| keyCode == fKeys.right_control_key
874 		|| keyCode == fKeys.left_option_key
875 		|| keyCode == fKeys.right_option_key
876 		|| keyCode == fKeys.menu_key;
877 }
878 
879 
880 //! Tell if a key is a dead key, needed for draw a dead key
881 uint8
882 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers)
883 {
884 	int32 offset;
885 	uint32 tableMask = 0;
886 
887 	switch (modifiers & 0xcf) {
888 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; tableMask = B_SHIFT_TABLE; break;
889 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; tableMask = B_CAPS_TABLE; break;
890 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; tableMask = B_CAPS_SHIFT_TABLE; break;
891 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; tableMask = B_OPTION_TABLE; break;
892 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; tableMask = B_OPTION_SHIFT_TABLE; break;
893 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; tableMask = B_OPTION_CAPS_TABLE; break;
894 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; tableMask = B_OPTION_CAPS_SHIFT_TABLE; break;
895 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; tableMask = B_CONTROL_TABLE; break;
896 		default: offset = fKeys.normal_map[keyCode]; tableMask = B_NORMAL_TABLE; break;
897 	}
898 
899 	if (offset <= 0)
900 		return 0;
901 	uint32 numBytes = fChars[offset];
902 
903 	if (!numBytes)
904 		return 0;
905 
906 	char chars[4];
907 	strncpy(chars, &(fChars[offset+1]), numBytes );
908 	chars[numBytes] = 0;
909 
910 	int32 deadOffsets[] = {
911 		fKeys.acute_dead_key[1],
912 		fKeys.grave_dead_key[1],
913 		fKeys.circumflex_dead_key[1],
914 		fKeys.dieresis_dead_key[1],
915 		fKeys.tilde_dead_key[1]
916 	};
917 
918 	uint32 deadTables[] = {
919 		fKeys.acute_tables,
920 		fKeys.grave_tables,
921 		fKeys.circumflex_tables,
922 		fKeys.dieresis_tables,
923 		fKeys.tilde_tables
924 	};
925 
926 	for (int32 i = 0; i < 5; i++) {
927 		if ((deadTables[i] & tableMask) == 0)
928 			continue;
929 
930 		if (offset == deadOffsets[i])
931 			return i+1;
932 
933 		uint32 deadNumBytes = fChars[deadOffsets[i]];
934 
935 		if (!deadNumBytes)
936 			continue;
937 
938 		if (strncmp(chars, &(fChars[deadOffsets[i]+1]), deadNumBytes ) == 0)
939 			return i+1;
940 	}
941 	return 0;
942 }
943 
944 
945 //! Tell if a key is a dead second key, needed for draw a dead second key
946 bool
947 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey)
948 {
949 	if (!activeDeadKey)
950 		return false;
951 
952 	int32 offset;
953 
954 	switch (modifiers & 0xcf) {
955 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break;
956 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break;
957 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break;
958 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break;
959 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break;
960 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break;
961 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break;
962 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break;
963 		default: offset = fKeys.normal_map[keyCode]; break;
964 	}
965 
966 	uint32 numBytes = fChars[offset];
967 
968 	if (!numBytes)
969 		return false;
970 
971 	int32* deadOffsets[] = {
972 		fKeys.acute_dead_key,
973 		fKeys.grave_dead_key,
974 		fKeys.circumflex_dead_key,
975 		fKeys.dieresis_dead_key,
976 		fKeys.tilde_dead_key
977 	};
978 
979 	int32 *deadOffset = deadOffsets[activeDeadKey - 1];
980 
981 	for (int32 i = 0; i < 32; i++) {
982 		if (offset == deadOffset[i])
983 			return true;
984 
985 		uint32 deadNumBytes = fChars[deadOffset[i]];
986 
987 		if (!deadNumBytes)
988 			continue;
989 
990 		if (strncmp(&(fChars[offset+1]), &(fChars[deadOffset[i]+1]), deadNumBytes) == 0)
991 			return true;
992 
993 		i++;
994 	}
995 	return false;
996 }
997 
998 
999 //! Get the char for a key given modifiers and active dead key
1000 void
1001 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey,
1002 	char** chars, int32* numBytes)
1003 {
1004 	int32 offset;
1005 
1006 	*numBytes = 0;
1007 	*chars = NULL;
1008 
1009 	// here we take NUMLOCK into account
1010 	if (modifiers & B_NUM_LOCK) {
1011 		switch (keyCode) {
1012 			case 0x37:
1013 			case 0x38:
1014 			case 0x39:
1015 			case 0x48:
1016 			case 0x49:
1017 			case 0x4a:
1018 			case 0x58:
1019 			case 0x59:
1020 			case 0x5a:
1021 			case 0x64:
1022 			case 0x65:
1023 				modifiers ^= B_SHIFT_KEY;
1024 		}
1025 	}
1026 
1027 	// here we choose the right map given the modifiers
1028 	switch (modifiers & 0xcf) {
1029 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break;
1030 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break;
1031 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break;
1032 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break;
1033 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break;
1034 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break;
1035 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break;
1036 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break;
1037 		default: offset = fKeys.normal_map[keyCode]; break;
1038 	}
1039 
1040 	// here we get the char size
1041 	*numBytes = fChars[offset];
1042 
1043 	if (!*numBytes)
1044 		return;
1045 
1046 	// here we take an potential active dead key
1047 	int32 *dead_key;
1048 	switch (activeDeadKey) {
1049 		case 1: dead_key = fKeys.acute_dead_key; break;
1050 		case 2: dead_key = fKeys.grave_dead_key; break;
1051 		case 3: dead_key = fKeys.circumflex_dead_key; break;
1052 		case 4: dead_key = fKeys.dieresis_dead_key; break;
1053 		case 5: dead_key = fKeys.tilde_dead_key; break;
1054 
1055 		default:
1056 			// if not dead, we copy and return the char
1057 			char *str = *chars = new char[*numBytes + 1];
1058 			strncpy(str, &(fChars[offset+1]), *numBytes );
1059 			str[*numBytes] = 0;
1060 			return;
1061 	}
1062 
1063 	// if dead key, we search for our current offset char in the dead key offset table
1064 	// string comparison is needed
1065 	for (int32 i = 0; i < 32; i++) {
1066 		if (strncmp(&(fChars[offset+1]), &(fChars[dead_key[i]+1]), *numBytes ) == 0) {
1067 			*numBytes = fChars[dead_key[i+1]];
1068 
1069 			switch (*numBytes) {
1070 				case 0:
1071 					// Not mapped
1072 					*chars = NULL;
1073 					break;
1074 
1075 				default:
1076 					// 1-, 2-, 3-, or 4-byte UTF-8 character
1077 					char *str = *chars = new char[*numBytes + 1];
1078 					strncpy(str, &fChars[dead_key[i+1]+1], *numBytes );
1079 					str[*numBytes] = 0;
1080 					break;
1081 			}
1082 			return;
1083 		}
1084 		i++;
1085 	}
1086 
1087 	// if not found we return the current char mapped
1088 	*chars = new char[*numBytes + 1];
1089 	strncpy(*chars, &(fChars[offset+1]), *numBytes );
1090 	(*chars)[*numBytes] = 0;
1091 }
1092 
1093 
1094 status_t _restore_key_map_();
1095 
1096 
1097 void
1098 Keymap::RestoreSystemDefault()
1099 {
1100 #ifdef __BEOS__
1101 	// work-around to get rid of this stupid find_directory_r() on Zeta
1102 #	ifdef find_directory
1103 #		undef find_directory
1104 #	endif
1105 	BPath path;
1106 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
1107 		return;
1108 
1109 	path.Append("Key_map");
1110 
1111 	BEntry ref(path.Path());
1112 	ref.Remove();
1113 
1114 	_restore_key_map_();
1115 #else	// ! __BEOS__
1116 	fprintf(stderr, "Unsupported operation on this platform!\n");
1117 	exit(1);
1118 #endif	// ! __BEOS__
1119 }
1120 
1121 
1122 void
1123 Keymap::SaveAsCurrent()
1124 {
1125 #ifdef __BEOS__
1126 	BPath path;
1127 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
1128 		return;
1129 
1130 	path.Append("Key_map");
1131 
1132 	entry_ref ref;
1133 	get_ref_for_path(path.Path(), &ref);
1134 
1135 	status_t err;
1136 	if ((err = Save(ref)) != B_OK) {
1137 		printf("error when saving : %s", strerror(err));
1138 		return;
1139 	}
1140 	Use();
1141 
1142 #else	// ! __BEOS__
1143 	fprintf(stderr, "Unsupported operation on this platform!\n");
1144 	exit(1);
1145 #endif	// ! __BEOS__
1146 }
1147 
1148 
1149 //! We make our input server use the map in /boot/home/config/settings/Keymap
1150 status_t
1151 Keymap::Use()
1152 {
1153 #ifdef __BEOS__
1154 	return _restore_key_map_();
1155 
1156 #else	// ! __BEOS__
1157 	fprintf(stderr, "Unsupported operation on this platform!\n");
1158 	exit(1);
1159 #endif	// ! __BEOS__
1160 }
1161