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