xref: /haiku/src/add-ons/input_server/devices/keyboard/Keymap.cpp (revision 03187b607b2b5eec7ee059f1ead09bdba14991fb)
1 /*
2  * Copyright 2004-2006, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Jérôme Duval
7  */
8 
9 
10 #include "Keymap.h"
11 
12 #include <ByteOrder.h>
13 #include <File.h>
14 #include <InputServerTypes.h>
15 #include <Message.h>
16 #include <input_globals.h>
17 
18 #include <new>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 
24 static void
25 print_key(char *chars, int32 offset)
26 {
27 	int size = chars[offset++];
28 
29 	switch (size) {
30 		case 0:
31 			// Not mapped
32 			printf("N/A");
33 			break;
34 
35 		case 1:
36 			// 1-byte UTF-8/ASCII character
37 			printf("%c", chars[offset]);
38 			break;
39 
40 		default:
41 		{
42 			// 2-, 3-, or 4-byte UTF-8 character
43 			char *str = new (std::nothrow) char[size + 1];
44 			if (str == NULL)
45 				break;
46 
47 			strncpy(str, &(chars[offset]), size);
48 			str[size] = 0;
49 			printf("%s", str);
50 			delete [] str;
51 			break;
52 		}
53 	}
54 
55 	printf("\t");
56 }
57 
58 
59 //	#pragma mark -
60 
61 
62 void
63 Keymap::DumpKeymap()
64 {
65 	// Print a chart of the normal, shift, option, and option+shift
66 	// keys.
67 	printf("Key #\tNormal\tShift\tCaps\tC+S\tOption\tO+S\tO+C\tO+C+S\tControl\n");
68 
69 	for (int i = 0; i < 128; i++) {
70 		printf(" 0x%x\t", i);
71 		print_key(fChars, fKeys.normal_map[i]);
72 		print_key(fChars, fKeys.shift_map[i]);
73 		print_key(fChars, fKeys.caps_map[i]);
74 		print_key(fChars, fKeys.caps_shift_map[i]);
75 		print_key(fChars, fKeys.option_map[i]);
76 		print_key(fChars, fKeys.option_shift_map[i]);
77 		print_key(fChars, fKeys.option_caps_map[i]);
78 		print_key(fChars, fKeys.option_caps_shift_map[i]);
79 		print_key(fChars, fKeys.control_map[i]);
80 		printf("\n");
81 	}
82 }
83 
84 
85 Keymap::Keymap()
86 	:
87 	fChars(NULL)
88 {
89 	key_map *keys;
90 	_get_key_map(&keys, &fChars, &fCharsSize);
91 
92 	if (keys) {
93 		memcpy(&fKeys, keys, sizeof(key_map));
94 		free(keys);
95 	}
96 }
97 
98 
99 Keymap::~Keymap()
100 {
101 	free(fChars);
102 }
103 
104 
105 /* we need to know if a key is a modifier key to choose
106 	a valid key when several are pressed together
107 */
108 bool
109 Keymap::IsModifierKey(uint32 keyCode)
110 {
111 	return keyCode == fKeys.caps_key
112 		|| keyCode == fKeys.num_key
113 		|| keyCode == fKeys.scroll_key
114 		|| keyCode == fKeys.left_shift_key
115 		|| keyCode == fKeys.right_shift_key
116 		|| keyCode == fKeys.left_command_key
117 		|| keyCode == fKeys.right_command_key
118 		|| keyCode == fKeys.left_control_key
119 		|| keyCode == fKeys.right_control_key
120 		|| keyCode == fKeys.left_option_key
121 		|| keyCode == fKeys.right_option_key
122 		|| keyCode == fKeys.menu_key;
123 }
124 
125 
126 //! We need to know a modifier for a key
127 uint32
128 Keymap::Modifier(uint32 keyCode)
129 {
130 	if (keyCode == fKeys.caps_key)
131 		return B_CAPS_LOCK;
132 	if (keyCode == fKeys.num_key)
133 		return B_NUM_LOCK;
134 	if (keyCode == fKeys.scroll_key)
135 		return B_SCROLL_LOCK;
136 	if (keyCode == fKeys.left_shift_key)
137 		return B_LEFT_SHIFT_KEY | B_SHIFT_KEY;
138 	if (keyCode == fKeys.right_shift_key)
139 		return B_RIGHT_SHIFT_KEY | B_SHIFT_KEY;
140 	if (keyCode == fKeys.left_command_key)
141 		return B_LEFT_COMMAND_KEY | B_COMMAND_KEY;
142 	if (keyCode == fKeys.right_command_key)
143 		return B_RIGHT_COMMAND_KEY | B_COMMAND_KEY;
144 	if (keyCode == fKeys.left_control_key)
145 		return B_LEFT_CONTROL_KEY | B_CONTROL_KEY;
146 	if (keyCode == fKeys.right_control_key)
147 		return B_RIGHT_CONTROL_KEY | B_CONTROL_KEY;
148 	if (keyCode == fKeys.left_option_key)
149 		return B_LEFT_OPTION_KEY | B_OPTION_KEY;
150 	if (keyCode == fKeys.right_option_key)
151 		return B_RIGHT_OPTION_KEY | B_OPTION_KEY;
152 	if (keyCode == fKeys.menu_key)
153 		return B_MENU_KEY;
154 
155 	return 0;
156 }
157 
158 
159 uint32
160 Keymap::KeyForModifier(uint32 modifier)
161 {
162 	if (modifier == B_CAPS_LOCK)
163 		return fKeys.caps_key;
164 	if (modifier == B_NUM_LOCK)
165 		return fKeys.num_key;
166 	if (modifier == B_SCROLL_LOCK)
167 		return fKeys.scroll_key;
168 	if (modifier == B_LEFT_SHIFT_KEY || modifier == B_SHIFT_KEY)
169 		return fKeys.left_shift_key;
170 	if (modifier == B_RIGHT_SHIFT_KEY)
171 		return fKeys.right_shift_key;
172 	if (modifier == B_LEFT_COMMAND_KEY || modifier == B_COMMAND_KEY)
173 		return fKeys.left_command_key;
174 	if (modifier == B_RIGHT_COMMAND_KEY)
175 		return fKeys.right_command_key;
176 	if (modifier == B_LEFT_CONTROL_KEY || modifier == B_CONTROL_KEY)
177 		return fKeys.left_control_key;
178 	if (modifier == B_RIGHT_CONTROL_KEY)
179 		return fKeys.right_control_key;
180 	if (modifier == B_LEFT_OPTION_KEY || modifier == B_OPTION_KEY)
181 		return fKeys.left_option_key;
182 	if (modifier == B_RIGHT_OPTION_KEY)
183 		return fKeys.right_option_key;
184 	if (modifier == B_MENU_KEY)
185 		return fKeys.menu_key;
186 
187 	return 0;
188 }
189 
190 
191 //! Tell if a key is a dead key, needed for draw a dead key
192 uint8
193 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers)
194 {
195 	if (keyCode >= 256)
196 		return 0;
197 
198 	int32 offset;
199 	uint32 tableMask = 0;
200 
201 	switch (modifiers & 0xcf) {
202 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; tableMask = B_SHIFT_TABLE; break;
203 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; tableMask = B_CAPS_TABLE; break;
204 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; tableMask = B_CAPS_SHIFT_TABLE; break;
205 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; tableMask = B_OPTION_TABLE; break;
206 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; tableMask = B_OPTION_SHIFT_TABLE; break;
207 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; tableMask = B_OPTION_CAPS_TABLE; break;
208 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; tableMask = B_OPTION_CAPS_SHIFT_TABLE; break;
209 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; tableMask = B_CONTROL_TABLE; break;
210 		default: offset = fKeys.normal_map[keyCode]; tableMask = B_NORMAL_TABLE; break;
211 	}
212 
213 	if (offset <= 0 || offset > fCharsSize)
214 		return 0;
215 
216 	uint32 numBytes = fChars[offset];
217 	if (!numBytes)
218 		return 0;
219 
220 	char chars[4];
221 	strncpy(chars, &(fChars[offset+1]), numBytes );
222 	chars[numBytes] = 0;
223 
224 	int32 deadOffsets[] = {
225 		fKeys.acute_dead_key[1],
226 		fKeys.grave_dead_key[1],
227 		fKeys.circumflex_dead_key[1],
228 		fKeys.dieresis_dead_key[1],
229 		fKeys.tilde_dead_key[1]
230 	};
231 
232 	uint32 deadTables[] = {
233 		fKeys.acute_tables,
234 		fKeys.grave_tables,
235 		fKeys.circumflex_tables,
236 		fKeys.dieresis_tables,
237 		fKeys.tilde_tables
238 	};
239 
240 	for (int32 i = 0; i < 5; i++) {
241 		if ((deadTables[i] & tableMask) == 0)
242 			continue;
243 
244 		if (offset == deadOffsets[i])
245 			return i + 1;
246 
247 		uint32 deadNumBytes = fChars[deadOffsets[i]];
248 		if (!deadNumBytes)
249 			continue;
250 
251 		if (!strncmp(chars, &(fChars[deadOffsets[i] + 1]), deadNumBytes))
252 			return i + 1;
253 	}
254 	return 0;
255 }
256 
257 
258 //! Tell if a key is a dead second key, needed for draw a dead second key
259 bool
260 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey)
261 {
262 	if (!activeDeadKey || keyCode >= 256)
263 		return false;
264 
265 	int32 offset;
266 
267 	switch (modifiers & 0xcf) {
268 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break;
269 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break;
270 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break;
271 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break;
272 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break;
273 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break;
274 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break;
275 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break;
276 		default: offset = fKeys.normal_map[keyCode]; break;
277 	}
278 
279 	if (offset <= 0 || offset > fCharsSize)
280 		return false;
281 
282 	uint32 numBytes = fChars[offset];
283 	if (!numBytes)
284 		return false;
285 
286 	int32* deadOffsets[] = {
287 		fKeys.acute_dead_key,
288 		fKeys.grave_dead_key,
289 		fKeys.circumflex_dead_key,
290 		fKeys.dieresis_dead_key,
291 		fKeys.tilde_dead_key
292 	};
293 
294 	int32 *deadOffset = deadOffsets[activeDeadKey-1];
295 
296 	for (int32 i=0; i<32; i++) {
297 		if (offset == deadOffset[i])
298 			return true;
299 
300 		uint32 deadNumBytes = fChars[deadOffset[i]];
301 		if (!deadNumBytes)
302 			continue;
303 
304 		if (!strncmp(&(fChars[offset+1]), &(fChars[deadOffset[i]+1]), deadNumBytes))
305 			return true;
306 
307 		i++;
308 	}
309 
310 	return false;
311 }
312 
313 
314 //! Get the char for a key given modifiers and active dead key
315 void
316 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey,
317 	char** chars, int32* numBytes)
318 {
319 	*numBytes = 0;
320 	*chars = NULL;
321 
322 	if (keyCode >= 256)
323 		return;
324 
325 	// here we take NUMLOCK into account
326 	if (modifiers & B_NUM_LOCK) {
327 		switch (keyCode) {
328 			case 0x37:
329 			case 0x38:
330 			case 0x39:
331 			case 0x48:
332 			case 0x49:
333 			case 0x4a:
334 			case 0x58:
335 			case 0x59:
336 			case 0x5a:
337 			case 0x64:
338 			case 0x65:
339 				modifiers ^= B_SHIFT_KEY;
340 				break;
341 		}
342 	}
343 
344 	int32 offset;
345 
346 	// here we choose the right map given the modifiers
347 	switch (modifiers & 0xcf) {
348 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break;
349 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break;
350 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break;
351 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break;
352 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break;
353 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break;
354 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break;
355 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break;
356 
357 		default:
358 			offset = fKeys.normal_map[keyCode];
359 			break;
360 	}
361 
362 	if (offset <= 0)
363 		return;
364 
365 	// here we get the char size
366 	*numBytes = fChars[offset];
367 	if (!*numBytes)
368 		return;
369 
370 	// here we take an potential active dead key
371 	int32 *deadKey;
372 	switch (activeDeadKey) {
373 		case 1: deadKey = fKeys.acute_dead_key; break;
374 		case 2: deadKey = fKeys.grave_dead_key; break;
375 		case 3: deadKey = fKeys.circumflex_dead_key; break;
376 		case 4: deadKey = fKeys.dieresis_dead_key; break;
377 		case 5: deadKey = fKeys.tilde_dead_key; break;
378 		default:
379 		{
380 			// if not dead, we copy and return the char
381 			char *str = *chars = new (std::nothrow) char[*numBytes + 1];
382 			if (str == NULL) {
383 				*numBytes = 0;
384 				return;
385 			}
386 			strncpy(str, &(fChars[offset + 1]), *numBytes);
387 			str[*numBytes] = 0;
388 			return;
389 		}
390 	}
391 
392 	// if dead key, we search for our current offset char in the dead key offset table
393 	// string comparison is needed
394 	for (int32 i = 0; i < 32; i++) {
395 		if (strncmp(&(fChars[offset + 1]), &(fChars[deadKey[i] + 1]), *numBytes) == 0) {
396 			*numBytes = fChars[deadKey[i + 1]];
397 
398 			switch (*numBytes) {
399 				case 0:
400 					// Not mapped
401 					*chars = NULL;
402 					break;
403 				default:
404 				{
405 					// 1-, 2-, 3-, or 4-byte UTF-8 character
406 					char *str = *chars = new (std::nothrow) char[*numBytes + 1];
407 					if (str == NULL) {
408 						*numBytes = 0;
409 						return;
410 					}
411 					strncpy(str, &fChars[deadKey[i + 1] + 1], *numBytes);
412 					str[*numBytes] = 0;
413 					break;
414 				}
415 			}
416 			return;
417 		}
418 		i++;
419 	}
420 
421 	// if not found we return the whole sequence (the dead key itself plus
422 	// the following char)
423 	int32 deadKeyNumBytes = fChars[deadKey[1]];
424 	int32 fullNumBytes = deadKeyNumBytes + *numBytes;
425 	*chars = new (std::nothrow) char[fullNumBytes + 1];
426 	if (*chars == NULL) {
427 		*numBytes = 0;
428 		return;
429 	}
430 	strncpy(*chars, &fChars[deadKey[1] + 1], deadKeyNumBytes);
431 	strncpy(*chars + deadKeyNumBytes, &fChars[offset + 1], *numBytes);
432 	*numBytes = fullNumBytes;
433 	(*chars)[fullNumBytes] = 0;
434 }
435 
436 
437 status_t
438 Keymap::LoadCurrent()
439 {
440 	key_map *keys = NULL;
441 	free(fChars);
442 	fChars = NULL;
443 
444 	_get_key_map(&keys, &fChars, &fCharsSize);
445 	if (!keys) {
446 		fprintf(stderr, "error while getting current keymap!\n");
447 		return B_ERROR;
448 	}
449 	memcpy(&fKeys, keys, sizeof(fKeys));
450 	free(keys);
451 	return B_OK;
452 }
453 
454