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