~ubuntu-branches/ubuntu/dapper/rdesktop/dapper

« back to all changes in this revision

Viewing changes to xkeymap.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Johnston
  • Date: 2004-02-04 17:52:26 UTC
  • Revision ID: james.westby@ubuntu.com-20040204175226-87kz4bzs1nimji68
Tags: upstream-1.3.1
ImportĀ upstreamĀ versionĀ 1.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   rdesktop: A Remote Desktop Protocol client.
 
3
   User interface services - X keyboard mapping
 
4
 
 
5
   Copyright (C) Matthew Chapman 1999-2002
 
6
   Copyright (C) Peter Astrand <peter@cendio.se> 2003
 
7
   
 
8
   This program is free software; you can redistribute it and/or modify
 
9
   it under the terms of the GNU General Public License as published by
 
10
   the Free Software Foundation; either version 2 of the License, or
 
11
   (at your option) any later version.
 
12
   
 
13
   This program is distributed in the hope that it will be useful,
 
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
   GNU General Public License for more details.
 
17
 
 
18
   You should have received a copy of the GNU General Public License
 
19
   along with this program; if not, write to the Free Software
 
20
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
21
*/
 
22
 
 
23
#ifdef RDP2VNC
 
24
#include "vnc/x11stubs.h"
 
25
#else
 
26
#include <X11/Xlib.h>
 
27
#include <X11/keysym.h>
 
28
#endif
 
29
 
 
30
#include <ctype.h>
 
31
#include <limits.h>
 
32
#include <time.h>
 
33
#include "rdesktop.h"
 
34
#include "scancodes.h"
 
35
 
 
36
#define KEYMAP_SIZE 0xffff+1
 
37
#define KEYMAP_MASK 0xffff
 
38
#define KEYMAP_MAX_LINE_LENGTH 80
 
39
 
 
40
extern Display *g_display;
 
41
extern Window g_wnd;
 
42
extern char keymapname[16];
 
43
extern int keylayout;
 
44
extern int g_win_button_size;
 
45
extern BOOL g_enable_compose;
 
46
extern BOOL g_use_rdp5;
 
47
extern BOOL g_numlock_sync;
 
48
 
 
49
static BOOL keymap_loaded;
 
50
static key_translation keymap[KEYMAP_SIZE];
 
51
static int min_keycode;
 
52
static uint16 remote_modifier_state = 0;
 
53
static uint16 saved_remote_modifier_state = 0;
 
54
 
 
55
static void update_modifier_state(uint8 scancode, BOOL pressed);
 
56
 
 
57
static void
 
58
add_to_keymap(char *keyname, uint8 scancode, uint16 modifiers, char *mapname)
 
59
{
 
60
        KeySym keysym;
 
61
 
 
62
        keysym = XStringToKeysym(keyname);
 
63
        if (keysym == NoSymbol)
 
64
        {
 
65
                DEBUG_KBD(("Bad keysym \"%s\" in keymap %s (ignoring)\n", keyname, mapname));
 
66
                return;
 
67
        }
 
68
 
 
69
        DEBUG_KBD(("Adding translation, keysym=0x%x, scancode=0x%x, "
 
70
                   "modifiers=0x%x\n", (unsigned int) keysym, scancode, modifiers));
 
71
 
 
72
        keymap[keysym & KEYMAP_MASK].scancode = scancode;
 
73
        keymap[keysym & KEYMAP_MASK].modifiers = modifiers;
 
74
 
 
75
        return;
 
76
}
 
77
 
 
78
 
 
79
static BOOL
 
80
xkeymap_read(char *mapname)
 
