xref: /haiku/src/add-ons/input_server/devices/keyboard/Keymap.cpp (revision 3332e5b7968a12fd6074d5d9293fe27f1f617fe2)
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_LEFT_COMMAND_KEY)
163 		return fKeys.left_command_key;
164 	if (modifier == B_RIGHT_COMMAND_KEY)
165 		return fKeys.right_command_key;
166 	if (modifier == B_LEFT_CONTROL_KEY)
167 		return fKeys.left_control_key;
168 	if (modifier == B_RIGHT_CONTROL_KEY)
169 		return fKeys.right_control_key;
170 
171 	return 0;
172 }
173 
174 
175 //! Tell if a key is a dead key, needed for draw a dead key
176 uint8
177 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers)
178 {
179 	if (keyCode >= 256)
180 		return 0;
181 
182 	int32 offset;
183 	uint32 tableMask = 0;
184 
185 	switch (modifiers & 0xcf) {
186 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; tableMask = B_SHIFT_TABLE; break;
187 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; tableMask = B_CAPS_TABLE; break;
188 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; tableMask = B_CAPS_SHIFT_TABLE; break;
189 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; tableMask = B_OPTION_TABLE; break;
190 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; tableMask = B_OPTION_SHIFT_TABLE; break;
191 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; tableMask = B_OPTION_CAPS_TABLE; break;
192 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; tableMask = B_OPTION_CAPS_SHIFT_TABLE; break;
193 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; tableMask = B_CONTROL_TABLE; break;
194 		default: offset = fKeys.normal_map[keyCode]; tableMask = B_NORMAL_TABLE; break;
195 	}
196 
197 	if (offset <= 0 || offset > fCharsSize)
198 		return 0;
199 
200 	uint32 numBytes = fChars[offset];
201 	if (!numBytes)
202 		return 0;
203 
204 	char chars[4];
205 	strncpy(chars, &(fChars[offset+1]), numBytes );
206 	chars[numBytes] = 0;
207 
208 	int32 deadOffsets[] = {
209 		fKeys.acute_dead_key[1],
210 		fKeys.grave_dead_key[1],
211 		fKeys.circumflex_dead_key[1],
212 		fKeys.dieresis_dead_key[1],
213 		fKeys.tilde_dead_key[1]
214 	};
215 
216 	uint32 deadTables[] = {
217 		fKeys.acute_tables,
218 		fKeys.grave_tables,
219 		fKeys.circumflex_tables,
220 		fKeys.dieresis_tables,
221 		fKeys.tilde_tables
222 	};
223 
224 	for (int32 i = 0; i < 5; i++) {
225 		if ((deadTables[i] & tableMask) == 0)
226 			continue;
227 
228 		if (offset == deadOffsets[i])
229 			return i + 1;
230 
231 		uint32 deadNumBytes = fChars[deadOffsets[i]];
232 		if (!deadNumBytes)
233 			continue;
234 
235 		if (!strncmp(chars, &(fChars[deadOffsets[i] + 1]), deadNumBytes))
236 			return i + 1;
237 	}
238 	return 0;
239 }
240 
241 
242 //! Tell if a key is a dead second key, needed for draw a dead second key
243 bool
244 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey)
245 {
246 	if (!activeDeadKey || keyCode >= 256)
247 		return false;
248 
249 	int32 offset;
250 
251 	switch (modifiers & 0xcf) {
252 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break;
253 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break;
254 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break;
255 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break;
256 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break;
257 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break;
258 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break;
259 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break;
260 		default: offset = fKeys.normal_map[keyCode]; break;
261 	}
262 
263 	if (offset <= 0 || offset > fCharsSize)
264 		return false;
265 
266 	uint32 numBytes = fChars[offset];
267 	if (!numBytes)
268 		return false;
269 
270 	int32* deadOffsets[] = {
271 		fKeys.acute_dead_key,
272 		fKeys.grave_dead_key,
273 		fKeys.circumflex_dead_key,
274 		fKeys.dieresis_dead_key,
275 		fKeys.tilde_dead_key
276 	};
277 
278 	int32 *deadOffset = deadOffsets[activeDeadKey-1];
279 
280 	for (int32 i=0; i<32; i++) {
281 		if (offset == deadOffset[i])
282 			return true;
283 
284 		uint32 deadNumBytes = fChars[deadOffset[i]];
285 		if (!deadNumBytes)
286 			continue;
287 
288 		if (!strncmp(&(fChars[offset+1]), &(fChars[deadOffset[i]+1]), deadNumBytes))
289 			return true;
290 
291 		i++;
292 	}
293 
294 	return false;
295 }
296 
297 
298 //! Get the char for a key given modifiers and active dead key
299 void
300 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey,
301 	char** chars, int32* numBytes)
302 {
303 	*numBytes = 0;
304 	*chars = NULL;
305 
306 	if (keyCode >= 256)
307 		return;
308 
309 	// here we take NUMLOCK into account
310 	if (modifiers & B_NUM_LOCK) {
311 		switch (keyCode) {
312 			case 0x37:
313 			case 0x38:
314 			case 0x39:
315 			case 0x48:
316 			case 0x49:
317 			case 0x4a:
318 			case 0x58:
319 			case 0x59:
320 			case 0x5a:
321 			case 0x64:
322 			case 0x65:
323 				modifiers ^= B_SHIFT_KEY;
324 				break;
325 		}
326 	}
327 
328 	int32 offset;
329 
330 	// here we choose the right map given the modifiers
331 	switch (modifiers & 0xcf) {
332 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break;
333 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break;
334 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break;
335 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break;
336 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break;
337 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break;
338 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break;
339 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break;
340 
341 		default:
342 			offset = fKeys.normal_map[keyCode];
343 			break;
344 	}
345 
346 	if (offset <= 0)
347 		return;
348 
349 	// here we get the char size
350 	*numBytes = fChars[offset];
351 	if (!*numBytes)
352 		return;
353 
354 	// here we take an potential active dead key
355 	int32 *deadKey;
356 	switch (activeDeadKey) {
357 		case 1: deadKey = fKeys.acute_dead_key; break;
358 		case 2: deadKey = fKeys.grave_dead_key; break;
359 		case 3: deadKey = fKeys.circumflex_dead_key; break;
360 		case 4: deadKey = fKeys.dieresis_dead_key; break;
361 		case 5: deadKey = fKeys.tilde_dead_key; break;
362 		default:
363 		{
364 			// if not dead, we copy and return the char
365 			char *str = *chars = new (std::nothrow) char[*numBytes + 1];
366 			if (str == NULL) {
367 				*numBytes = 0;
368 				return;
369 			}
370 			strncpy(str, &(fChars[offset + 1]), *numBytes);
371 			str[*numBytes] = 0;
372 			return;
373 		}
374 	}
375 
376 	// if dead key, we search for our current offset char in the dead key offset table
377 	// string comparison is needed
378 	for (int32 i = 0; i < 32; i++) {
379 		if (strncmp(&(fChars[offset + 1]), &(fChars[deadKey[i] + 1]), *numBytes) == 0) {
380 			*numBytes = fChars[deadKey[i + 1]];
381 
382 			switch (*numBytes) {
383 				case 0:
384 					// Not mapped
385 					*chars = NULL;
386 					break;
387 				default:
388 				{
389 					// 1-, 2-, 3-, or 4-byte UTF-8 character
390 					char *str = *chars = new (std::nothrow) char[*numBytes + 1];
391 					if (str == NULL) {
392 						*numBytes = 0;
393 						return;
394 					}
395 					strncpy(str, &fChars[deadKey[i + 1] + 1], *numBytes);
396 					str[*numBytes] = 0;
397 					break;
398 				}
399 			}
400 			return;
401 		}
402 		i++;
403 	}
404 
405 	// if not found we return the current char mapped
406 	*chars = new (std::nothrow) char[*numBytes + 1];
407 	if (*chars == NULL) {
408 		*numBytes = 0;
409 		return;
410 	}
411 
412 	strncpy(*chars, &(fChars[offset + 1]), *numBytes );
413 	(*chars)[*numBytes] = 0;
414 }
415 
416 
417 status_t
418 Keymap::LoadCurrent()
419 {
420 	key_map *keys = NULL;
421 	free(fChars);
422 	fChars = NULL;
423 
424 	_get_key_map(&keys, &fChars, &fCharsSize);
425 	if (!keys) {
426 		fprintf(stderr, "error while getting current keymap!\n");
427 		return B_ERROR;
428 	}
429 	memcpy(&fKeys, keys, sizeof(fKeys));
430 	free(keys);
431 	return B_OK;
432 }
433 
434