2 * Copyright 2004-2012, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
7 * Axel Dörfler, axeld@pinc-software.de.
8 * John Scipione, jscipione@gmail.com.
20 #include <ByteOrder.h>
24 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
25 # include "SystemKeymap.h"
26 // generated by the build system
30 // Private only at this point, as we might want to improve the dead key
31 // implementation in the future
41 static const uint32 kModifierKeys
= B_SHIFT_KEY
| B_CAPS_LOCK
| B_CONTROL_KEY
42 | B_OPTION_KEY
| B_COMMAND_KEY
| B_MENU_KEY
;
60 /*! Load a map from a file.
61 File format in big endian:
63 uint32 size of following charset
64 charset (offsets go into this with size of character followed by
68 BKeymap::SetTo(const char* path
)
71 status_t status
= file
.SetTo(path
, B_READ_ONLY
);
80 BKeymap::SetTo(BDataIO
& stream
)
82 if (stream
.Read(&fKeys
, sizeof(fKeys
)) < 1)
85 // convert from big-endian
86 for (uint32 i
= 0; i
< sizeof(fKeys
) / 4; i
++) {
87 ((uint32
*)&fKeys
)[i
] = B_BENDIAN_TO_HOST_INT32(((uint32
*)&fKeys
)[i
]);
90 if (fKeys
.version
!= 3)
93 if (stream
.Read(&fCharsSize
, sizeof(uint32
)) < 1)
96 fCharsSize
= B_BENDIAN_TO_HOST_INT32(fCharsSize
);
97 if (fCharsSize
> 16 * 1024) {
103 fChars
= new char[fCharsSize
];
105 if (stream
.Read(fChars
, fCharsSize
) != (ssize_t
)fCharsSize
) {
115 BKeymap::SetToCurrent()
117 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
118 key_map
* keys
= NULL
;
119 get_key_map(&keys
, &fChars
);
123 memcpy(&fKeys
, keys
, sizeof(fKeys
));
126 fCharsSize
= sizeof(fChars
);
130 fprintf(stderr
, "Unsupported operation on this platform!\n");
137 BKeymap::SetToDefault()
139 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
140 fKeys
= kSystemKeymap
;
141 fCharsSize
= kSystemKeyCharsSize
;
143 fChars
= new (std::nothrow
) char[fCharsSize
];
144 if (fChars
== NULL
) {
149 memcpy(fChars
, kSystemKeyChars
, fCharsSize
);
152 fprintf(stderr
, "Unsupported operation on this platform!\n");
165 memset(&fKeys
, 0, sizeof(fKeys
));
169 /*! We need to know if a key is a modifier key to choose
170 a valid key when several are pressed together
173 BKeymap::IsModifierKey(uint32 keyCode
) const
175 return keyCode
== fKeys
.caps_key
176 || keyCode
== fKeys
.num_key
177 || keyCode
== fKeys
.scroll_key
178 || keyCode
== fKeys
.left_shift_key
179 || keyCode
== fKeys
.right_shift_key
180 || keyCode
== fKeys
.left_command_key
181 || keyCode
== fKeys
.right_command_key
182 || keyCode
== fKeys
.left_control_key
183 || keyCode
== fKeys
.right_control_key
184 || keyCode
== fKeys
.left_option_key
185 || keyCode
== fKeys
.right_option_key
186 || keyCode
== fKeys
.menu_key
;
190 //! We need to know a modifier for a key
192 BKeymap::Modifier(uint32 keyCode
) const
194 if (keyCode
== fKeys
.caps_key
)
196 if (keyCode
== fKeys
.num_key
)
198 if (keyCode
== fKeys
.scroll_key
)
199 return B_SCROLL_LOCK
;
200 if (keyCode
== fKeys
.left_shift_key
)
201 return B_LEFT_SHIFT_KEY
| B_SHIFT_KEY
;
202 if (keyCode
== fKeys
.right_shift_key
)
203 return B_RIGHT_SHIFT_KEY
| B_SHIFT_KEY
;
204 if (keyCode
== fKeys
.left_command_key
)
205 return B_LEFT_COMMAND_KEY
| B_COMMAND_KEY
;
206 if (keyCode
== fKeys
.right_command_key
)
207 return B_RIGHT_COMMAND_KEY
| B_COMMAND_KEY
;
208 if (keyCode
== fKeys
.left_control_key
)
209 return B_LEFT_CONTROL_KEY
| B_CONTROL_KEY
;
210 if (keyCode
== fKeys
.right_control_key
)
211 return B_RIGHT_CONTROL_KEY
| B_CONTROL_KEY
;
212 if (keyCode
== fKeys
.left_option_key
)
213 return B_LEFT_OPTION_KEY
| B_OPTION_KEY
;
214 if (keyCode
== fKeys
.right_option_key
)
215 return B_RIGHT_OPTION_KEY
| B_OPTION_KEY
;
216 if (keyCode
== fKeys
.menu_key
)
224 BKeymap::KeyForModifier(uint32 modifier
) const
226 if (modifier
== B_CAPS_LOCK
)
227 return fKeys
.caps_key
;
228 if (modifier
== B_NUM_LOCK
)
229 return fKeys
.num_key
;
230 if (modifier
== B_SCROLL_LOCK
)
231 return fKeys
.scroll_key
;
232 if (modifier
== B_LEFT_SHIFT_KEY
|| modifier
== B_SHIFT_KEY
)
233 return fKeys
.left_shift_key
;
234 if (modifier
== B_RIGHT_SHIFT_KEY
)
235 return fKeys
.right_shift_key
;
236 if (modifier
== B_LEFT_COMMAND_KEY
|| modifier
== B_COMMAND_KEY
)
237 return fKeys
.left_command_key
;
238 if (modifier
== B_RIGHT_COMMAND_KEY
)
239 return fKeys
.right_command_key
;
240 if (modifier
== B_LEFT_CONTROL_KEY
|| modifier
== B_CONTROL_KEY
)
241 return fKeys
.left_control_key
;
242 if (modifier
== B_RIGHT_CONTROL_KEY
)
243 return fKeys
.right_control_key
;
244 if (modifier
== B_LEFT_OPTION_KEY
|| modifier
== B_OPTION_KEY
)
245 return fKeys
.left_option_key
;
246 if (modifier
== B_RIGHT_OPTION_KEY
)
247 return fKeys
.right_option_key
;
248 if (modifier
== B_MENU_KEY
)
249 return fKeys
.menu_key
;
255 /*! Checks whether a key is an active dead key.
258 BKeymap::ActiveDeadKey(uint32 keyCode
, uint32 modifiers
) const
261 uint8 deadKey
= DeadKey(keyCode
, modifiers
, &enabled
);
262 if (deadKey
== 0 || !enabled
)
269 /*! Checks whether a key is a dead key.
270 If it is, the enabled/disabled state of that dead key will be passed
271 out via isEnabled (isEnabled is not touched for non-dead keys).
274 BKeymap::DeadKey(uint32 keyCode
, uint32 modifiers
, bool* _isEnabled
) const
276 uint32 tableMask
= 0;
277 int32 offset
= Offset(keyCode
, modifiers
, &tableMask
);
278 uint8 deadKeyIndex
= DeadKeyIndex(offset
);
279 if (deadKeyIndex
> 0 && _isEnabled
!= NULL
) {
280 uint32 deadTables
[] = {
283 fKeys
.circumflex_tables
,
284 fKeys
.dieresis_tables
,
287 *_isEnabled
= (deadTables
[deadKeyIndex
- 1] & tableMask
) != 0;
294 //! Tell if a key is a dead second key.
296 BKeymap::IsDeadSecondKey(uint32 keyCode
, uint32 modifiers
,
297 uint8 activeDeadKey
) const
302 int32 offset
= Offset(keyCode
, modifiers
);
306 uint32 numBytes
= fChars
[offset
];
310 const int32
* deadOffsets
[] = {
311 fKeys
.acute_dead_key
,
312 fKeys
.grave_dead_key
,
313 fKeys
.circumflex_dead_key
,
314 fKeys
.dieresis_dead_key
,
318 const int32
* deadOffset
= deadOffsets
[activeDeadKey
- 1];
320 for (int32 i
= 0; i
< 32; i
++) {
321 if (offset
== deadOffset
[i
])
324 uint32 deadNumBytes
= fChars
[deadOffset
[i
]];
329 if (strncmp(&fChars
[offset
+ 1], &fChars
[deadOffset
[i
] + 1],
338 //! Get the char for a key given modifiers and active dead key
340 BKeymap::GetChars(uint32 keyCode
, uint32 modifiers
, uint8 activeDeadKey
,
341 char** chars
, int32
* numBytes
) const
346 if (keyCode
> 128 || fChars
== NULL
)
349 // here we take NUMLOCK into account
350 if ((modifiers
& B_NUM_LOCK
) != 0) {
363 modifiers
^= B_SHIFT_KEY
;
367 int32 offset
= Offset(keyCode
, modifiers
);
371 // here we get the char size
372 *numBytes
= fChars
[offset
];
373 if (*numBytes
<= 0) {
374 // if key is not mapped in the option table, fall-through.
375 if ((modifiers
& B_OPTION_KEY
) != 0) {
376 offset
= Offset(keyCode
, modifiers
& ~B_OPTION_KEY
);
379 // get the char size again
380 *numBytes
= fChars
[offset
];
387 // here we take an potential active dead key
388 const int32
* deadKey
;
389 switch (activeDeadKey
) {
391 deadKey
= fKeys
.acute_dead_key
;
394 deadKey
= fKeys
.grave_dead_key
;
396 case kDeadKeyCircumflex
:
397 deadKey
= fKeys
.circumflex_dead_key
;
399 case kDeadKeyDiaeresis
:
400 deadKey
= fKeys
.dieresis_dead_key
;
403 deadKey
= fKeys
.tilde_dead_key
;
407 // if not dead, we copy and return the char
408 char* str
= *chars
= new char[*numBytes
+ 1];
409 strncpy(str
, &fChars
[offset
+ 1], *numBytes
);
415 // if dead key, we search for our current offset char in the dead key
416 // offset table string comparison is needed
417 for (int32 i
= 0; i
< 32; i
++) {
418 if (strncmp(&fChars
[offset
+ 1], &fChars
[deadKey
[i
] + 1], *numBytes
)
420 *numBytes
= fChars
[deadKey
[i
+ 1]];
429 // 1-, 2-, 3-, or 4-byte UTF-8 character
430 char *str
= *chars
= new char[*numBytes
+ 1];
431 strncpy(str
, &fChars
[deadKey
[i
+ 1] + 1], *numBytes
);
441 // if not found we return the current char mapped
442 *chars
= new char[*numBytes
+ 1];
443 strncpy(*chars
, &fChars
[offset
+ 1], *numBytes
);
444 (*chars
)[*numBytes
] = 0;
448 /*! Get a list of characters translated from a given character and
449 set of modifiers to another set of modifiers.
452 BKeymap::GetModifiedCharacters(const char* in
, int32 inModifiers
,
453 int32 outModifiers
, BObjectList
<const char>* _outList
)
455 if (in
== NULL
|| *in
== '\0' || _outList
== NULL
)
458 for(uint32 i
= 0; i
< 128; i
++) {
459 int32 inOffset
= Offset(i
, inModifiers
);
460 size_t sizeIn
= fChars
[inOffset
++];
461 if (sizeIn
== 0 || memcmp(in
, fChars
+ inOffset
, sizeIn
) != 0) {
462 // this character isn't mapped or doesn't match
466 int32 outOffset
= Offset(i
, outModifiers
);
467 size_t sizeOut
= fChars
[outOffset
++];
468 char* out
= (char*)malloc(sizeOut
+ 1);
472 memcpy(out
, fChars
+ outOffset
, sizeOut
);
475 _outList
->AddItem((const char*)out
);
483 BKeymap::operator==(const BKeymap
& other
) const
485 return fCharsSize
== other
.fCharsSize
486 && !memcmp(&fKeys
, &other
.fKeys
, sizeof(fKeys
))
487 && !memcmp(fChars
, other
.fChars
, fCharsSize
);
492 BKeymap::operator!=(const BKeymap
& other
) const
494 return !(*this == other
);
499 BKeymap::operator=(const BKeymap
& other
)
503 fChars
= new char[fCharsSize
];
504 fCharsSize
= other
.fCharsSize
;
505 memcpy(fChars
, other
.fChars
, fCharsSize
);
506 memcpy(&fKeys
, &other
.fKeys
, sizeof(fKeys
));
513 BKeymap::Offset(uint32 keyCode
, uint32 modifiers
, uint32
* _table
) const
521 switch (modifiers
& kModifierKeys
) {
523 offset
= fKeys
.shift_map
[keyCode
];
524 table
= B_SHIFT_TABLE
;
527 offset
= fKeys
.caps_map
[keyCode
];
528 table
= B_CAPS_TABLE
;
530 case B_CAPS_LOCK
| B_SHIFT_KEY
:
531 offset
= fKeys
.caps_shift_map
[keyCode
];
532 table
= B_CAPS_SHIFT_TABLE
;
535 offset
= fKeys
.control_map
[keyCode
];
536 table
= B_CONTROL_TABLE
;
539 offset
= fKeys
.option_map
[keyCode
];
540 table
= B_OPTION_TABLE
;
542 case B_OPTION_KEY
| B_SHIFT_KEY
:
543 offset
= fKeys
.option_shift_map
[keyCode
];
544 table
= B_OPTION_SHIFT_TABLE
;
546 case B_OPTION_KEY
| B_CAPS_LOCK
:
547 offset
= fKeys
.option_caps_map
[keyCode
];
548 table
= B_OPTION_CAPS_TABLE
;
550 case B_OPTION_KEY
| B_SHIFT_KEY
| B_CAPS_LOCK
:
551 offset
= fKeys
.option_caps_shift_map
[keyCode
];
552 table
= B_OPTION_CAPS_SHIFT_TABLE
;
555 offset
= fKeys
.normal_map
[keyCode
];
556 table
= B_NORMAL_TABLE
;
563 if (offset
>= (int32
)fCharsSize
)
571 BKeymap::DeadKeyIndex(int32 offset
) const
573 if (fChars
== NULL
|| offset
<= 0)
576 uint32 numBytes
= fChars
[offset
];
577 if (!numBytes
|| numBytes
> 4)
581 strncpy(chars
, &fChars
[offset
+ 1], numBytes
);
584 const int32 deadOffsets
[] = {
585 fKeys
.acute_dead_key
[1],
586 fKeys
.grave_dead_key
[1],
587 fKeys
.circumflex_dead_key
[1],
588 fKeys
.dieresis_dead_key
[1],
589 fKeys
.tilde_dead_key
[1]
593 for (int32 i
= 0; i
< 5; i
++) {
594 if (offset
== deadOffsets
[i
])
597 uint32 deadNumBytes
= fChars
[deadOffsets
[i
]];
601 if (strncmp(chars
, &fChars
[deadOffsets
[i
] + 1], deadNumBytes
) == 0)