81
{
 
82
        FILE *fp;
 
83
        char line[KEYMAP_MAX_LINE_LENGTH];
 
84
        char path[PATH_MAX], inplace_path[PATH_MAX];
 
85
        unsigned int line_num = 0;
 
86
        unsigned int line_length = 0;
 
87
        char *keyname, *p;
 
88
        char *line_rest;
 
89
        uint8 scancode;
 
90
        uint16 modifiers;
 
91
 
 
92
 
 
93
        strcpy(path, KEYMAP_PATH);
 
94
        strncat(path, mapname, sizeof(path) - sizeof(KEYMAP_PATH));
 
95
 
 
96
        fp = fopen(path, "r");
 
97
        if (fp == NULL)
 
98
        {
 
99
                /* in case we are running from the source tree */
 
100
                strcpy(inplace_path, "keymaps/");
 
101
                strncat(inplace_path, mapname, sizeof(inplace_path) - sizeof("keymaps/"));
 
102
 
 
103
                fp = fopen(inplace_path, "r");
 
104
                if (fp == NULL)
 
105
                {
 
106
                        error("Failed to open keymap %s\n", path);
 
107
                        return False;
 
108
                }
 
109
        }
 
110
 
 
111
        /* FIXME: More tolerant on white space */
 
112
        while (fgets(line, sizeof(line), fp) != NULL)
 
113
        {
 
114
                line_num++;
 
115
 
 
116
                /* Replace the \n with \0 */
 
117
                p = strchr(line, '\n');
 
118
                if (p != NULL)
 
119
                        *p = 0;
 
120
 
 
121
                line_length = strlen(line);
 
122
 
 
123
                /* Completely empty line */
 
124
                if (strspn(line, " \t\n\r\f\v") == line_length)
 
125
                {
 
126
                        continue;
 
127
                }
 
128
 
 
129
                /* Include */
 
130
                if (strncmp(line, "include ", 8) == 0)
 
131
                {
 
132
                        if (!xkeymap_read(line + 8))
 
133
                                return False;
 
134
                        continue;
 
135
                }
 
136
 
 
137
                /* map */
 
138
                if (strncmp(line, "map ", 4) == 0)
 
139
                {
 
140
                        keylayout = strtol(line + 4, NULL, 16);
 
141
                        DEBUG_KBD(("Keylayout 0x%x\n", keylayout));
 
142
                        continue;
 
143
                }
 
144
 
 
145
                /* compose */
 
146
                if (strncmp(line, "enable_compose", 15) == 0)
 
147
                {
 
148
                        DEBUG_KBD(("Enabling compose handling\n"));
 
149
                        g_enable_compose = True;
 
150
                        continue;
 
151
                }
 
152
 
 
153
                /* Comment */
 
154
                if (line[0] == '#')
 
155
                {
 
156
                        continue;
 
157
                }
 
158
 
 
159
                /* Normal line */
 
160
                keyname = line;
 
161
                p = strchr(line, ' ');
 
162
                if (p == NULL)
 
163
                {
 
164
                        error("Bad line %d in keymap %s\n", line_num, mapname);
 
165
                        continue;
 
166
                }
 
167
                else
 
168
                {
 
169
                        *p = 0;
 
170
                }
 
171
 
 
172
                /* scancode */
 
173
                p++;
 
174
                scancode = strtol(p, &line_rest, 16);
 
175
 
 
176
                /* flags */
 
177
                /* FIXME: Should allow case-insensitive flag names. 
 
178
                   Fix by using lex+yacc... */
 
179
                modifiers = 0;
 
180
                if (strstr(line_rest, "altgr"))
 
181
                {
 
182
                        MASK_ADD_BITS(modifiers, MapAltGrMask);
 
183
                }
 
184
 
 
185
                if (strstr(line_rest, "shift"))
 
186
                {
 
187
                        MASK_ADD_BITS(modifiers, MapLeftShiftMask);
 
188
                }
 
189
 
 
190
                if (strstr(line_rest, "numlock"))
 
191
                {
 
192
                        MASK_ADD_BITS(modifiers, MapNumLockMask);
 
193
                }
 
194
 
 
195
                if (strstr(line_rest, "localstate"))
 
196
                {
 
197
                        MASK_ADD_BITS(modifiers, MapLocalStateMask);
 
198
                }
 
199
 
 
200
                if (strstr(line_rest, "inhibit"))
 
201
                {
 
202
                        MASK_ADD_BITS(modifiers, MapInhibitMask);
 
203
                }
 
204
 
 
205
                add_to_keymap(keyname, scancode, modifiers, mapname);
 
206
 
 
207
                if (strstr(line_rest, "addupper"))
 
208
                {
 
209
                        /* Automatically add uppercase key, with same modifiers 
 
210
                           plus shift */
 
211
                        for (p = keyname; *p; p++)
 
212
                                *p = toupper((int) *p);
 
213
                        MASK_ADD_BITS(modifiers, MapLeftShiftMask);
 
214
                        add_to_keymap(keyname, scancode, modifiers, mapname);
 
215
                }
 
216
        }
 
217
 
 
218
        fclose(fp);
 
219
        return True;
 
220
}
 
