/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 212 - (hide annotations)
Sun Oct 6 13:25:30 2002 UTC (21 years, 7 months ago) by matthewc
File MIME type: text/plain
File size: 14691 byte(s)
On Solaris Break is Shift-Pause not Alt-Pause - so when checking for
Ctrl-Alt-Break, accept both Break and Pause and check state of Ctrl
and Alt.

1 matthewc 38 /*
2     rdesktop: A Remote Desktop Protocol client.
3     User interface services - X keyboard mapping
4 matthewc 207 Copyright (C) Matthew Chapman 1999-2002
5 matthewc 38
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 matthewc 190 #define XK_MISCELLANY
23     #include <X11/keysymdef.h>
24 astrand 66 #include <ctype.h>
25 matthewc 39 #include <limits.h>
26 matthewc 190 #include <time.h>
27 matthewc 38 #include "rdesktop.h"
28 astrand 66 #include "scancodes.h"
29 matthewc 38
30     #define KEYMAP_SIZE 4096
31     #define KEYMAP_MASK (KEYMAP_SIZE - 1)
32 astrand 66 #define KEYMAP_MAX_LINE_LENGTH 80
33 matthewc 38
34 matthewc 50 extern Display *display;
35 matthewc 38 extern char keymapname[16];
36     extern int keylayout;
37 astrand 70 extern BOOL enable_compose;
38 matthewc 38
39 matthewc 205 static BOOL keymap_loaded;
40 astrand 66 static key_translation keymap[KEYMAP_SIZE];
41 astrand 73 static int min_keycode;
42 astrand 66 static uint16 remote_modifier_state = 0;
43 matthewc 38
44 matthewc 203 static void update_modifier_state(uint8 scancode, BOOL pressed);
45 astrand 115
46 astrand 66 static void
47     add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
48     {
49     KeySym keysym;
50    
51     keysym = XStringToKeysym(keyname);
52     if (keysym == NoSymbol)
53     {
54     error("Bad keysym %s in keymap %s\n", keyname, mapname);
55     return;
56     }
57    
58 astrand 84 DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
59     "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
60 astrand 66
61     keymap[keysym & KEYMAP_MASK].scancode = scancode;
62     keymap[keysym & KEYMAP_MASK].modifiers = modifiers;
63    
64     return;
65     }
66    
67    
68 astrand 64 static BOOL
69     xkeymap_read(char *mapname)
70 matthewc 38 {
71     FILE *fp;
72 astrand 66 char line[KEYMAP_MAX_LINE_LENGTH], path[PATH_MAX];
73     unsigned int line_num = 0;
74     unsigned int line_length = 0;
75 matthewc 38 char *keyname, *p;
76 astrand 66 char *line_rest;
77     uint8 scancode;
78     uint16 modifiers;
79 matthewc 38
80 astrand 66
81 matthewc 38 strcpy(path, KEYMAP_PATH);
82     strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));
83    
84     fp = fopen(path, "r");
85     if (fp == NULL)
86     {
87     error("Failed to open keymap %s\n", path);
88     return False;
89     }
90    
91 astrand 66 /* FIXME: More tolerant on white space */
92 matthewc 38 while (fgets(line, sizeof(line), fp) != NULL)
93     {
94 astrand 66 line_num++;
95    
96     /* Replace the \n with \0 */
97 matthewc 38 p = strchr(line, '\n');
98     if (p != NULL)
99     *p = 0;
100    
101 astrand 66 line_length = strlen(line);
102    
103     /* Completely empty line */
104     if (strspn(line, " \t\n\r\f\v") == line_length)
105 matthewc 38 {
106 astrand 66 continue;
107     }
108 matthewc 38
109 astrand 66 /* Include */
110     if (strncmp(line, "include ", 8) == 0)
111 matthewc 38 {
112 astrand 64 if (!xkeymap_read(line + 8))
113 matthewc 38 return False;
114 astrand 66 continue;
115 matthewc 38 }
116 astrand 66
117     /* map */
118     if (strncmp(line, "map ", 4) == 0)
119 matthewc 38 {
120 astrand 64 keylayout = strtol(line + 4, NULL, 16);
121 astrand 84 DEBUG_KBD(("Keylayout 0x%x\n", keylayout));
122 astrand 66 continue;
123 matthewc 38 }
124 astrand 66
125 astrand 70 /* compose */
126     if (strncmp(line, "enable_compose", 15) == 0)
127     {
128 astrand 84 DEBUG_KBD(("Enabling compose handling\n"));
129 astrand 70 enable_compose = True;
130     continue;
131     }
132    
133 astrand 66 /* Comment */
134     if (line[0] == '#')
135 matthewc 38 {
136 astrand 66 continue;
137 matthewc 38 }
138 astrand 66
139     /* Normal line */
140     keyname = line;
141     p = strchr(line, ' ');
142     if (p == NULL)
143     {
144 astrand 82 error("Bad line %d in keymap %s\n", line_num, mapname);
145 astrand 66 continue;
146     }
147     else
148     {
149     *p = 0;
150     }
151    
152     /* scancode */
153     p++;
154     scancode = strtol(p, &line_rest, 16);
155    
156     /* flags */
157     /* FIXME: Should allow case-insensitive flag names.
158     Fix by using lex+yacc... */
159     modifiers = 0;
160     if (strstr(line_rest, "altgr"))
161     {
162     MASK_ADD_BITS(modifiers, MapAltGrMask);
163     }
164    
165     if (strstr(line_rest, "shift"))
166     {
167     MASK_ADD_BITS(modifiers, MapLeftShiftMask);
168     }
169    
170     if (strstr(line_rest, "numlock"))
171     {
172     MASK_ADD_BITS(modifiers, MapNumLockMask);
173     }
174    
175 astrand 69 if (strstr(line_rest, "localstate"))
176     {
177     MASK_ADD_BITS(modifiers, MapLocalStateMask);
178     }
179    
180 astrand 116 if (strstr(line_rest, "inhibit"))
181     {
182     MASK_ADD_BITS(modifiers, MapInhibitMask);
183     }
184    
185 astrand 66 add_to_keymap(keyname, scancode, modifiers, mapname);
186    
187     if (strstr(line_rest, "addupper"))
188     {
189     /* Automatically add uppercase key, with same modifiers
190     plus shift */
191     for (p = keyname; *p; p++)
192     *p = toupper(*p);
193     MASK_ADD_BITS(modifiers, MapLeftShiftMask);
194     add_to_keymap(keyname, scancode, modifiers, mapname);
195     }
196 matthewc 38 }
197    
198     fclose(fp);
199     return True;
200     }
201    
202 astrand 66
203     /* Before connecting and creating UI */
204 astrand 64 void
205 matthewc 121 xkeymap_init(void)
206 matthewc 38 {
207 matthewc 121 unsigned int max_keycode;
208 matthewc 38
209     if (strcmp(keymapname, "none"))
210 matthewc 205 {
211     if (xkeymap_read(keymapname))
212     keymap_loaded = True;
213     }
214 astrand 66
215 astrand 77 XDisplayKeycodes(display, &min_keycode, (int *) &max_keycode);
216 astrand 66 }
217 matthewc 38
218 astrand 118 /* Handles, for example, multi-scancode keypresses (which is not
219     possible via keymap-files) */
220     BOOL
221 matthewc 203 handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
222 astrand 118 {
223     switch (keysym)
224     {
225 astrand 199 case XK_Break:
226 matthewc 212 case XK_Pause:
227     if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
228     && (get_key_state(state, XK_Control_L) || get_key_state(state, XK_Control_R)))
229 astrand 118 {
230 matthewc 212 /* Ctrl-Alt-Break: toggle full screen */
231 matthewc 193 if (pressed)
232     xwin_toggle_fullscreen();
233 astrand 199
234 astrand 118 }
235 matthewc 212 else if (keysym == XK_Break)
236 astrand 199 {
237     /* Send Break sequence E0 46 E0 C6 */
238     if (pressed)
239     {
240     rdp_send_scancode(ev_time, RDP_KEYPRESS,
241     (SCANCODE_EXTENDED | 0x46));
242     rdp_send_scancode(ev_time, RDP_KEYPRESS,
243     (SCANCODE_EXTENDED | 0xc6));
244     }
245     /* No break sequence */
246     }
247 matthewc 212 else /* XK_Pause */
248 astrand 197 {
249 matthewc 212 /* According to MS Keyboard Scan Code
250     Specification, pressing Pause should result
251     in E1 1D 45 E1 9D C5. I'm not exactly sure
252     of how this is supposed to be sent via
253     RDP. The code below seems to work, but with
254     the side effect that Left Ctrl stays
255     down. Therefore, we release it when Pause
256     is released. */
257     if (pressed)
258     {
259     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
260     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
261     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
262     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
263     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
264     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
265     }
266     else
267     {
268     /* Release Left Ctrl */
269     rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE, 0x1d,
270     0);
271     }
272 astrand 197 }
273     return True;
274    
275 astrand 118 case XK_Meta_L: /* Windows keys */
276     case XK_Super_L:
277     case XK_Hyper_L:
278     case XK_Meta_R:
279     case XK_Super_R:
280     case XK_Hyper_R:
281     if (pressed)
282     {
283     rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
284     rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
285     }
286     else
287     {
288     rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
289     rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
290     }
291     return True;
292     }
293     return False;
294     }
295    
296    
297 astrand 66 key_translation
298 matthewc 190 xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
299 astrand 66 {
300     key_translation tr = { 0, 0 };
301    
302     tr = keymap[keysym & KEYMAP_MASK];
303    
304 astrand 116 if (tr.modifiers & MapInhibitMask)
305     {
306     DEBUG_KBD(("Inhibiting key\n"));
307     tr.scancode = 0;
308     return tr;
309     }
310    
311 astrand 69 if (tr.modifiers & MapLocalStateMask)
312     {
313     /* The modifiers to send for this key should be obtained
314     from the local state. Currently, only shift is implemented. */
315     if (state & ShiftMask)
316     {
317     tr.modifiers = MapLeftShiftMask;
318     }
319     }
320    
321 astrand 66 if (tr.scancode != 0)
322 matthewc 50 {
323 matthewc 190 DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",
324 astrand 197 tr.scancode, tr.modifiers));
325 astrand 66 return tr;
326 matthewc 50 }
327    
328 matthewc 205 if (keymap_loaded)
329     error("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));
330 astrand 66
331 matthewc 38 /* not in keymap, try to interpret the raw scancode */
332     if ((keycode >= min_keycode) && (keycode <= 0x60))
333     {
334 astrand 66 tr.scancode = keycode - min_keycode;
335 astrand 165
336     /* The modifiers to send for this key should be
337     obtained from the local state. Currently, only
338     shift is implemented. */
339     if (state & ShiftMask)
340     {
341     tr.modifiers = MapLeftShiftMask;
342     }
343    
344 matthewc 190 DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
345 matthewc 38 }
346 astrand 66 else
347     {
348 matthewc 190 DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
349 astrand 66 }
350 matthewc 38
351 astrand 66 return tr;
352 matthewc 38 }
353    
354 astrand 64 uint16
355     xkeymap_translate_button(unsigned int button)
356 matthewc 38 {
357     switch (button)
358     {
359 astrand 64 case Button1: /* left */
360 matthewc 38 return MOUSE_FLAG_BUTTON1;
361 astrand 64 case Button2: /* middle */
362 matthewc 38 return MOUSE_FLAG_BUTTON3;
363 astrand 64 case Button3: /* right */
364 matthewc 38 return MOUSE_FLAG_BUTTON2;
365 jsorg71 67 case Button4: /* wheel up */
366     return MOUSE_FLAG_BUTTON4;
367     case Button5: /* wheel down */
368     return MOUSE_FLAG_BUTTON5;
369 matthewc 38 }
370    
371     return 0;
372     }
373 astrand 66
374     char *
375 matthewc 190 get_ksname(uint32 keysym)
376 astrand 66 {
377     char *ksname = NULL;
378    
379     if (keysym == NoSymbol)
380     ksname = "NoSymbol";
381     else if (!(ksname = XKeysymToString(keysym)))
382     ksname = "(no name)";
383    
384     return ksname;
385     }
386    
387    
388     void
389     ensure_remote_modifiers(uint32 ev_time, key_translation tr)
390     {
391     /* If this key is a modifier, do nothing */
392     switch (tr.scancode)
393     {
394     case SCANCODE_CHAR_LSHIFT:
395     case SCANCODE_CHAR_RSHIFT:
396     case SCANCODE_CHAR_LCTRL:
397     case SCANCODE_CHAR_RCTRL:
398     case SCANCODE_CHAR_LALT:
399     case SCANCODE_CHAR_RALT:
400     case SCANCODE_CHAR_LWIN:
401     case SCANCODE_CHAR_RWIN:
402     case SCANCODE_CHAR_NUMLOCK:
403     return;
404     default:
405     break;
406     }
407    
408 astrand 183 /* Shift. Left shift and right shift are treated as equal; either is fine. */
409 astrand 66 if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
410     != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
411     {
412     /* The remote modifier state is not correct */
413 astrand 183 if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
414 astrand 66 {
415 astrand 183 /* Needs left shift. Send down. */
416 astrand 82 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
417 astrand 66 }
418 astrand 183 else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
419     {
420     /* Needs right shift. Send down. */
421     rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
422     }
423 astrand 66 else
424     {
425 astrand 183 /* Should not use this modifier. Send up for shift currently pressed. */
426     if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
427     /* Left shift is down */
428     rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
429     else
430     /* Right shift is down */
431     rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
432 astrand 66 }
433     }
434    
435     /* AltGr */
436     if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
437     != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
438     {
439     /* The remote modifier state is not correct */
440     if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
441     {
442     /* Needs this modifier. Send down. */
443 astrand 82 rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
444 astrand 66 }
445     else
446     {
447     /* Should not use this modifier. Send up. */
448 astrand 82 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
449 astrand 66 }
450     }
451    
452     /* NumLock */
453     if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
454     != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
455     {
456     /* The remote modifier state is not correct */
457 astrand 115 uint16 new_remote_state = 0;
458    
459 astrand 66 if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
460     {
461 astrand 115 DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
462     new_remote_state |= KBD_FLAG_NUMLOCK;
463 astrand 66 }
464     else
465     {
466 astrand 115 DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
467 astrand 66 }
468 astrand 115
469     rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
470     update_modifier_state(SCANCODE_CHAR_NUMLOCK, True);
471 astrand 66 }
472     }
473    
474    
475 astrand 170 void
476 matthewc 203 reset_modifier_keys(unsigned int state)
477 astrand 170 {
478     /* reset keys */
479     uint32 ev_time;
480     ev_time = time(NULL);
481    
482 matthewc 203 if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask) && !get_key_state(state, XK_Shift_L))
483 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
484    
485 matthewc 203 if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask) && !get_key_state(state, XK_Shift_R))
486 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
487    
488 matthewc 203 if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask) && !get_key_state(state, XK_Control_L))
489 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
490    
491 matthewc 203 if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask) && !get_key_state(state, XK_Control_R))
492 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
493    
494 matthewc 203 if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
495 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
496    
497     if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
498 matthewc 203 !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch))
499 astrand 170 rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
500     }
501    
502    
503 astrand 66 static void
504 matthewc 203 update_modifier_state(uint8 scancode, BOOL pressed)
505 astrand 66 {
506 astrand 113 #ifdef WITH_DEBUG_KBD
507     uint16 old_modifier_state;
508 astrand 66
509 astrand 113 old_modifier_state = remote_modifier_state;
510     #endif
511    
512 matthewc 203 switch (scancode)
513 astrand 66 {
514     case SCANCODE_CHAR_LSHIFT:
515 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
516 astrand 66 break;
517     case SCANCODE_CHAR_RSHIFT:
518 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
519 astrand 66 break;
520     case SCANCODE_CHAR_LCTRL:
521 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
522 astrand 66 break;
523     case SCANCODE_CHAR_RCTRL:
524 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
525 astrand 66 break;
526     case SCANCODE_CHAR_LALT:
527 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
528 astrand 66 break;
529     case SCANCODE_CHAR_RALT:
530 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
531 astrand 66 break;
532     case SCANCODE_CHAR_LWIN:
533 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
534 astrand 66 break;
535     case SCANCODE_CHAR_RWIN:
536 astrand 82 MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
537 astrand 66 break;
538     case SCANCODE_CHAR_NUMLOCK:
539     /* KeyReleases for NumLocks are sent immediately. Toggle the
540     modifier state only on Keypress */
541     if (pressed)
542     {
543     BOOL newNumLockState;
544     newNumLockState =
545     (MASK_HAS_BITS
546 astrand 82 (remote_modifier_state, MapNumLockMask) == False);
547 astrand 66 MASK_CHANGE_BIT(remote_modifier_state,
548 astrand 82 MapNumLockMask, newNumLockState);
549 astrand 66 }
550     break;
551     }
552    
553 astrand 113 #ifdef WITH_DEBUG_KBD
554     if (old_modifier_state != remote_modifier_state)
555     {
556     DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
557     old_modifier_state, pressed));
558     DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
559     }
560     #endif
561    
562 astrand 66 }
563    
564     /* Send keyboard input */
565     void
566 matthewc 203 rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
567 astrand 66 {
568     update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
569    
570     if (scancode & SCANCODE_EXTENDED)
571     {
572 astrand 84 DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
573     scancode & ~SCANCODE_EXTENDED, flags));
574 astrand 66 rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
575     scancode & ~SCANCODE_EXTENDED, 0);
576     }
577     else
578     {
579 astrand 85 DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
580     rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
581 astrand 66 }
582     }

  ViewVC Help
Powered by ViewVC 1.1.26