2
* Copyright (C) 2003 Sun Microsystems, Inc.
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License as
6
* published by the Free Software Foundation; either version 2 of the
7
* License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful, but
10
* WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20
* Mark McLoughlin <mark@skynet.ie>
23
* The keyboard and pointer handling code is borrowed from
24
* x11vnc.c in libvncserver/contrib which is:
26
* Copyright (c) 2002-2003 Karl J. Runge <runge@karlrunge.com>
28
* x11vnc.c itself is based heavily on:
29
* the originial x11vnc.c in libvncserver (Johannes E. Schindelin)
30
* krfb, the KDE desktopsharing project (Tim Jansen)
31
* x0rfbserver, the original native X vnc server (Jens Wagner)
36
#include "vino-input.h"
41
#include <X11/keysym.h>
43
#include <X11/extensions/XTest.h>
46
#include "vino-util.h"
48
/* See <X11/keysymdef.h> - "Latin 1: Byte 3 = 0"
50
#define VINO_IS_LATIN1_KEYSYM(k) ((k) != NoSymbol && ((k) & 0x0f00) == 0)
54
VINO_LEFT_SHIFT = 1 << 0,
55
VINO_RIGHT_SHIFT = 1 << 1,
59
#define VINO_LEFT_OR_RIGHT_SHIFT (VINO_LEFT_SHIFT | VINO_RIGHT_SHIFT)
65
VinoModifierState modifier_state;
66
guint8 modifiers [0x100];
67
KeyCode keycodes [0x100];
68
KeyCode left_shift_keycode;
69
KeyCode right_shift_keycode;
70
KeyCode alt_gr_keycode;
72
guint initialized : 1;
73
guint xtest_supported : 1;
76
/* Data is per-display, but we only handle a single display.
78
static VinoInputData global_input_data = { 0, };
80
/* Set up a keysym -> keycode + modifier mapping.
82
* RFB transmits the KeySym for a keypress, but we may only inject
83
* keycodes using XTest. Thus, we must ensure that the modifier
84
* state is such that the keycode we inject maps to the KeySym
85
* we received from the client.
89
vino_input_initialize_keycodes (GdkDisplay *display)
92
int min_keycodes, max_keycodes;
93
int keysyms_per_keycode;
97
xdisplay = GDK_DISPLAY_XDISPLAY (display);
99
memset (global_input_data.keycodes, 0, sizeof (global_input_data.keycodes));
100
memset (global_input_data.modifiers, -1, sizeof (global_input_data.modifiers));
102
XDisplayKeycodes (xdisplay, &min_keycodes, &max_keycodes);
104
g_assert (min_keycodes >= 8);
105
g_assert (max_keycodes <= 255);
107
keymap = XGetKeyboardMapping (xdisplay,
109
max_keycodes - min_keycodes + 1,
110
&keysyms_per_keycode);
112
g_assert (keymap != NULL);
114
dprintf (INPUT, "Initializing keysym to keycode/modifier mapping\n");
116
for (keycode = min_keycodes; keycode < max_keycodes; keycode++)
118
int keycode_index = (keycode - min_keycodes) * keysyms_per_keycode;
121
for (modifier = 0; modifier < keysyms_per_keycode; modifier++)
123
guint32 keysym = keymap [keycode_index + modifier];
125
if (VINO_IS_LATIN1_KEYSYM (keysym) &&
126
XKeysymToKeycode (xdisplay, keysym) == keycode)
128
global_input_data.keycodes [keysym] = keycode;
129
global_input_data.modifiers [keysym] = modifier;
131
dprintf (INPUT, "\t0x%.2x -> %d %d\n", keysym, keycode, modifier);
138
global_input_data.left_shift_keycode = XKeysymToKeycode (xdisplay, XK_Shift_L);
139
global_input_data.right_shift_keycode = XKeysymToKeycode (xdisplay, XK_Shift_R);
140
global_input_data.alt_gr_keycode = XKeysymToKeycode (xdisplay, XK_Mode_switch);
142
#endif /* HAVE_XTEST */
145
vino_input_init (GdkDisplay *display)
149
int ignore, *i = &ignore;
151
g_assert (global_input_data.initialized != TRUE);
153
xdisplay = GDK_DISPLAY_XDISPLAY (display);
155
if (XTestQueryExtension (xdisplay, i, i, i, i))
157
XTestGrabControl (xdisplay, True);
159
global_input_data.xtest_supported = TRUE;
162
vino_input_initialize_keycodes (display);
164
global_input_data.initialized = TRUE;
166
return global_input_data.xtest_supported;
168
return global_input_data.xtest_supported = FALSE;
169
#endif /* HAVE_XSHM */
173
vino_input_handle_pointer_event (GdkScreen *screen,
180
guint8 prev_mask = global_input_data.button_mask;
183
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
185
XTestFakeMotionEvent (xdisplay,
186
gdk_screen_get_number (screen),
190
dprintf (INPUT, "Injected motion event: %d, %d\n", x, y);
192
for (i = 0; i < 5; i++)
194
gboolean button_down = (button_mask & (1 << i)) != FALSE;
195
gboolean prev_button_down = (prev_mask & (1 << i)) != FALSE;
197
if (button_down != prev_button_down)
199
XTestFakeButtonEvent (xdisplay, i + 1, button_down, CurrentTime);
201
dprintf (INPUT, "Injected button %d %s\n",
202
i + 1, button_down ? "press" : "release");
206
global_input_data.button_mask = button_mask;
207
#endif /* HAVE_XTEST */
212
vino_input_update_modifier_state (VinoInputData *input_data,
213
VinoModifierState state,
214
guint32 check_keysym,
218
if (keysym == check_keysym)
221
input_data->modifier_state |= state;
223
input_data->modifier_state &= ~state;
228
vino_input_fake_modifier (GdkScreen *screen,
229
VinoInputData *input_data,
234
VinoModifierState modifier_state = input_data->modifier_state;
236
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
238
if ((modifier_state & VINO_LEFT_OR_RIGHT_SHIFT) && modifier != 1)
240
dprintf (INPUT, "Shift is down, but we don't want it to be\n");
242
if (modifier_state & VINO_LEFT_SHIFT)
243
XTestFakeKeyEvent (xdisplay,
244
input_data->left_shift_keycode,
248
if (modifier_state & VINO_RIGHT_SHIFT)
249
XTestFakeKeyEvent (xdisplay,
250
input_data->right_shift_keycode,
255
if (!(modifier_state & VINO_LEFT_OR_RIGHT_SHIFT) && modifier == 1)
257
dprintf (INPUT, "Shift isn't down, but we want it to be\n");
259
XTestFakeKeyEvent (xdisplay,
260
input_data->left_shift_keycode,
265
if ((modifier_state & VINO_ALT_GR) && modifier != 2)
267
dprintf (INPUT, "Alt is down, but we don't want it to be\n");
269
XTestFakeKeyEvent (xdisplay,
270
input_data->alt_gr_keycode,
275
if (!(modifier_state & VINO_ALT_GR) && modifier == 2)
277
dprintf (INPUT, "Alt isn't down, but we want it to be\n");
279
XTestFakeKeyEvent (xdisplay,
280
input_data->alt_gr_keycode,
285
#endif /* HAVE_XTEST */
288
vino_input_handle_key_event (GdkScreen *screen,
295
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
297
vino_input_update_modifier_state (&global_input_data,
298
VINO_LEFT_SHIFT, XK_Shift_L,
301
vino_input_update_modifier_state (&global_input_data,
302
VINO_RIGHT_SHIFT, XK_Shift_R,
305
vino_input_update_modifier_state (&global_input_data,
306
VINO_ALT_GR, XK_Mode_switch,
309
if (VINO_IS_LATIN1_KEYSYM (keysym))
311
KeyCode keycode = global_input_data.keycodes [keysym];
312
guint8 modifier = global_input_data.modifiers [keysym];
314
if (keycode != NoSymbol)
317
vino_input_fake_modifier (screen, &global_input_data, modifier, TRUE);
319
dprintf (INPUT, "Injecting keysym 0x%.2x %s (keycode %d, modifier %d)\n",
320
keysym, key_press ? "press" : "release", keycode, modifier);
322
XTestFakeKeyEvent (xdisplay, keycode, key_press, CurrentTime);
325
vino_input_fake_modifier (screen, &global_input_data, modifier, FALSE);
332
if ((keycode = XKeysymToKeycode (xdisplay, keysym)) != NoSymbol)
334
dprintf (INPUT, "Injecting keysym 0x%.2x %s (keycode %d)\n",
335
keysym, key_press ? "press" : "release", keycode);
337
XTestFakeKeyEvent (xdisplay, keycode, key_press, CurrentTime);
340
#endif /* HAVE_XTEST */
344
vino_input_handle_clipboard_event (GdkScreen *screen,