221
 
 
222
 
 
223
/* Before connecting and creating UI */
 
224
void
 
225
xkeymap_init(void)
 
226
{
 
227
        unsigned int max_keycode;
 
228
        char *mapname_ptr;
 
229
 
 
230
        /* Make keymapname lowercase */
 
231
        mapname_ptr = keymapname;
 
232
        while (*mapname_ptr)
 
233
        {
 
234
                *mapname_ptr = tolower((int) *mapname_ptr);
 
235
                mapname_ptr++;
 
236
        }
 
237
 
 
238
        if (strcmp(keymapname, "none"))
 
239
        {
 
240
                if (xkeymap_read(keymapname))
 
241
                        keymap_loaded = True;
 
242
        }
 
243
 
 
244
        XDisplayKeycodes(g_display, &min_keycode, (int *) &max_keycode);
 
245
}
 
246
 
 
247
static void
 
248
send_winkey(uint32 ev_time, BOOL pressed, BOOL leftkey)
 
249
{
 
250
        uint8 winkey;
 
251
 
 
252
        if (leftkey)
 
253
                winkey = SCANCODE_CHAR_LWIN;
 
254
        else
 
255
                winkey = SCANCODE_CHAR_RWIN;
 
256
 
 
257
        if (pressed)
 
258
        {
 
259
                if (g_use_rdp5)
 
260
                {
 
261
                        rdp_send_scancode(ev_time, RDP_KEYPRESS, winkey);
 
262
                }
 
263
                else
 
264
                {
 
265
                        /* RDP4 doesn't support winkey. Fake with Ctrl-Esc */
 
266
                        rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LCTRL);
 
267
                        rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_ESC);
 
268
                }
 
269
        }
 
270
        else
 
271
        {
 
272
                /* key released */
 
273
                if (g_use_rdp5)
 
274
                {
 
275
                        rdp_send_scancode(ev_time, RDP_KEYRELEASE, winkey);
 
276
                }
 
277
                else
 
278
                {
 
279
                        rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_ESC);
 
280
                        rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
 
281
                }
 
282
        }
 
283
}
 
284
 
 
285
static void
 
286
reset_winkey(uint32 ev_time)
 
287
{
 
288
        if (g_use_rdp5)
 
289
        {
 
290
                /* For some reason, it seems to suffice to release
 
291
                 *either* the left or right winkey. */
 
292
                rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LWIN);
 
293
        }
 
294
}
 
295
 
 
296
/* Handles, for example, multi-scancode keypresses (which is not
 
297
   possible via keymap-files) */
 
298
BOOL
 
299
handle_special_keys(uint32 keysym, unsigned int state, uint32 ev_time, BOOL pressed)
 
300
{
 
301
        switch (keysym)
 
302
        {
 
303
                case XK_Return:
 
304
                        if ((get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R))
 
305
                            && (get_key_state(state, XK_Control_L)
 
306
                                || get_key_state(state, XK_Control_R)))
 
307
                        {
 
308
                                /* Ctrl-Alt-Enter: toggle full screen */
 
309
                                if (pressed)
 
310
                                        xwin_toggle_fullscreen();
 
311
                                return True;
 
312
                        }
 
313
                        break;
 
314
 
 
315
                case XK_Break:
 
316
                        /* Send Break sequence E0 46 E0 C6 */
 
317
                        if (pressed)
 
318
                        {
 
319
                                rdp_send_scancode(ev_time, RDP_KEYPRESS,
 
320
                                                  (SCANCODE_EXTENDED | 0x46));
 
321
                                rdp_send_scancode(ev_time, RDP_KEYPRESS,
 
322
                                                  (SCANCODE_EXTENDED | 0xc6));
 
323
                        }
 
324
                        /* No release sequence */
 
325
                        return True;
 
326
                        break;
 
327
 
 
328
                case XK_Pause:
 
329
                        /* According to MS Keyboard Scan Code
 
330
                           Specification, pressing Pause should result
 
331
                           in E1 1D 45 E1 9D C5. I'm not exactly sure
 
332
                           of how this is supposed to be sent via
 
333
                           RDP. The code below seems to work, but with
 
334
                           the side effect that Left Ctrl stays
 
335
                           down. Therefore, we release it when Pause
 
336
                           is released. */
 
337
                        if (pressed)
 
338
                        {
 
339
                                rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
 
340
                                rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x1d, 0);
 
341
                                rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x45, 0);
 
