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