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
dump_map(FILE * file,const char * name,int32 * map)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
dump_keys(FILE * file,const char * name,int32 * keys)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
Keymap()200 Keymap::Keymap()
201 {
202 }
203
204
~Keymap()205 Keymap::~Keymap()
206 {
207 }
208
209
210 status_t
LoadSource(const char * name)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
LoadSource(FILE * file)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), ´Buf);
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 ´tabBuf);
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, ®s) >= 0) {
365 sscanf(buffer + regs.start[1], "%" B_SCNu32, &fKeys.version);
366 } else if (re_search(&capslockBuf, buffer, length, 0, length, ®s)
367 >= 0) {
368 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.caps_key);
369 } else if (re_search(&scrolllockBuf, buffer, length, 0, length, ®s)
370 >= 0) {
371 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.scroll_key);
372 } else if (re_search(&numlockBuf, buffer, length, 0, length, ®s)
373 >= 0) {
374 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.num_key);
375 } else if (re_search(&lshiftBuf, buffer, length, 0, length, ®s)
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, ®s)
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, ®s)
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, ®s)
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, ®s)
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, ®s)
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, ®s)
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, ®s)
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, ®s)
408 >= 0) {
409 sscanf(buffer + regs.start[1], "0x%" B_SCNx32, &fKeys.menu_key);
410 } else if (re_search(&locksettingsBuf, buffer, length, 0, length, ®s)
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, ®s)
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(´Buf, buffer, length, 0, length, ®s)
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, ®s)
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, ®s)
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, ®s)
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, ®s) >= 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(´tabBuf, buffer, length, 0, length, ®s)
465 >= 0) {
466 _ComputeTables(buffer, regs, fKeys.acute_tables);
467 } else if (re_search(&gravetabBuf, buffer, length, 0, length, ®s)
468 >= 0) {
469 _ComputeTables(buffer, regs, fKeys.grave_tables);
470 } else if (re_search(&circumflextabBuf, buffer, length, 0, length, ®s)
471 >= 0) {
472 _ComputeTables(buffer, regs, fKeys.circumflex_tables);
473 } else if (re_search(&diaeresistabBuf, buffer, length, 0, length, ®s)
474 >= 0) {
475 _ComputeTables(buffer, regs, fKeys.dieresis_tables);
476 } else if (re_search(&tildetabBuf, buffer, length, 0, length, ®s)
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
SaveAsCurrent()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
Save(const char * name)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
SaveAsSource(const char * name)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
SaveAsSource(FILE * file)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
SaveAsCppHeader(const char * fileName,const char * mapName)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
Use()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
RestoreSystemDefault()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
GetKey(const char * chars,int32 offset,char * buffer,size_t bufferSize)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
_SaveSourceText(FILE * file,text_run_array ** _textRuns)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