342
                                rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xe1, 0);
 
343
                                rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0x9d, 0);
 
344
                                rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYPRESS, 0xc5, 0);
 
345
                        }
 
346
                        else
 
347
                        {
 
348
                                /* Release Left Ctrl */
 
349
                                rdp_send_input(ev_time, RDP_INPUT_SCANCODE, RDP_KEYRELEASE,
 
350
                                               0x1d, 0);
 
351
                        }
 
352
                        return True;
 
353
                        break;
 
354
 
 
355
                case XK_Meta_L: /* Windows keys */
 
356
                case XK_Super_L:
 
357
                case XK_Hyper_L:
 
358
                        send_winkey(ev_time, pressed, True);
 
359
                        return True;
 
360
                        break;
 
361
 
 
362
                case XK_Meta_R:
 
363
                case XK_Super_R:
 
364
                case XK_Hyper_R:
 
365
                        send_winkey(ev_time, pressed, False);
 
366
                        return True;
 
367
                        break;
 
368
 
 
369
                case XK_space:
 
370
                        /* Prevent access to the Windows system menu in single app mode */
 
371
                        if (g_win_button_size
 
372
                            && (get_key_state(state, XK_Alt_L) || get_key_state(state, XK_Alt_R)))
 
373
                                return True;
 
374
                        break;
 
375
                case XK_Num_Lock:
 
376
                        /* FIXME: We might want to do RDP_INPUT_SYNCHRONIZE here, if g_numlock_sync */
 
377
                        if (!g_numlock_sync)
 
378
                                /* Inhibit */
 
379
                                return True;
 
380
                        break;
 
381
 
 
382
        }
 
383
        return False;
 
384
}
 
385
 
 
386
 
 
387
key_translation
 
388
xkeymap_translate_key(uint32 keysym, unsigned int keycode, unsigned int state)
 
389
{
 
390
        key_translation tr = { 0, 0 };
 
391
 
 
392
        tr = keymap[keysym & KEYMAP_MASK];
 
393
 
 
394
        if (tr.modifiers & MapInhibitMask)
 
395
        {
 
396
                DEBUG_KBD(("Inhibiting key\n"));
 
397
                tr.scancode = 0;
 
398
                return tr;
 
399
        }
 
400
 
 
401
        if (tr.modifiers & MapLocalStateMask)
 
402
        {
 
403
                /* The modifiers to send for this key should be obtained
 
404
                   from the local state. Currently, only shift is implemented. */
 
405
                if (state & ShiftMask)
 
406
                {
 
407
                        tr.modifiers = MapLeftShiftMask;
 
408
                }
 
409
        }
 
410
 
 
411
        if (tr.scancode != 0)
 
412
        {
 
413
                DEBUG_KBD(("Found key translation, scancode=0x%x, modifiers=0x%x\n",
 
414
                           tr.scancode, tr.modifiers));
 
415
                return tr;
 
416
        }
 
417
 
 
418
        if (keymap_loaded)
 
419
                warning("No translation for (keysym 0x%lx, %s)\n", keysym, get_ksname(keysym));
 
420
 
 
421
        /* not in keymap, try to interpret the raw scancode */
 
422
        if (((int) keycode >= min_keycode) && (keycode <= 0x60))
 
423
        {
 
424
                tr.scancode = keycode - min_keycode;
 
425
 
 
426
                /* The modifiers to send for this key should be
 
427
                   obtained from the local state. Currently, only
 
428
                   shift is implemented. */
 
429
                if (state & ShiftMask)
 
430
                {
 
431
                        tr.modifiers = MapLeftShiftMask;
 
432
                }
 
433
 
 
434
                DEBUG_KBD(("Sending guessed scancode 0x%x\n", tr.scancode));
 
435
        }
 
436
        else
 
437
        {
 
438
                DEBUG_KBD(("No good guess for keycode 0x%x found\n", keycode));
 
439
        }
 
440
 
 
441
        return tr;
 
442
}
 
443
 
 
444
uint16
 
445
xkeymap_translate_button(unsigned int button)
 
