2 * Copyright 2004-2011 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
8 * Axel Dörfler, axeld@pinc-software.de.
18 #include <ByteOrder.h>
20 #include <FindDirectory.h>
23 #include <input_globals.h>
26 static const uint32 kModifierKeys
= B_SHIFT_KEY
| B_CAPS_LOCK
| B_CONTROL_KEY
27 | B_OPTION_KEY
| B_COMMAND_KEY
| B_MENU_KEY
;
31 print_key(char* chars
, int32 offset
, bool last
= false)
33 int size
= chars
[offset
++];
42 // single-byte UTF-8/ASCII character
43 fputc(chars
[offset
], stdout
);
48 // 2-, 3-, or 4-byte UTF-8 character
49 char* str
= new char[size
+ 1];
50 strncpy(str
, &chars
[offset
], size
);
68 fModificationMessage(NULL
)
75 delete fModificationMessage
;
80 Keymap::SetTarget(BMessenger target
, BMessage
* modificationMessage
)
82 delete fModificationMessage
;
85 fModificationMessage
= modificationMessage
;
90 Keymap::SetName(const char* name
)
92 strlcpy(fName
, name
, sizeof(fName
));
99 if (fKeys
.version
!= 3)
102 // Print a chart of the normal, shift, control, option, option+shift,
103 // Caps, Caps+shift, Caps+option, and Caps+option+shift keys.
104 puts("Key #\tn\ts\tc\to\tos\tC\tCs\tCo\tCos\n");
106 for (uint8 i
= 0; i
< 128; i
++) {
107 printf(" 0x%02x\t", i
);
108 print_key(fChars
, fKeys
.normal_map
[i
]);
109 print_key(fChars
, fKeys
.shift_map
[i
]);
110 print_key(fChars
, fKeys
.control_map
[i
]);
111 print_key(fChars
, fKeys
.option_map
[i
]);
112 print_key(fChars
, fKeys
.option_shift_map
[i
]);
113 print_key(fChars
, fKeys
.caps_map
[i
]);
114 print_key(fChars
, fKeys
.caps_shift_map
[i
]);
115 print_key(fChars
, fKeys
.option_caps_map
[i
]);
116 print_key(fChars
, fKeys
.option_caps_shift_map
[i
], true);
122 //! Load a map from a file
124 Keymap::Load(const entry_ref
& ref
)
127 status_t status
= entry
.SetTo(&ref
, true);
131 BFile
file(&entry
, B_READ_ONLY
);
132 status
= SetTo(file
);
136 // fetch name from attribute and fall back to filename
138 ssize_t bytesRead
= file
.ReadAttr("keymap:name", B_STRING_TYPE
, 0, fName
,
141 fName
[bytesRead
] = '\0';
143 strlcpy(fName
, ref
.name
, sizeof(fName
));
149 //! We save a map to a file
151 Keymap::Save(const entry_ref
& ref
)
154 status_t status
= file
.SetTo(&ref
,
155 B_WRITE_ONLY
| B_CREATE_FILE
| B_ERASE_FILE
);
156 if (status
!= B_OK
) {
157 printf("error %s\n", strerror(status
));
161 for (uint32 i
= 0; i
< sizeof(fKeys
) / 4; i
++)
162 ((uint32
*)&fKeys
)[i
] = B_HOST_TO_BENDIAN_INT32(((uint32
*)&fKeys
)[i
]);
164 ssize_t bytesWritten
= file
.Write(&fKeys
, sizeof(fKeys
));
165 if (bytesWritten
< (ssize_t
)sizeof(fKeys
))
166 status
= bytesWritten
< 0 ? bytesWritten
: B_IO_ERROR
;
168 for (uint32 i
= 0; i
< sizeof(fKeys
) / 4; i
++)
169 ((uint32
*)&fKeys
)[i
] = B_BENDIAN_TO_HOST_INT32(((uint32
*)&fKeys
)[i
]);
171 if (status
== B_OK
) {
172 fCharsSize
= B_HOST_TO_BENDIAN_INT32(fCharsSize
);
174 bytesWritten
= file
.Write(&fCharsSize
, sizeof(uint32
));
175 if (bytesWritten
< (ssize_t
)sizeof(uint32
))
176 status
= bytesWritten
< 0 ? bytesWritten
: B_IO_ERROR
;
178 fCharsSize
= B_BENDIAN_TO_HOST_INT32(fCharsSize
);
181 if (status
== B_OK
) {
182 bytesWritten
= file
.Write(fChars
, fCharsSize
);
183 if (bytesWritten
< (ssize_t
)fCharsSize
)
184 status
= bytesWritten
< 0 ? bytesWritten
: B_IO_ERROR
;
187 if (status
== B_OK
) {
188 file
.WriteAttr("keymap:name", B_STRING_TYPE
, 0, fName
, strlen(fName
));
189 // Failing would be non-fatal
197 Keymap::SetModifier(uint32 keyCode
, uint32 modifier
)
199 const uint32 kSingleModifierKeys
= B_LEFT_SHIFT_KEY
| B_RIGHT_SHIFT_KEY
200 | B_LEFT_COMMAND_KEY
| B_RIGHT_COMMAND_KEY
| B_LEFT_CONTROL_KEY
201 | B_RIGHT_CONTROL_KEY
| B_LEFT_OPTION_KEY
| B_RIGHT_OPTION_KEY
;
203 if ((modifier
& kSingleModifierKeys
) != 0)
204 modifier
&= kSingleModifierKeys
;
205 else if ((modifier
& kModifierKeys
) != 0)
206 modifier
&= kModifierKeys
;
208 if (modifier
== B_CAPS_LOCK
)
209 fKeys
.caps_key
= keyCode
;
210 else if (modifier
== B_NUM_LOCK
)
211 fKeys
.num_key
= keyCode
;
212 else if (modifier
== B_SCROLL_LOCK
)
213 fKeys
.scroll_key
= keyCode
;
214 else if (modifier
== B_LEFT_SHIFT_KEY
)
215 fKeys
.left_shift_key
= keyCode
;
216 else if (modifier
== B_RIGHT_SHIFT_KEY
)
217 fKeys
.right_shift_key
= keyCode
;
218 else if (modifier
== B_LEFT_COMMAND_KEY
)
219 fKeys
.left_command_key
= keyCode
;
220 else if (modifier
== B_RIGHT_COMMAND_KEY
)
221 fKeys
.right_command_key
= keyCode
;
222 else if (modifier
== B_LEFT_CONTROL_KEY
)
223 fKeys
.left_control_key
= keyCode
;
224 else if (modifier
== B_RIGHT_CONTROL_KEY
)
225 fKeys
.right_control_key
= keyCode
;
226 else if (modifier
== B_LEFT_OPTION_KEY
)
227 fKeys
.left_option_key
= keyCode
;
228 else if (modifier
== B_RIGHT_OPTION_KEY
)
229 fKeys
.right_option_key
= keyCode
;
230 else if (modifier
== B_MENU_KEY
)
231 fKeys
.menu_key
= keyCode
;
235 if (fModificationMessage
!= NULL
)
236 fTarget
.SendMessage(fModificationMessage
);
242 //! Enables/disables the "deadness" of the given keycode/modifier combo.
244 Keymap::SetDeadKeyEnabled(uint32 keyCode
, uint32 modifiers
, bool enabled
)
246 uint32 tableMask
= 0;
247 int32 offset
= Offset(keyCode
, modifiers
, &tableMask
);
248 uint8 deadKeyIndex
= DeadKeyIndex(offset
);
249 if (deadKeyIndex
> 0) {
250 uint32
* deadTables
[] = {
253 &fKeys
.circumflex_tables
,
254 &fKeys
.dieresis_tables
,
259 (*deadTables
[deadKeyIndex
- 1]) |= tableMask
;
261 (*deadTables
[deadKeyIndex
- 1]) &= ~tableMask
;
263 if (fModificationMessage
!= NULL
)
264 fTarget
.SendMessage(fModificationMessage
);
269 /*! Returns the trigger character string that is currently set for the dead
270 key with the given index (which is 1..5).
273 Keymap::GetDeadKeyTrigger(dead_key_index deadKeyIndex
, BString
& outTrigger
)
276 if (deadKeyIndex
< 1 || deadKeyIndex
> 5)
279 int32 deadOffsets
[] = {
280 fKeys
.acute_dead_key
[1],
281 fKeys
.grave_dead_key
[1],
282 fKeys
.circumflex_dead_key
[1],
283 fKeys
.dieresis_dead_key
[1],
284 fKeys
.tilde_dead_key
[1]
287 int32 offset
= deadOffsets
[deadKeyIndex
- 1];
288 if (offset
< 0 || offset
>= (int32
)fCharsSize
)
291 uint32 deadNumBytes
= fChars
[offset
];
295 outTrigger
.SetTo(&fChars
[offset
+ 1], deadNumBytes
);
299 /*! Sets the trigger character string that shall be used for the dead key
300 with the given index (which is 1..5).
303 Keymap::SetDeadKeyTrigger(dead_key_index deadKeyIndex
, const BString
& trigger
)
305 if (deadKeyIndex
< 1 || deadKeyIndex
> 5)
308 int32 deadOffsets
[] = {
309 fKeys
.acute_dead_key
[1],
310 fKeys
.grave_dead_key
[1],
311 fKeys
.circumflex_dead_key
[1],
312 fKeys
.dieresis_dead_key
[1],
313 fKeys
.tilde_dead_key
[1]
316 int32 offset
= deadOffsets
[deadKeyIndex
- 1];
317 if (offset
< 0 || offset
>= (int32
)fCharsSize
)
320 if (_SetChars(offset
, trigger
.String(), trigger
.Length())) {
321 // reset modifier table such that new dead key is enabled wherever
323 uint32
* deadTables
[] = {
326 &fKeys
.circumflex_tables
,
327 &fKeys
.dieresis_tables
,
330 *deadTables
[deadKeyIndex
- 1]
331 = B_NORMAL_TABLE
| B_SHIFT_TABLE
| B_CONTROL_TABLE
| B_OPTION_TABLE
332 | B_OPTION_SHIFT_TABLE
| B_CAPS_TABLE
| B_CAPS_SHIFT_TABLE
333 | B_OPTION_CAPS_TABLE
| B_OPTION_CAPS_SHIFT_TABLE
;
335 if (fModificationMessage
!= NULL
)
336 fTarget
.SendMessage(fModificationMessage
);
342 Keymap::RestoreSystemDefault()
345 status_t status
= find_directory(B_USER_SETTINGS_DIRECTORY
, &path
);
349 path
.Append("Key_map");
351 BEntry
entry(path
.Path());
358 //! We make our input server use the map in /boot/home/config/settings/Keymap
362 status_t result
= _restore_key_map_();
364 set_keyboard_locks(modifiers());
370 Keymap::SetKey(uint32 keyCode
, uint32 modifiers
, int8 deadKey
,
371 const char* bytes
, int32 numBytes
)
373 int32 offset
= Offset(keyCode
, modifiers
);
378 numBytes
= strlen(bytes
);
382 if (_SetChars(offset
, bytes
, numBytes
)) {
383 if (fModificationMessage
!= NULL
)
384 fTarget
.SendMessage(fModificationMessage
);
390 Keymap::operator=(const Keymap
& other
)
396 delete fModificationMessage
;
398 fChars
= new(std::nothrow
) char[other
.fCharsSize
];
399 if (fChars
!= NULL
) {
400 memcpy(fChars
, other
.fChars
, other
.fCharsSize
);
401 fCharsSize
= other
.fCharsSize
;
405 memcpy(&fKeys
, &other
.fKeys
, sizeof(key_map
));
406 strlcpy(fName
, other
.fName
, sizeof(fName
));
408 fTarget
= other
.fTarget
;
410 if (other
.fModificationMessage
!= NULL
)
411 fModificationMessage
= new BMessage(*other
.fModificationMessage
);
418 Keymap::_SetChars(int32 offset
, const char* bytes
, int32 numBytes
)
420 int32 oldNumBytes
= fChars
[offset
];
422 if (oldNumBytes
== numBytes
423 && !memcmp(&fChars
[offset
+ 1], bytes
, numBytes
)) {
428 int32 diff
= numBytes
- oldNumBytes
;
433 // make space for the new data
434 char* chars
= new(std::nothrow
) char[fCharsSize
];
436 memcpy(chars
, fChars
, offset
+ oldNumBytes
+ 1);
437 memcpy(&chars
[offset
+ 1 + numBytes
],
438 &fChars
[offset
+ 1 + oldNumBytes
],
439 fCharsSize
- 2 - offset
- diff
);
444 } else if (diff
< 0) {
446 memmove(&fChars
[offset
+ numBytes
], &fChars
[offset
+ oldNumBytes
],
447 fCharsSize
- offset
- 2 - diff
);
451 int32
* data
= fKeys
.control_map
;
452 int32 size
= sizeof(fKeys
.control_map
) / 4 * 9
453 + sizeof(fKeys
.acute_dead_key
) / 4 * 5;
454 for (int32 i
= 0; i
< size
; i
++) {
455 if (data
[i
] > offset
)
460 memcpy(&fChars
[offset
+ 1], bytes
, numBytes
);
461 fChars
[offset
] = numBytes
;