/[rdesktop]/sourceforge.net/trunk/rdesktop/xkeymap.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/xkeymap.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69 - (show annotations)
Sat Jul 27 22:35:38 2002 UTC (21 years, 9 months ago) by astrand
File MIME type: text/plain
File size: 10439 byte(s)
Added "localstate" support to keymapping: Send local modifier state. This fixes problems with Shift-Home etc

1 /*
2 rdesktop: A Remote Desktop Protocol client.
3 User interface services - X keyboard mapping
4 Copyright (C) Matthew Chapman 1999-2001
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include <X11/Xlib.h>
22 #include <X11/keysym.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <limits.h>
28 #include "rdesktop.h"
29 #include "scancodes.h"
30
31 #define KEYMAP_SIZE 4096
32 #define KEYMAP_MASK (KEYMAP_SIZE - 1)
33 #define KEYMAP_MAX_LINE_LENGTH 80
34
35 extern Display *display;
36 extern char keymapname[16];
37 extern int keylayout;
38
39 static key_translation keymap[KEYMAP_SIZE];
40 static unsigned int min_keycode;
41 static uint16 remote_modifier_state = 0;
42
43 static void
44 add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
45 {
46 KeySym keysym;
47
48 keysym = XStringToKeysym(keyname);
49 if (keysym == NoSymbol)
50 {
51 error("Bad keysym %s in keymap %s\n", keyname, mapname);
52 return;
53 }
54
55 DEBUG_KBD("Adding translation, keysym=0x%x, scancode=0x%x, "
56 "modifiers=0x%x\n", (unsigned int) keysym, scancode,
57 modifiers);
58
59 keymap[keysym & KEYMAP_MASK].scancode = scancode;
60 keymap[keysym & KEYMAP_MASK].modifiers = modifiers;
61
62 return;
63 }
64
65
66 static BOOL
67 xkeymap_read(char *mapname)
68 {
69 FILE *fp;
70 char line[KEYMAP_MAX_LINE_LENGTH], path[PATH_MAX];
71 unsigned int line_num = 0;
72 unsigned int line_length = 0;
73 char *keyname, *p;
74 char *line_rest;
75 uint8 scancode;
76 uint16 modifiers;
77
78
79 strcpy(path, KEYMAP_PATH);
80 strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));
81
82 fp = fopen(path, "r");
83 if (fp == NULL)
84 {
85 error("Failed to open keymap %s\n", path);
86 return False;
87 }
88
89 /* FIXME: More tolerant on white space */
90 while (fgets(line, sizeof(line), fp) != NULL)
91 {
92 line_num++;
93
94 /* Replace the \n with \0 */
95 p = strchr(line, '\n');
96 if (p != NULL)
97 *p = 0;
98
99 line_length = strlen(line);
100
101 /* Completely empty line */
102 if (strspn(line, " \t\n\r\f\v") == line_length)
103 {
104 continue;
105 }
106
107 /* Include */
108 if (strncmp(line, "include ", 8) == 0)
109 {
110 if (!xkeymap_read(line + 8))
111 return False;
112 continue;
113 }
114
115 /* map */
116 if (strncmp(line, "map ", 4) == 0)
117 {
118 keylayout = strtol(line + 4, NULL, 16);
119 DEBUG_KBD("Keylayout 0x%x\n", keylayout);
120 continue;
121 }
122
123 /* Comment */
124 if (line[0] == '#')
125 {
126 continue;
127 }
128
129 /* Normal line */
130 keyname = line;
131 p = strchr(line, ' ');
132 if (p == NULL)
133 {
134 error("Bad line %d in keymap %s\n", line_num,
135 mapname);
136 continue;
137 }
138 else
139 {
140 *p = 0;
141 }
142
143 /* scancode */
144 p++;
145 scancode = strtol(p, &line_rest, 16);
146
147 /* flags */
148 /* FIXME: Should allow case-insensitive flag names.
149 Fix by using lex+yacc... */
150 modifiers = 0;
151 if (strstr(line_rest, "altgr"))
152 {
153 MASK_ADD_BITS(modifiers, MapAltGrMask);
154 }
155
156 if (strstr(line_rest, "shift"))
157 {
158 MASK_ADD_BITS(modifiers, MapLeftShiftMask);
159 }
160
161 if (strstr(line_rest, "numlock"))
162 {
163 MASK_ADD_BITS(modifiers, MapNumLockMask);
164 }
165
166 if (strstr(line_rest, "localstate"))
167 {
168 MASK_ADD_BITS(modifiers, MapLocalStateMask);
169 }
170
171 add_to_keymap(keyname, scancode, modifiers, mapname);
172
173 if (strstr(line_rest, "addupper"))
174 {
175 /* Automatically add uppercase key, with same modifiers
176 plus shift */
177 for (p = keyname; *p; p++)
178 *p = toupper(*p);
179 MASK_ADD_BITS(modifiers, MapLeftShiftMask);
180 add_to_keymap(keyname, scancode, modifiers, mapname);
181 }
182 }
183
184 fclose(fp);
185 return True;
186 }
187
188
189 /* Before connecting and creating UI */
190 void
191 xkeymap_init1(void)
192 {
193 int i;
194
195 /* Zeroing keymap */
196 for (i = 0; i < KEYMAP_SIZE; i++)
197 {
198 keymap[i].scancode = 0;
199 keymap[i].modifiers = 0;
200 }
201
202 if (strcmp(keymapname, "none"))
203 {
204 xkeymap_read(keymapname);
205 }
206
207 }
208
209 /* After connecting and creating UI */
210 void
211 xkeymap_init2(void)
212 {
213 unsigned int max_keycode;
214 XDisplayKeycodes(display, &min_keycode, &max_keycode);
215 }
216
217
218 key_translation
219 xkeymap_translate_key(KeySym keysym, unsigned int keycode, unsigned int state)
220 {
221 key_translation tr = { 0, 0 };
222
223 tr = keymap[keysym & KEYMAP_MASK];
224
225 if (tr.modifiers & MapLocalStateMask)
226 {
227 /* The modifiers to send for this key should be obtained
228 from the local state. Currently, only shift is implemented. */
229 if (state & ShiftMask)
230 {
231 tr.modifiers = MapLeftShiftMask;
232 }
233 }
234
235 if (tr.scancode != 0)
236 {
237 DEBUG_KBD
238 ("Found key translation, scancode=0x%x, modifiers=0x%x\n",
239 tr.scancode, tr.modifiers);
240 return tr;
241 }
242
243 printf("No translation for (keysym 0x%lx, %s)\n", keysym,
244 get_ksname(keysym));
245
246 /* not in keymap, try to interpret the raw scancode */
247 if ((keycode >= min_keycode) && (keycode <= 0x60))
248 {
249 tr.scancode = keycode - min_keycode;
250 printf("Sending guessed scancode 0x%x\n", tr.scancode);
251 }
252 else
253 {
254 printf("No good guess for keycode 0x%x found\n", keycode);
255 }
256
257 return tr;
258 }
259
260 uint16
261 xkeymap_translate_button(unsigned int button)
262 {
263 switch (button)
264 {
265 case Button1: /* left */
266 return MOUSE_FLAG_BUTTON1;
267 case Button2: /* middle */
268 return MOUSE_FLAG_BUTTON3;
269 case Button3: /* right */
270 return MOUSE_FLAG_BUTTON2;
271 case Button4: /* wheel up */
272 return MOUSE_FLAG_BUTTON4;
273 case Button5: /* wheel down */
274 return MOUSE_FLAG_BUTTON5;
275 }
276
277 return 0;
278 }
279
280 char *
281 get_ksname(KeySym keysym)
282 {
283 char *ksname = NULL;
284
285 if (keysym == NoSymbol)
286 ksname = "NoSymbol";
287 else if (!(ksname = XKeysymToString(keysym)))
288 ksname = "(no name)";
289
290 return ksname;
291 }
292
293 BOOL
294 inhibit_key(KeySym keysym)
295 {
296 switch (keysym)
297 {
298 case XK_Caps_Lock:
299 return True;
300 break;
301 case XK_Multi_key:
302 return True;
303 break;
304 default:
305 break;
306 }
307 return False;
308 }
309
310 void
311 ensure_remote_modifiers(uint32 ev_time, key_translation tr)
312 {
313 /* If this key is a modifier, do nothing */
314 switch (tr.scancode)
315 {
316 case SCANCODE_CHAR_LSHIFT:
317 case SCANCODE_CHAR_RSHIFT:
318 case SCANCODE_CHAR_LCTRL:
319 case SCANCODE_CHAR_RCTRL:
320 case SCANCODE_CHAR_LALT:
321 case SCANCODE_CHAR_RALT:
322 case SCANCODE_CHAR_LWIN:
323 case SCANCODE_CHAR_RWIN:
324 case SCANCODE_CHAR_NUMLOCK:
325 return;
326 default:
327 break;
328 }
329
330 /* Shift */
331 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
332 != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
333 {
334 /* The remote modifier state is not correct */
335 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask))
336 {
337 /* Needs this modifier. Send down. */
338 rdp_send_scancode(ev_time, RDP_KEYPRESS,
339 SCANCODE_CHAR_LSHIFT);
340 }
341 else
342 {
343 /* Should not use this modifier. Send up. */
344 rdp_send_scancode(ev_time, RDP_KEYRELEASE,
345 SCANCODE_CHAR_LSHIFT);
346 }
347 }
348
349 /* AltGr */
350 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
351 != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
352 {
353 /* The remote modifier state is not correct */
354 if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
355 {
356 /* Needs this modifier. Send down. */
357 rdp_send_scancode(ev_time, RDP_KEYPRESS,
358 SCANCODE_CHAR_RALT);
359 }
360 else
361 {
362 /* Should not use this modifier. Send up. */
363 rdp_send_scancode(ev_time, RDP_KEYRELEASE,
364 SCANCODE_CHAR_RALT);
365 }
366 }
367
368 /* NumLock */
369 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
370 != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
371 {
372 /* The remote modifier state is not correct */
373 DEBUG_KBD("Remote NumLock state is incorrect. Toggling\n");
374 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
375 {
376 /* Needs this modifier. Toggle */
377 rdp_send_scancode(ev_time, RDP_KEYPRESS,
378 SCANCODE_CHAR_NUMLOCK);
379 rdp_send_scancode(ev_time, RDP_KEYRELEASE,
380 SCANCODE_CHAR_NUMLOCK);
381 }
382 else
383 {
384 /* Should not use this modifier. Toggle */
385 rdp_send_scancode(ev_time, RDP_KEYPRESS,
386 SCANCODE_CHAR_NUMLOCK);
387 rdp_send_scancode(ev_time, RDP_KEYRELEASE,
388 SCANCODE_CHAR_NUMLOCK);
389 }
390 }
391
392 }
393
394
395 static void
396 update_modifier_state(uint16 modifiers, BOOL pressed)
397 {
398
399 DEBUG_KBD("Before updating modifier_state:0x%x, pressed=0x%x\n",
400 remote_modifier_state, pressed);
401 switch (modifiers)
402 {
403 case SCANCODE_CHAR_LSHIFT:
404 MASK_CHANGE_BIT(remote_modifier_state,
405 MapLeftShiftMask, pressed);
406 break;
407 case SCANCODE_CHAR_RSHIFT:
408 MASK_CHANGE_BIT(remote_modifier_state,
409 MapRightShiftMask, pressed);
410 break;
411 case SCANCODE_CHAR_LCTRL:
412 MASK_CHANGE_BIT(remote_modifier_state,
413 MapLeftCtrlMask, pressed);
414 break;
415 case SCANCODE_CHAR_RCTRL:
416 MASK_CHANGE_BIT(remote_modifier_state,
417 MapRightCtrlMask, pressed);
418 break;
419 case SCANCODE_CHAR_LALT:
420 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask,
421 pressed);
422 break;
423 case SCANCODE_CHAR_RALT:
424 MASK_CHANGE_BIT(remote_modifier_state,
425 MapRightAltMask, pressed);
426 break;
427 case SCANCODE_CHAR_LWIN:
428 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask,
429 pressed);
430 break;
431 case SCANCODE_CHAR_RWIN:
432 MASK_CHANGE_BIT(remote_modifier_state,
433 MapRightWinMask, pressed);
434 break;
435 case SCANCODE_CHAR_NUMLOCK:
436 /* KeyReleases for NumLocks are sent immediately. Toggle the
437 modifier state only on Keypress */
438 if (pressed)
439 {
440 BOOL newNumLockState;
441 newNumLockState =
442 (MASK_HAS_BITS
443 (remote_modifier_state,
444 MapNumLockMask) == False);
445 MASK_CHANGE_BIT(remote_modifier_state,
446 MapNumLockMask,
447 newNumLockState);
448 }
449 break;
450 }
451 DEBUG_KBD("After updating modifier_state:0x%x\n",
452 remote_modifier_state);
453
454 }
455
456 /* Send keyboard input */
457 void
458 rdp_send_scancode(uint32 time, uint16 flags, uint16 scancode)
459 {
460 update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
461
462 if (scancode & SCANCODE_EXTENDED)
463 {
464 DEBUG_KBD("Sending extended scancode=0x%x, flags=0x%x\n",
465 scancode & ~SCANCODE_EXTENDED, flags);
466 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
467 scancode & ~SCANCODE_EXTENDED, 0);
468 }
469 else
470 {
471 DEBUG_KBD("Sending scancode=0x%x, flags=0x%x\n", scancode,
472 flags);
473 rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
474 }
475 }

  ViewVC Help
Powered by ViewVC 1.1.26