446
{
 
447
        switch (button)
 
448
        {
 
449
                case Button1:   /* left */
 
450
                        return MOUSE_FLAG_BUTTON1;
 
451
                case Button2:   /* middle */
 
452
                        return MOUSE_FLAG_BUTTON3;
 
453
                case Button3:   /* right */
 
454
                        return MOUSE_FLAG_BUTTON2;
 
455
                case Button4:   /* wheel up */
 
456
                        return MOUSE_FLAG_BUTTON4;
 
457
                case Button5:   /* wheel down */
 
458
                        return MOUSE_FLAG_BUTTON5;
 
459
        }
 
460
 
 
461
        return 0;
 
462
}
 
463
 
 
464
char *
 
465
get_ksname(uint32 keysym)
 
466
{
 
467
        char *ksname = NULL;
 
468
 
 
469
        if (keysym == NoSymbol)
 
470
                ksname = "NoSymbol";
 
471
        else if (!(ksname = XKeysymToString(keysym)))
 
472
                ksname = "(no name)";
 
473
 
 
474
        return ksname;
 
475
}
 
476
 
 
477
static BOOL
 
478
is_modifier(uint8 scancode)
 
479
{
 
480
        switch (scancode)
 
481
        {
 
482
                case SCANCODE_CHAR_LSHIFT:
 
483
                case SCANCODE_CHAR_RSHIFT:
 
484
                case SCANCODE_CHAR_LCTRL:
 
485
                case SCANCODE_CHAR_RCTRL:
 
486
                case SCANCODE_CHAR_LALT:
 
487
                case SCANCODE_CHAR_RALT:
 
488
                case SCANCODE_CHAR_LWIN:
 
489
                case SCANCODE_CHAR_RWIN:
 
490
                case SCANCODE_CHAR_NUMLOCK:
 
491
                        return True;
 
492
                default:
 
493
                        break;
 
494
        }
 
495
        return False;
 
496
}
 
497
 
 
498
void
 
499
save_remote_modifiers(uint8 scancode)
 
500
{
 
501
        if (is_modifier(scancode))
 
502
                return;
 
503
 
 
504
        saved_remote_modifier_state = remote_modifier_state;
 
505
}
 
506
 
 
507
void
 
508
restore_remote_modifiers(uint32 ev_time, uint8 scancode)
 
509
{
 
510
        key_translation dummy;
 
511
 
 
512
        if (is_modifier(scancode))
 
513
                return;
 
514
 
 
515
        dummy.scancode = 0;
 
516
        dummy.modifiers = saved_remote_modifier_state;
 
517
        ensure_remote_modifiers(ev_time, dummy);
 
518
}
 
519
 
 
520
void
 
521
ensure_remote_modifiers(uint32 ev_time, key_translation tr)
 
522
{
 
523
        /* If this key is a modifier, do nothing */
 
524
        if (is_modifier(tr.scancode))
 
525
                return;
 
526
 
 
527
        if (!g_numlock_sync)
 
528
        {
 
529
                /* NumLock */
 
530
                if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask)
 
531
                    != MASK_HAS_BITS(remote_modifier_state, MapNumLockMask))
 
532
                {
 
533
                        /* The remote modifier state is not correct */
 
534
                        uint16 new_remote_state;
 
535
 
 
536
                        if (MASK_HAS_BITS(tr.modifiers, MapNumLockMask))
 
537
                        {
 
538
                                DEBUG_KBD(("Remote NumLock state is incorrect, activating NumLock.\n"));
 
539
                                new_remote_state = KBD_FLAG_NUMLOCK;
 
540
                                remote_modifier_state = MapNumLockMask;
 
541
                        }
 
542
                        else
 
543
                        {
 
544
                                DEBUG_KBD(("Remote NumLock state is incorrect, deactivating NumLock.\n"));
 
545
                                new_remote_state = 0;
 
546
                                remote_modifier_state = 0;
 
547
                        }
 
548
 
 
549
                        rdp_send_input(0, RDP_INPUT_SYNCHRONIZE, 0, new_remote_state, 0);
 
550
                }
 
551
        }
 
552
 
 
553
 
 
554
        /* Shift. Left shift and right shift are treated as equal; either is fine. */
 
