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