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