555
        if (MASK_HAS_BITS(tr.modifiers, MapShiftMask)
 
556
            != MASK_HAS_BITS(remote_modifier_state, MapShiftMask))
 
557
        {
 
558
                /* The remote modifier state is not correct */
 
559
                if (MASK_HAS_BITS(tr.modifiers, MapLeftShiftMask))
 
560
                {
 
561
                        /* Needs left shift. Send down. */
 
562
                        rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_LSHIFT);
 
563
                }
 
564
                else if (MASK_HAS_BITS(tr.modifiers, MapRightShiftMask))
 
565
                {
 
566
                        /* Needs right shift. Send down. */
 
567
                        rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RSHIFT);
 
568
                }
 
569
                else
 
570
                {
 
571
                        /* Should not use this modifier. Send up for shift currently pressed. */
 
572
                        if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask))
 
573
                                /* Left shift is down */
 
574
                                rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
 
575
                        else
 
576
                                /* Right shift is down */
 
577
                                rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
 
578
                }
 
579
        }
 
580
 
 
581
        /* AltGr */
 
582
        if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask)
 
583
            != MASK_HAS_BITS(remote_modifier_state, MapAltGrMask))
 
584
        {
 
585
                /* The remote modifier state is not correct */
 
586
                if (MASK_HAS_BITS(tr.modifiers, MapAltGrMask))
 
587
                {
 
588
                        /* Needs this modifier. Send down. */
 
589
                        rdp_send_scancode(ev_time, RDP_KEYPRESS, SCANCODE_CHAR_RALT);
 
590
                }
 
591
                else
 
592
                {
 
593
                        /* Should not use this modifier. Send up. */
 
594
                        rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
 
595
                }
 
596
        }
 
597
 
 
598
 
 
599
}
 
600
 
 
601
 
 
602
unsigned int
 
603
read_keyboard_state()
 
604
{
 
605
        unsigned int state;
 
606
        Window wdummy;
 
607
        int dummy;
 
608
 
 
609
        XQueryPointer(g_display, g_wnd, &wdummy, &wdummy, &dummy, &dummy, &dummy, &dummy, &state);
 
610
        return state;
 
611
}
 
612
 
 
613
 
 
614
uint16
 
615
ui_get_numlock_state(unsigned int state)
 
616
{
 
617
        uint16 numlock_state = 0;
 
618
 
 
619
        if (get_key_state(state, XK_Num_Lock))
 
620
                numlock_state = KBD_FLAG_NUMLOCK;
 
621
 
 
622
        return numlock_state;
 
623
}
 
624
 
 
625
 
 
626
void
 
627
reset_modifier_keys()
 
628
{
 
629
        unsigned int state = read_keyboard_state();
 
630
 
 
631
        /* reset keys */
 
632
        uint32 ev_time;
 
633
        ev_time = time(NULL);
 
634
 
 
635
        if (MASK_HAS_BITS(remote_modifier_state, MapLeftShiftMask)
 
636
            && !get_key_state(state, XK_Shift_L))
 
637
                rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LSHIFT);
 
638
 
 
639
        if (MASK_HAS_BITS(remote_modifier_state, MapRightShiftMask)
 
640
            && !get_key_state(state, XK_Shift_R))
 
641
                rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RSHIFT);
 
642
 
 
643
        if (MASK_HAS_BITS(remote_modifier_state, MapLeftCtrlMask)
 
644
            && !get_key_state(state, XK_Control_L))
 
645
                rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LCTRL);
 
646
 
 
647
        if (MASK_HAS_BITS(remote_modifier_state, MapRightCtrlMask)
 
648
            && !get_key_state(state, XK_Control_R))
 
649
                rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RCTRL);
 
650
 
 
651
        if (MASK_HAS_BITS(remote_modifier_state, MapLeftAltMask) && !get_key_state(state, XK_Alt_L))
 
652
                rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_LALT);
 
653
 
 
654
        if (MASK_HAS_BITS(remote_modifier_state, MapRightAltMask) &&
 
655
            !get_key_state(state, XK_Alt_R) && !get_key_state(state, XK_Mode_switch))
 
656
                rdp_send_scancode(ev_time, RDP_KEYRELEASE, SCANCODE_CHAR_RALT);
 
657
 
 
658
        reset_winkey(ev_time);
 
659
 
 
660
        if (g_numlock_sync)
 
