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