xref: /haiku/src/bin/keymap/Keymap.cpp (revision d34daac82a58a31e54a076f121c2bbb0cea60447)
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 	return B_OK;
579 }
580 
581 
582 status_t
583 Keymap::SaveAsSource(FILE* file)
584 {
585 	_SaveSourceText(file);
586 	return B_OK;
587 }
588 
589 
590 /*!	Save a keymap as C source file - this is used to get the default keymap
591 	into the input_server, for example.
592 	\a mapName is usually the path of the input keymap, and is used as the
593 	name of the keymap (the path will be removed, as well as its suffix).
594 */
595 status_t
596 Keymap::SaveAsCppHeader(const char* fileName, const char* mapName)
597 {
598 	BString name = mapName;
599 
600 	// cut off path
601 	int32 index = name.FindLast('/');
602 	if (index > 0)
603 		name.Remove(0, index + 1);
604 
605 	// prune ".keymap"
606 	index = name.FindLast('.');
607 	if (index > 0)
608 		name.Truncate(index);
609 
610 	FILE* file = fopen(fileName, "w");
611 	if (file == NULL)
612 		return errno;
613 
614 	fprintf(file, "/*\n"
615 		" * Haiku Keymap\n"
616 		" * This file is generated automatically. Don't edit!\n"
617 		" */\n\n");
618 	fprintf(file, "#include <InterfaceDefs.h>\n\n");
619 	fprintf(file, "const char *kSystemKeymapName = \"%s\";\n\n", name.String());
620 	fprintf(file, "const key_map kSystemKeymap = {\n");
621 	fprintf(file, "\tversion:%" B_PRIu32 ",\n", fKeys.version);
622 	fprintf(file, "\tcaps_key:0x%" B_PRIx32 ",\n", fKeys.caps_key);
623 	fprintf(file, "\tscroll_key:0x%" B_PRIx32 ",\n", fKeys.scroll_key);
624 	fprintf(file, "\tnum_key:0x%" B_PRIx32 ",\n", fKeys.num_key);
625 	fprintf(file, "\tleft_shift_key:0x%" B_PRIx32 ",\n", fKeys.left_shift_key);
626 	fprintf(file, "\tright_shift_key:0x%" B_PRIx32 ",\n",
627 		fKeys.right_shift_key);
628 	fprintf(file, "\tleft_command_key:0x%" B_PRIx32 ",\n",
629 		fKeys.left_command_key);
630 	fprintf(file, "\tright_command_key:0x%" B_PRIx32 ",\n",
631 		fKeys.right_command_key);
632 	fprintf(file, "\tleft_control_key:0x%" B_PRIx32 ",\n",
633 		fKeys.left_control_key);
634 	fprintf(file, "\tright_control_key:0x%" B_PRIx32 ",\n",
635 		fKeys.right_control_key);
636 	fprintf(file, "\tleft_option_key:0x%" B_PRIx32 ",\n",
637 		fKeys.left_option_key);
638 	fprintf(file, "\tright_option_key:0x%" B_PRIx32 ",\n",
639 		fKeys.right_option_key);
640 	fprintf(file, "\tmenu_key:0x%" B_PRIx32 ",\n", fKeys.menu_key);
641 	fprintf(file, "\tlock_settings:0x%" B_PRIx32 ",\n", fKeys.lock_settings);
642 
643 	dump_map(file, "control_map", fKeys.control_map);
644 	dump_map(file, "option_caps_shift_map", fKeys.option_caps_shift_map);
645 	dump_map(file, "option_caps_map", fKeys.option_caps_map);
646 	dump_map(file, "option_shift_map", fKeys.option_shift_map);
647 	dump_map(file, "option_map", fKeys.option_map);
648 	dump_map(file, "caps_shift_map", fKeys.caps_shift_map);
649 	dump_map(file, "caps_map", fKeys.caps_map);
650 	dump_map(file, "shift_map", fKeys.shift_map);
651 	dump_map(file, "normal_map", fKeys.normal_map);
652 
653 	dump_keys(file, "acute_dead_key", fKeys.acute_dead_key);
654 	dump_keys(file, "grave_dead_key", fKeys.grave_dead_key);
655 
656 	dump_keys(file, "circumflex_dead_key", fKeys.circumflex_dead_key);
657 	dump_keys(file, "dieresis_dead_key", fKeys.dieresis_dead_key);
658 	dump_keys(file, "tilde_dead_key", fKeys.tilde_dead_key);
659 
660 	fprintf(file, "\tacute_tables:0x%" B_PRIx32 ",\n", fKeys.acute_tables);
661 	fprintf(file, "\tgrave_tables:0x%" B_PRIx32 ",\n", fKeys.grave_tables);
662 	fprintf(file, "\tcircumflex_tables:0x%" B_PRIx32 ",\n",
663 		fKeys.circumflex_tables);
664 	fprintf(file, "\tdieresis_tables:0x%" B_PRIx32 ",\n",
665 		fKeys.dieresis_tables);
666 	fprintf(file, "\ttilde_tables:0x%" B_PRIx32 ",\n", fKeys.tilde_tables);
667 
668 	fprintf(file, "};\n\n");
669 
670 	fprintf(file, "const char kSystemKeyChars[] = {\n");
671 	for (uint32 i = 0; i < fCharsSize; i++) {
672 		if (i % 10 == 0) {
673 			if (i > 0)
674 				fprintf(file, "\n");
675 			fprintf(file, "\t");
676 		} else
677 			fprintf(file, " ");
678 
679 		fprintf(file, "0x%02x,", (uint8)fChars[i]);
680 	}
681 	fprintf(file, "\n};\n\n");
682 
683 	fprintf(file, "const uint32 kSystemKeyCharsSize = %" B_PRIu32 ";\n",
684 		fCharsSize);
685 	fclose(file);
686 
687 	return B_OK;
688 }
689 
690 
691 //! We make our input server use the map in /boot/home/config/settings/Keymap
692 status_t
693 Keymap::Use()
694 {
695 #if (defined(__BEOS__) || defined(__HAIKU__))
696 	return _restore_key_map_();
697 
698 #else	// ! __BEOS__
699 	fprintf(stderr, "Unsupported operation on this platform!\n");
700 	exit(1);
701 #endif	// ! __BEOS__
702 }
703 
704 
705 void
706 Keymap::RestoreSystemDefault()
707 {
708 #if (defined(__BEOS__) || defined(__HAIKU__))
709 	// work-around to get rid of this stupid find_directory_r() on Zeta
710 #	ifdef find_directory
711 #		undef find_directory
712 #	endif
713 	BPath path;
714 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
715 		return;
716 
717 	path.Append("Key_map");
718 
719 	BEntry entry(path.Path());
720 	entry.Remove();
721 
722 	_restore_key_map_();
723 #else	// ! __BEOS__
724 	fprintf(stderr, "Unsupported operation on this platform!\n");
725 	exit(1);
726 #endif	// ! __BEOS__
727 }
728 
729 
730 /*static*/ bool
731 Keymap::GetKey(const char* chars, int32 offset, char* buffer, size_t bufferSize)
732 {
733 	uint8 size = (uint8)chars[offset++];
734 	char string[1024];
735 
736 	switch (size) {
737 		case 0:
738 			// Not mapped
739 			strlcpy(buffer, "''", bufferSize);
740 			return false;
741 
742 		case 1:
743 			// 1-byte UTF-8/ASCII character
744 			if ((uint8)chars[offset] < 0x20 || (uint8)chars[offset] > 0x7e)
745 				sprintf(string, "0x%02x", (uint8)chars[offset]);
746 			else {
747 				sprintf(string, "'%s%c'",
748 					(chars[offset] == '\\' || chars[offset] == '\'') ? "\\" : "",
749 					chars[offset]);
750 			}
751 			break;
752 
753 		default:
754 			// multi-byte UTF-8 character
755 			sprintf(string, "0x");
756 			for (int i = 0; i < size; i++) {
757 				sprintf(string + 2 * (i + 1), "%02x", (uint8)chars[offset + i]);
758 			}
759 			break;
760 	}
761 
762 	strlcpy(buffer, string, bufferSize);
763 	return true;
764 }
765 
766 
767 #if (defined(__BEOS__) || defined(__HAIKU__))
768 void
769 Keymap::_SaveSourceText(FILE* file, text_run_array** _textRuns)
770 {
771 	text_run_array* runs = NULL;
772 	if (_textRuns != NULL) {
773 		runs = BTextView::AllocRunArray(8);
774 		*_textRuns = runs;
775 	}
776 #else
777 void
778 Keymap::_SaveSourceText(FILE* file)
779 {
780 #endif
781 
782 	static const rgb_color kCommentColor = (rgb_color){200, 92, 92, 255};
783 	static const rgb_color kTextColor = (rgb_color){0, 0, 0, 255};
784 
785 #if (defined(__BEOS__) || defined(__HAIKU__))
786 	BFont font = *be_fixed_font;
787 
788 	if (runs != NULL) {
789 		runs->runs[0].offset = 0;
790 		runs->runs[0].font = font;
791 		runs->runs[0].color = kCommentColor;
792 	}
793 #endif
794 
795 	int bytes = fprintf(file, "#!/bin/keymap -s\n"
796 		"#\n"
797 		"#\tRaw key numbering for 101 keyboard...\n");
798 
799 #if (defined(__BEOS__) || defined(__HAIKU__))
800 	if (runs != NULL) {
801 		runs->runs[1].offset = bytes;
802 		runs->runs[1].font = font;
803 		runs->runs[1].font.SetSize(9);
804 		runs->runs[1].color = kCommentColor;
805 	}
806 #endif
807 
808 	bytes += fprintf(file, "#                                                                                        [sys]       [brk]\n"
809 		"#                                                                                         0x7e        0x7f\n"
810 		"# [esc]       [ f1] [ f2] [ f3] [ f4] [ f5] [ f6] [ f7] [ f8] [ f9] [f10] [f11] [f12]    [prn] [scr] [pau]\n"
811 		"#  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"
812 		"#\n"
813 		"# [ ` ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 0 ] [ - ] [ = ] [bck]    [ins] [hme] [pup]    [num] [ / ] [ * ] [ - ]\n"
814 		"#  0x11  0x12  0x13  0x14  0x15  0x16  0x17  0x18  0x19  0x1a  0x1b  0x1c  0x1d  0x1e     0x1f  0x20  0x21     0x22  0x23  0x24  0x25\n"
815 		"#\n"
816 		"# [tab] [ q ] [ w ] [ e ] [ r ] [ t ] [ y ] [ u ] [ i ] [ o ] [ p ] [ [ ] [ ] ] [ \\ ]    [del] [end] [pdn]    [ 7 ] [ 8 ] [ 9 ] [ + ]\n"
817 		"#  0x26  0x27  0x28  0x29  0x2a  0x2b  0x2c  0x2d  0x2e  0x2f  0x30  0x31  0x32  0x33     0x34  0x35  0x36     0x37  0x38  0x39  0x3a\n"
818 		"#\n"
819 		"# [cap] [ a ] [ s ] [ d ] [ f ] [ g ] [ h ] [ j ] [ k ] [ l ] [ ; ] [ ' ] [  enter  ]                         [ 4 ] [ 5 ] [ 6 ]\n"
820 		"#  0x3b  0x3c  0x3d  0x3e  0x3f  0x40  0x41  0x42  0x43  0x44  0x45  0x46     0x47                             0x48  0x49  0x4a\n"
821 		"#\n"
822 		"# [shift]     [ z ] [ x ] [ c ] [ v ] [ b ] [ n ] [ m ] [ , ] [ . ] [ / ]     [shift]          [ up]          [ 1 ] [ 2 ] [ 3 ] [ent]\n"
823 		"#   0x4b       0x4c  0x4d  0x4e  0x4f  0x50  0x51  0x52  0x53  0x54  0x55       0x56            0x57           0x58  0x59  0x5a  0x5b\n"
824 		"#\n"
825 		"# [ctr]             [cmd]             [  space  ]             [cmd]             [ctr]    [lft] [dwn] [rgt]    [ 0 ] [ . ]\n"
826 		"#  0x5c              0x5d                 0x5e                 0x5f              0x60     0x61  0x62  0x63     0x64  0x65\n");
827 
828 #if (defined(__BEOS__) || defined(__HAIKU__))
829 	if (runs != NULL) {
830 		runs->runs[2].offset = bytes;
831 		runs->runs[2].font = font;
832 		runs->runs[2].color = kCommentColor;
833 	}
834 #endif
835 
836 	bytes += fprintf(file, "#\n"
837 		"#\tNOTE: On a Microsoft Natural Keyboard:\n"
838 		"#\t\t\tleft option  = 0x66\n"
839 		"#\t\t\tright option = 0x67\n"
840 		"#\t\t\tmenu key     = 0x68\n"
841 		"#\tNOTE: On an Apple Extended Keyboard:\n"
842 		"#\t\t\tleft option  = 0x66\n"
843 		"#\t\t\tright option = 0x67\n"
844 		"#\t\t\tkeypad '='   = 0x6a\n"
845 		"#\t\t\tpower key    = 0x6b\n");
846 
847 #if (defined(__BEOS__) || defined(__HAIKU__))
848 	if (runs != NULL) {
849 		runs->runs[3].offset = bytes;
850 		runs->runs[3].font = *be_fixed_font;
851 		runs->runs[3].color = kTextColor;
852 	}
853 #endif
854 
855 	bytes += fprintf(file, "Version = %" B_PRIu32 "\n"
856 		"CapsLock = 0x%02" B_PRIx32 "\n"
857 		"ScrollLock = 0x%02" B_PRIx32 "\n"
858 		"NumLock = 0x%02" B_PRIx32 "\n"
859 		"LShift = 0x%02" B_PRIx32 "\n"
860 		"RShift = 0x%02" B_PRIx32 "\n"
861 		"LCommand = 0x%02" B_PRIx32 "\n"
862 		"RCommand = 0x%02" B_PRIx32 "\n"
863 		"LControl = 0x%02" B_PRIx32 "\n"
864 		"RControl = 0x%02" B_PRIx32 "\n"
865 		"LOption = 0x%02" B_PRIx32 "\n"
866 		"ROption = 0x%02" B_PRIx32 "\n"
867 		"Menu = 0x%02" B_PRIx32 "\n",
868 		fKeys.version, fKeys.caps_key, fKeys.scroll_key, fKeys.num_key,
869 		fKeys.left_shift_key, fKeys.right_shift_key, fKeys.left_command_key,
870 		fKeys.right_command_key, fKeys.left_control_key, fKeys.right_control_key,
871 		fKeys.left_option_key, fKeys.right_option_key, fKeys.menu_key);
872 
873 #if (defined(__BEOS__) || defined(__HAIKU__))
874 	if (runs != NULL) {
875 		runs->runs[4].offset = bytes;
876 		runs->runs[4].font = *be_fixed_font;
877 		runs->runs[4].color = kCommentColor;
878 	}
879 #endif
880 
881 	bytes += fprintf(file, "#\n"
882 		"# Lock settings\n"
883 		"# To set NumLock, do the following:\n"
884 		"#   LockSettings = NumLock\n"
885 		"#\n"
886 		"# To set everything, do the following:\n"
887 		"#   LockSettings = CapsLock NumLock ScrollLock\n"
888 		"#\n");
889 
890 #if (defined(__BEOS__) || defined(__HAIKU__))
891 	if (runs != NULL) {
892 		runs->runs[5].offset = bytes;
893 		runs->runs[5].font = *be_fixed_font;
894 		runs->runs[5].color = kTextColor;
895 	}
896 #endif
897 
898 	bytes += fprintf(file, "LockSettings = ");
899 	if ((fKeys.lock_settings & B_CAPS_LOCK) != 0)
900 		bytes += fprintf(file, "CapsLock ");
901 	if ((fKeys.lock_settings & B_NUM_LOCK) != 0)
902 		bytes += fprintf(file, "NumLock ");
903 	if ((fKeys.lock_settings & B_SCROLL_LOCK) != 0)
904 		bytes += fprintf(file, "ScrollLock ");
905 	bytes += fprintf(file, "\n");
906 
907 #if (defined(__BEOS__) || defined(__HAIKU__))
908 	if (runs != NULL) {
909 		runs->runs[6].offset = bytes;
910 		runs->runs[6].font = *be_fixed_font;
911 		runs->runs[6].color = kCommentColor;
912 	}
913 #endif
914 
915 	bytes += fprintf(file, "# Legend:\n"
916 		"#   n = Normal\n"
917 		"#   s = Shift\n"
918 		"#   c = Control\n"
919 		"#   C = CapsLock\n"
920 		"#   o = Option\n"
921 		"# Key      n        s        c        o        os       C        Cs       Co       Cos     \n");
922 
923 #if (defined(__BEOS__) || defined(__HAIKU__))
924 	if (runs != NULL) {
925 		runs->runs[7].offset = bytes;
926 		runs->runs[7].font = *be_fixed_font;
927 		runs->runs[7].color = kTextColor;
928 	}
929 #endif
930 
931 	for (int i = 0; i < 128; i++) {
932 		char normalKey[32];
933 		char shiftKey[32];
934 		char controlKey[32];
935 		char optionKey[32];
936 		char optionShiftKey[32];
937 		char capsKey[32];
938 		char capsShiftKey[32];
939 		char optionCapsKey[32];
940 		char optionCapsShiftKey[32];
941 
942 		GetKey(fChars, fKeys.normal_map[i], normalKey, 32);
943 		GetKey(fChars, fKeys.shift_map[i], shiftKey, 32);
944 		GetKey(fChars, fKeys.control_map[i], controlKey, 32);
945 		GetKey(fChars, fKeys.option_map[i], optionKey, 32);
946 		GetKey(fChars, fKeys.option_shift_map[i], optionShiftKey, 32);
947 		GetKey(fChars, fKeys.caps_map[i], capsKey, 32);
948 		GetKey(fChars, fKeys.caps_shift_map[i], capsShiftKey, 32);
949 		GetKey(fChars, fKeys.option_caps_map[i], optionCapsKey, 32);
950 		GetKey(fChars, fKeys.option_caps_shift_map[i], optionCapsShiftKey, 32);
951 
952 		fprintf(file, "Key 0x%02x = %-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s%-9s\n", i,
953 			normalKey, shiftKey, controlKey, optionKey, optionShiftKey, capsKey,
954 			capsShiftKey, optionCapsKey, optionCapsShiftKey);
955 	}
956 
957 	int32* deadOffsets[] = {
958 		fKeys.acute_dead_key,
959 		fKeys.grave_dead_key,
960 		fKeys.circumflex_dead_key,
961 		fKeys.dieresis_dead_key,
962 		fKeys.tilde_dead_key
963 	};
964 
965 	char labels[][12] = {
966 		"Acute",
967 		"Grave",
968 		"Circumflex",
969 		"Diaeresis",
970 		"Tilde"
971 	};
972 
973 	uint32 deadTables[] = {
974 		fKeys.acute_tables,
975 		fKeys.grave_tables,
976 		fKeys.circumflex_tables,
977 		fKeys.dieresis_tables,
978 		fKeys.tilde_tables
979 	};
980 
981 	for (int i = 0; i < 5; i++) {
982 		for (int deadIndex = 0; deadIndex < 32; deadIndex++) {
983 			char deadKey[32];
984 			char secondKey[32];
985 			if (!GetKey(fChars, deadOffsets[i][deadIndex++], deadKey, 32))
986 				break;
987 
988 			GetKey(fChars, deadOffsets[i][deadIndex], secondKey, 32);
989 			fprintf(file, "%s %-9s = %-9s\n", labels[i], deadKey, secondKey);
990 		}
991 
992 		fprintf(file, "%sTab = ", labels[i]);
993 
994 		if (deadTables[i] & B_NORMAL_TABLE)
995 			fprintf(file, "Normal ");
996 		if (deadTables[i] & B_SHIFT_TABLE)
997 			fprintf(file, "Shift ");
998 		if (deadTables[i] & B_CONTROL_TABLE)
999 			fprintf(file, "Control ");
1000 		if (deadTables[i] & B_OPTION_TABLE)
1001 			fprintf(file, "Option ");
1002 		if (deadTables[i] & B_OPTION_SHIFT_TABLE)
1003 			fprintf(file, "Option-Shift ");
1004 		if (deadTables[i] & B_CAPS_TABLE)
1005 			fprintf(file, "CapsLock ");
1006 		if (deadTables[i] & B_CAPS_SHIFT_TABLE)
1007 			fprintf(file, "CapsLock-Shift ");
1008 		if (deadTables[i] & B_OPTION_CAPS_TABLE)
1009 			fprintf(file, "CapsLock-Option ");
1010 		if (deadTables[i] & B_OPTION_CAPS_SHIFT_TABLE)
1011 			fprintf(file, "CapsLock-Option-Shift ");
1012 		fprintf(file, "\n");
1013 	}
1014 }
1015 
1016 
1017 void
1018 Keymap::_ComputeChars(const char* buffer, struct re_registers& regs, int i,
1019 	int& offset)
1020 {
1021 	char* current = &fChars[offset + 1];
1022 	char hexChars[12];
1023 	uint32 length = 0;
1024 
1025 	if (strncmp(buffer + regs.start[i], "''", regs.end[i] - regs.start[i]) == 0)
1026 		length = 0;
1027 	else if (sscanf(buffer + regs.start[i], "'%s'", current) > 0) {
1028 		if (current[0] == '\\')
1029 			current[0] = current[1];
1030 		else if (current[0] == '\'')
1031 			current[0] = ' ';
1032 		length = 1;
1033 	} else if (sscanf(buffer + regs.start[i], "0x%s", hexChars) > 0) {
1034 		length = strlen(hexChars) / 2;
1035 		for (uint32 j = 0; j < length; j++)
1036 			sscanf(hexChars + 2*j, "%02hhx", current + j);
1037 	}
1038 
1039 	fChars[offset] = length;
1040 	offset += length + 1;
1041 }
1042 
1043 
1044 void
1045 Keymap::_ComputeTables(const char* buffer, struct re_registers& regs,
1046 	uint32& table)
1047 {
1048 	for (int32 i = 1; i <= 9; i++) {
1049 		int32 length = regs.end[i] - regs.start[i];
1050 		if (length <= 0)
1051 			break;
1052 
1053 		const char* start = buffer + regs.start[i];
1054 
1055 		if (strncmp(start, "Normal", length) == 0)
1056 			table |= B_NORMAL_TABLE;
1057 		else if (strncmp(start, "Shift", length) == 0)
1058 			table |= B_SHIFT_TABLE;
1059 		else if (strncmp(start, "Control", length) == 0)
1060 			table |= B_CONTROL_TABLE;
1061 		else if (strncmp(start, "Option", length) == 0)
1062 			table |= B_OPTION_TABLE;
1063 		else if (strncmp(start, "Option-Shift", length) == 0)
1064 			table |= B_OPTION_SHIFT_TABLE;
1065 		else if (strncmp(start, "CapsLock", length) == 0)
1066 			table |= B_CAPS_TABLE;
1067 		else if (strncmp(start, "CapsLock-Shift", length) == 0)
1068 			table |= B_CAPS_SHIFT_TABLE;
1069 		else if (strncmp(start, "CapsLock-Option", length) == 0)
1070 			table |= B_OPTION_CAPS_TABLE;
1071 		else if (strncmp(start, "CapsLock-Option-Shift", length) == 0)
1072 			table |= B_OPTION_CAPS_SHIFT_TABLE;
1073 	}
1074 }
1075