661
                rdp_send_input(ev_time, RDP_INPUT_SYNCHRONIZE, 0, ui_get_numlock_state(state), 0);
 
662
}
 
663
 
 
664
 
 
665
static void
 
666
update_modifier_state(uint8 scancode, BOOL pressed)
 
667
{
 
668
#ifdef WITH_DEBUG_KBD
 
669
        uint16 old_modifier_state;
 
670
 
 
671
        old_modifier_state = remote_modifier_state;
 
672
#endif
 
673
 
 
674
        switch (scancode)
 
675
        {
 
676
                case SCANCODE_CHAR_LSHIFT:
 
677
                        MASK_CHANGE_BIT(remote_modifier_state, MapLeftShiftMask, pressed);
 
678
                        break;
 
679
                case SCANCODE_CHAR_RSHIFT:
 
680
                        MASK_CHANGE_BIT(remote_modifier_state, MapRightShiftMask, pressed);
 
681
                        break;
 
682
                case SCANCODE_CHAR_LCTRL:
 
683
                        MASK_CHANGE_BIT(remote_modifier_state, MapLeftCtrlMask, pressed);
 
684
                        break;
 
685
                case SCANCODE_CHAR_RCTRL:
 
686
                        MASK_CHANGE_BIT(remote_modifier_state, MapRightCtrlMask, pressed);
 
687
                        break;
 
688
                case SCANCODE_CHAR_LALT:
 
689
                        MASK_CHANGE_BIT(remote_modifier_state, MapLeftAltMask, pressed);
 
690
                        break;
 
691
                case SCANCODE_CHAR_RALT:
 
692
                        MASK_CHANGE_BIT(remote_modifier_state, MapRightAltMask, pressed);
 
693
                        break;
 
694
                case SCANCODE_CHAR_LWIN:
 
695
                        MASK_CHANGE_BIT(remote_modifier_state, MapLeftWinMask, pressed);
 
696
                        break;
 
697
                case SCANCODE_CHAR_RWIN:
 
698
                        MASK_CHANGE_BIT(remote_modifier_state, MapRightWinMask, pressed);
 
699
                        break;
 
700
                case SCANCODE_CHAR_NUMLOCK:
 
701
                        /* KeyReleases for NumLocks are sent immediately. Toggle the
 
702
                           modifier state only on Keypress */
 
703
                        if (pressed && !g_numlock_sync)
 
704
                        {
 
705
                                BOOL newNumLockState;
 
706
                                newNumLockState =
 
707
                                        (MASK_HAS_BITS
 
708
                                         (remote_modifier_state, MapNumLockMask) == False);
 
709
                                MASK_CHANGE_BIT(remote_modifier_state,
 
710
                                                MapNumLockMask, newNumLockState);
 
711
                        }
 
712
        }
 
713
 
 
714
#ifdef WITH_DEBUG_KBD
 
715
        if (old_modifier_state != remote_modifier_state)
 
716
        {
 
717
                DEBUG_KBD(("Before updating modifier_state:0x%x, pressed=0x%x\n",
 
718
                           old_modifier_state, pressed));
 
719
                DEBUG_KBD(("After updating modifier_state:0x%x\n", remote_modifier_state));
 
720
        }
 
721
#endif
 
722
 
 
723
}
 
724
 
 
725
/* Send keyboard input */
 
726
void
 
727
rdp_send_scancode(uint32 time, uint16 flags, uint8 scancode)
 
728
{
 
729
        update_modifier_state(scancode, !(flags & RDP_KEYRELEASE));
 
730
 
 
731
        if (scancode & SCANCODE_EXTENDED)
 
732
        {
 
733
                DEBUG_KBD(("Sending extended scancode=0x%x, flags=0x%x\n",
 
734
                           scancode & ~SCANCODE_EXTENDED, flags));
 
735
                rdp_send_input(time, RDP_INPUT_SCANCODE, flags | KBD_FLAG_EXT,
 
736
                               scancode & ~SCANCODE_EXTENDED, 0);
 
737
        }
 
738
        else
 
739
        {
 
740
                DEBUG_KBD(("Sending scancode=0x%x, flags=0x%x\n", scancode, flags));
 
741
                rdp_send_input(time, RDP_INPUT_SCANCODE, flags, scancode, 0);
 
742
        }
 
743
}