xref: /haiku/src/preferences/keymap/Keymap.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
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.cpp
10 //  Author:      Sandor Vroemisse, Jérôme Duval
11 //  Description: Keymap Preferences
12 //  Created :    July 12, 2004
13 //
14 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
15 
16 #include "Keymap.h"
17 #include <stdio.h>
18 #include <string.h>
19 #include <ByteOrder.h>
20 #include <File.h>
21 #include <input_globals.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 /*
79 	file format in big endian :
80 	struct key_map
81 	uint32 size of following charset
82 	charset (offsets go into this with size of character followed by character)
83 */
84 // we load a map from a file
85 status_t
86 Keymap::Load(entry_ref &ref)
87 {
88 	status_t err;
89 	BEntry entry(&ref, true);
90 	if ((err = entry.InitCheck()) != B_OK) {
91 		fprintf(stderr, "error loading keymap: %s\n", strerror(err));
92 		return err;
93 	}
94 
95 	BFile file(&entry, B_READ_ONLY);
96 	if ((err = file.InitCheck()) != B_OK) {
97 		fprintf(stderr, "error loading keymap: %s\n", strerror(err));
98 		return err;
99 	}
100 
101 	if ((err = file.Read(&fKeys, sizeof(fKeys))) < (ssize_t)sizeof(fKeys)) {
102 		fprintf(stderr, "error reading keymap keys: %s\n", strerror(err));
103 		return B_BAD_VALUE;
104 	}
105 
106 	for (uint32 i=0; i<sizeof(fKeys)/4; i++)
107 		((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]);
108 
109 	if ((err = file.Read(&fCharsSize, sizeof(uint32))) < (ssize_t)sizeof(uint32)) {
110 		fprintf(stderr, "error reading keymap size: %s\n", strerror(err));
111 		return B_BAD_VALUE;
112 	}
113 
114 	fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize);
115 	if (!fChars)
116 		delete[] fChars;
117 	fChars = new char[fCharsSize];
118 	err = file.Read(fChars, fCharsSize);
119 	if (err < B_OK) {
120 		fprintf(stderr, "error reading keymap chars: %s\n", strerror(err));
121 	}
122 	return err;
123 }
124 
125 
126 // we save a map from a file
127 status_t
128 Keymap::Save(entry_ref &ref)
129 {
130 	status_t err;
131 
132 	BFile file(&ref, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE );
133 	if ((err = file.InitCheck()) != B_OK) {
134 		printf("error %s\n", strerror(err));
135 		return err;
136 	}
137 
138 	for (uint32 i=0; i<sizeof(fKeys)/4; i++)
139 		((uint32*)&fKeys)[i] = B_HOST_TO_BENDIAN_INT32(((uint32*)&fKeys)[i]);
140 
141 	if ((err = file.Write(&fKeys, sizeof(fKeys))) < (ssize_t)sizeof(fKeys)) {
142 		return err;
143 	}
144 
145 	for (uint32 i=0; i<sizeof(fKeys)/4; i++)
146 		((uint32*)&fKeys)[i] = B_BENDIAN_TO_HOST_INT32(((uint32*)&fKeys)[i]);
147 
148 	fCharsSize = B_HOST_TO_BENDIAN_INT32(fCharsSize);
149 
150 	if ((err = file.Write(&fCharsSize, sizeof(uint32))) < (ssize_t)sizeof(uint32)) {
151 		return B_BAD_VALUE;
152 	}
153 
154 	fCharsSize = B_BENDIAN_TO_HOST_INT32(fCharsSize);
155 
156 	if ((err = file.Write(fChars, fCharsSize)) < (ssize_t)fCharsSize)
157 		return err;
158 
159 	return B_OK;
160 }
161 
162 
163 /* we need to know if a key is a modifier key to choose
164 	a valid key when several are pressed together
165 */
166 bool
167 Keymap::IsModifierKey(uint32 keyCode)
168 {
169 	if ((keyCode == fKeys.caps_key)
170 		|| (keyCode == fKeys.num_key)
171 		|| (keyCode == fKeys.scroll_key)
172 		|| (keyCode == fKeys.left_shift_key)
173 		|| (keyCode == fKeys.right_shift_key)
174 		|| (keyCode == fKeys.left_command_key)
175 		|| (keyCode == fKeys.right_command_key)
176 		|| (keyCode == fKeys.left_control_key)
177 		|| (keyCode == fKeys.right_control_key)
178 		|| (keyCode == fKeys.left_option_key)
179 		|| (keyCode == fKeys.right_option_key)
180 		|| (keyCode == fKeys.menu_key))
181 			return true;
182 	return false;
183 }
184 
185 
186 // tell if a key is a dead key, needed for draw a dead key
187 uint8
188 Keymap::IsDeadKey(uint32 keyCode, uint32 modifiers)
189 {
190 	int32 offset;
191 	uint32 tableMask = 0;
192 
193 	switch (modifiers & 0xcf) {
194 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; tableMask = B_SHIFT_TABLE; break;
195 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; tableMask = B_CAPS_TABLE; break;
196 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; tableMask = B_CAPS_SHIFT_TABLE; break;
197 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; tableMask = B_OPTION_TABLE; break;
198 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; tableMask = B_OPTION_SHIFT_TABLE; break;
199 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; tableMask = B_OPTION_CAPS_TABLE; break;
200 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; tableMask = B_OPTION_CAPS_SHIFT_TABLE; break;
201 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; tableMask = B_CONTROL_TABLE; break;
202 		default: offset = fKeys.normal_map[keyCode]; tableMask = B_NORMAL_TABLE; break;
203 	}
204 
205 	if (offset<=0)
206 		return 0;
207 	uint32 numBytes = fChars[offset];
208 
209 	if (!numBytes)
210 		return 0;
211 
212 	char chars[4];
213 	strncpy(chars, &(fChars[offset+1]), numBytes );
214 	chars[numBytes] = 0;
215 
216 	int32 deadOffsets[] = {
217 		fKeys.acute_dead_key[1],
218 		fKeys.grave_dead_key[1],
219 		fKeys.circumflex_dead_key[1],
220 		fKeys.dieresis_dead_key[1],
221 		fKeys.tilde_dead_key[1]
222 	};
223 
224 	uint32 deadTables[] = {
225 		fKeys.acute_tables,
226 		fKeys.grave_tables,
227 		fKeys.circumflex_tables,
228 		fKeys.dieresis_tables,
229 		fKeys.tilde_tables
230 	};
231 
232 	for (int32 i=0; i<5; i++) {
233 		if ((deadTables[i] & tableMask) == 0)
234 			continue;
235 
236 		if (offset == deadOffsets[i])
237 			return i+1;
238 
239 		uint32 deadNumBytes = fChars[deadOffsets[i]];
240 
241 		if (!deadNumBytes)
242 			continue;
243 
244 		if (strncmp(chars, &(fChars[deadOffsets[i]+1]), deadNumBytes ) == 0) {
245 			return i+1;
246 		}
247 	}
248 	return 0;
249 }
250 
251 
252 // tell if a key is a dead second key, needed for draw a dead second key
253 bool
254 Keymap::IsDeadSecondKey(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey)
255 {
256 	if (!activeDeadKey)
257 		return false;
258 
259 	int32 offset;
260 
261 	switch (modifiers & 0xcf) {
262 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break;
263 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break;
264 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break;
265 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break;
266 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break;
267 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break;
268 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break;
269 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break;
270 		default: offset = fKeys.normal_map[keyCode]; break;
271 	}
272 
273 	uint32 numBytes = fChars[offset];
274 
275 	if (!numBytes)
276 		return false;
277 
278 	int32* deadOffsets[] = {
279 		fKeys.acute_dead_key,
280 		fKeys.grave_dead_key,
281 		fKeys.circumflex_dead_key,
282 		fKeys.dieresis_dead_key,
283 		fKeys.tilde_dead_key
284 	};
285 
286 	int32 *deadOffset = deadOffsets[activeDeadKey-1];
287 
288 	for (int32 i=0; i<32; i++) {
289 		if (offset == deadOffset[i])
290 			return true;
291 
292 		uint32 deadNumBytes = fChars[deadOffset[i]];
293 
294 		if (!deadNumBytes)
295 			continue;
296 
297 		if (strncmp(&(fChars[offset+1]), &(fChars[deadOffset[i]+1]), deadNumBytes ) == 0)
298 			return true;
299 		i++;
300 	}
301 	return false;
302 }
303 
304 
305 // get the char for a key given modifiers and active dead key
306 void
307 Keymap::GetChars(uint32 keyCode, uint32 modifiers, uint8 activeDeadKey, char** chars, int32* numBytes)
308 {
309 	int32 offset;
310 
311 	*numBytes = 0;
312 	*chars = NULL;
313 
314 	// here we take NUMLOCK into account
315 	if (modifiers & B_NUM_LOCK)
316 		switch (keyCode) {
317 			case 0x37:
318 			case 0x38:
319 			case 0x39:
320 			case 0x48:
321 			case 0x49:
322 			case 0x4a:
323 			case 0x58:
324 			case 0x59:
325 			case 0x5a:
326 			case 0x64:
327 			case 0x65:
328 				modifiers ^= B_SHIFT_KEY;
329 		}
330 
331 	// here we choose the right map given the modifiers
332 	switch (modifiers & 0xcf) {
333 		case B_SHIFT_KEY: offset = fKeys.shift_map[keyCode]; break;
334 		case B_CAPS_LOCK: offset = fKeys.caps_map[keyCode]; break;
335 		case B_CAPS_LOCK|B_SHIFT_KEY: offset = fKeys.caps_shift_map[keyCode]; break;
336 		case B_OPTION_KEY: offset = fKeys.option_map[keyCode]; break;
337 		case B_OPTION_KEY|B_SHIFT_KEY: offset = fKeys.option_shift_map[keyCode]; break;
338 		case B_OPTION_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_map[keyCode]; break;
339 		case B_OPTION_KEY|B_SHIFT_KEY|B_CAPS_LOCK: offset = fKeys.option_caps_shift_map[keyCode]; break;
340 		case B_CONTROL_KEY: offset = fKeys.control_map[keyCode]; break;
341 		default: offset = fKeys.normal_map[keyCode]; break;
342 	}
343 
344 	// here we get the char size
345 	*numBytes = fChars[offset];
346 
347 	if (!*numBytes)
348 		return;
349 
350 	// here we take an potential active dead key
351 	int32 *dead_key;
352 	switch(activeDeadKey) {
353 		case 1: dead_key = fKeys.acute_dead_key; break;
354 		case 2: dead_key = fKeys.grave_dead_key; break;
355 		case 3: dead_key = fKeys.circumflex_dead_key; break;
356 		case 4: dead_key = fKeys.dieresis_dead_key; break;
357 		case 5: dead_key = fKeys.tilde_dead_key; break;
358 		default:
359 		{
360 			// if not dead, we copy and return the char
361 			char *str = *chars = new char[*numBytes + 1];
362 			strncpy(str, &(fChars[offset+1]), *numBytes );
363 			str[*numBytes] = 0;
364 			return;
365 		}
366 	}
367 
368 	// if dead key, we search for our current offset char in the dead key offset table
369 	// string comparison is needed
370 	for (int32 i=0; i<32; i++) {
371 		if (strncmp(&(fChars[offset+1]), &(fChars[dead_key[i]+1]), *numBytes ) == 0) {
372 			*numBytes = fChars[dead_key[i+1]];
373 
374 			switch( *numBytes ) {
375 				case 0:
376 					// Not mapped
377 					*chars = NULL;
378 					break;
379 				default:
380 					// 1-, 2-, 3-, or 4-byte UTF-8 character
381 				{
382 					char *str = *chars = new char[*numBytes + 1];
383 					strncpy(str, &fChars[dead_key[i+1]+1], *numBytes );
384 					str[*numBytes] = 0;
385 				}
386 					break;
387 			}
388 			return;
389 		}
390 		i++;
391 	}
392 
393 	// if not found we return the current char mapped
394 	*chars = new char[*numBytes + 1];
395 	strncpy(*chars, &(fChars[offset+1]), *numBytes );
396 	(*chars)[*numBytes] = 0;
397 
398 }
399 
400 
401 // we make our input server use the map in /boot/home/config/settings/Keymap
402 status_t
403 Keymap::Use()
404 {
405 	return _restore_key_map_();
406 }
407