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