~ubuntu-branches/ubuntu/dapper/vino/dapper

« back to all changes in this revision

Viewing changes to server/vino-input.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2004-10-12 19:36:40 UTC
  • Revision ID: james.westby@ubuntu.com-20041012193640-ybetkwuqt7e04dke
Tags: upstream-2.8.1
ImportĀ upstreamĀ versionĀ 2.8.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2003 Sun Microsystems, Inc.
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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
 
17
 * 02111-1307, USA.
 
18
 *
 
19
 * Authors:
 
20
 *      Mark McLoughlin <mark@skynet.ie>
 
21
 *
 
22
 *
 
23
 *   The keyboard and pointer handling code is borrowed from
 
24
 *   x11vnc.c in libvncserver/contrib which is:
 
25
 *
 
26
 *     Copyright (c) 2002-2003 Karl J. Runge <runge@karlrunge.com>
 
27
 *
 
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)
 
32
 */
 
33
 
 
34
#include <config.h>
 
35
 
 
36
#include "vino-input.h"
 
37
 
 
38
#include <string.h>
 
39
#include <gdk/gdkx.h>
 
40
#include <X11/Xlib.h>
 
41
#include <X11/keysym.h>
 
42
#ifdef HAVE_XTEST
 
43
#include <X11/extensions/XTest.h>
 
44
#endif
 
45
 
 
46
#include "vino-util.h"
 
47
 
 
48
/* See <X11/keysymdef.h> - "Latin 1: Byte 3 = 0"
 
49
 */
 
50
#define VINO_IS_LATIN1_KEYSYM(k) ((k) != NoSymbol && ((k) & 0x0f00) == 0)
 
51
 
 
52
typedef enum
 
53
{
 
54
  VINO_LEFT_SHIFT  = 1 << 0,
 
55
  VINO_RIGHT_SHIFT = 1 << 1,
 
56
  VINO_ALT_GR      = 1 << 2
 
57
} VinoModifierState;
 
58
 
 
59
#define VINO_LEFT_OR_RIGHT_SHIFT (VINO_LEFT_SHIFT | VINO_RIGHT_SHIFT)
 
60
 
 
61
typedef struct
 
62
{
 
63
  guint8            button_mask;
 
64
 
 
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;
 
71
 
 
72
  guint             initialized : 1;
 
73
  guint             xtest_supported : 1;
 
74
} VinoInputData;
 
75
 
 
76
/* Data is per-display, but we only handle a single display.
 
77
 */
 
78
static VinoInputData global_input_data = { 0, };
 
79
 
 
80
/* Set up a keysym -> keycode + modifier mapping.
 
81
 *
 
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.
 
86
 */
 
87
#ifdef HAVE_XTEST
 
88
static void
 
89
vino_input_initialize_keycodes (GdkDisplay *display)
 
90
{
 
91
  Display *xdisplay;
 
92
  int      min_keycodes, max_keycodes;
 
93
  int      keysyms_per_keycode;
 
94
  KeySym  *keymap;
 
95
  int      keycode;
 
96
 
 
97
  xdisplay = GDK_DISPLAY_XDISPLAY (display);
 
98
 
 
99
  memset (global_input_data.keycodes,   0, sizeof (global_input_data.keycodes));
 
100
  memset (global_input_data.modifiers, -1, sizeof (global_input_data.modifiers));
 
101
 
 
102
  XDisplayKeycodes (xdisplay, &min_keycodes, &max_keycodes);
 
103
 
 
104
  g_assert (min_keycodes >= 8);
 
105
  g_assert (max_keycodes <= 255);
 
106
 
 
107
  keymap = XGetKeyboardMapping (xdisplay,
 
108
                                min_keycodes,
 
109
                                max_keycodes - min_keycodes + 1,
 
110
                                &keysyms_per_keycode);
 
111
 
 
112
  g_assert (keymap != NULL);
 
113
 
 
114
  dprintf (INPUT, "Initializing keysym to keycode/modifier mapping\n");
 
115
 
 
116
  for (keycode = min_keycodes; keycode < max_keycodes; keycode++)
 
117
    {
 
118
      int    keycode_index = (keycode - min_keycodes) * keysyms_per_keycode;
 
119
      guint8 modifier;
 
120
 
 
121
      for (modifier = 0; modifier < keysyms_per_keycode; modifier++)
 
122
        {
 
123
          guint32 keysym = keymap [keycode_index + modifier];
 
124
 
 
125
          if (VINO_IS_LATIN1_KEYSYM (keysym) &&
 
126
              XKeysymToKeycode (xdisplay, keysym) == keycode)
 
127
            {
 
128
              global_input_data.keycodes  [keysym] = keycode;
 
129
              global_input_data.modifiers [keysym] = modifier;
 
130
 
 
131
              dprintf (INPUT, "\t0x%.2x -> %d %d\n", keysym, keycode, modifier);
 
132
            }
 
133
        }
 
134
    }
 
135
 
 
136
  XFree (keymap);
 
137
 
 
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);
 
141
}
 
142
#endif /* HAVE_XTEST */
 
143
 
 
144
gboolean
 
145
vino_input_init (GdkDisplay *display)
 
146
{
 
147
#ifdef HAVE_XTEST
 
148
  Display *xdisplay;
 
149
  int      ignore, *i = &ignore;
 
150
 
 
151
  g_assert (global_input_data.initialized != TRUE);
 
152
 
 
153
  xdisplay = GDK_DISPLAY_XDISPLAY (display);
 
154
 
 
155
  if (XTestQueryExtension (xdisplay, i, i, i, i))
 
156
    {
 
157
      XTestGrabControl (xdisplay, True);
 
158
 
 
159
      global_input_data.xtest_supported = TRUE;
 
160
    }
 
161
 
 
162
  vino_input_initialize_keycodes (display);
 
163
 
 
164
  global_input_data.initialized = TRUE;
 
165
 
 
166
  return global_input_data.xtest_supported;
 
167
#else
 
168
  return global_input_data.xtest_supported = FALSE;
 
169
#endif /* HAVE_XSHM */
 
170
}
 
171
 
 
172
void
 
173
vino_input_handle_pointer_event (GdkScreen *screen,
 
174
                                 guint8     button_mask,
 
175
                                 guint16    x,
 
176
                                 guint16    y)
 
177
{
 
178
#ifdef HAVE_XTEST
 
179
  Display *xdisplay;
 
180
  guint8   prev_mask = global_input_data.button_mask;
 
181
  int      i;
 
182
 
 
183
  xdisplay = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
 
184
 
 
185
  XTestFakeMotionEvent (xdisplay,
 
186
                        gdk_screen_get_number (screen),
 
187
                        x, y,
 
188
                        CurrentTime);
 
189
  
 
190
  dprintf (INPUT, "Injected motion event: %d, %d\n", x, y);
 
191
 
 
192
  for (i = 0; i < 5; i++)
 
193
    {
 
194
      gboolean button_down      = (button_mask & (1 << i)) != FALSE;
 
195
      gboolean prev_button_down = (prev_mask   & (1 << i)) != FALSE;
 
196
 
 
197
      if (button_down != prev_button_down)
 
198
        {
 
199
          XTestFakeButtonEvent (xdisplay, i + 1, button_down, CurrentTime);
 
200
          
 
201
          dprintf (INPUT, "Injected button %d %s\n",
 
202
                   i + 1, button_down ? "press" : "release");
 
203
        }
 
204
    }
 
205
 
 
206
  global_input_data.button_mask = button_mask;
 
207
#endif /* HAVE_XTEST */
 
208
}
 
209
 
 
210
#ifdef HAVE_XTEST
 
211
static inline void
 
212
vino_input_update_modifier_state (VinoInputData    *input_data,
 
213
                                  VinoModifierState state,
 
214
                                  guint32           check_keysym,
 
215
                                  guint32           keysym,
 
216
                                  gboolean          key_press)
 
217
{
 
218
  if (keysym == check_keysym)
 
219
    {
 
220
      if (key_press)
 
221
        input_data->modifier_state |= state;
 
222
      else
 
223
        input_data->modifier_state &= ~state;
 
224
    }
 
225
}
 
226
 
 
227
static void
 
228
vino_input_fake_modifier (GdkScreen         *screen,
 
229
                          VinoInputData     *input_data,
 
230
                          guint8             modifier,
 
231
                          gboolean           key_press)
 
232
{
 
233
  Display           *xdisplay;
 
234
  VinoModifierState  modifier_state = input_data->modifier_state;
 
235
 
 
236
  xdisplay = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
 
237
 
 
238
  if ((modifier_state & VINO_LEFT_OR_RIGHT_SHIFT) && modifier != 1)
 
239
    {
 
240
      dprintf (INPUT, "Shift is down, but we don't want it to be\n");
 
241
 
 
242
      if (modifier_state & VINO_LEFT_SHIFT)
 
243
        XTestFakeKeyEvent (xdisplay,
 
244
                           input_data->left_shift_keycode,
 
245
                           !key_press,
 
246
                           CurrentTime);
 
247
      
 
248
      if (modifier_state & VINO_RIGHT_SHIFT)
 
249
        XTestFakeKeyEvent (xdisplay,
 
250
                           input_data->right_shift_keycode,
 
251
                           !key_press,
 
252
                           CurrentTime);
 
253
    }
 
254
 
 
255
  if (!(modifier_state & VINO_LEFT_OR_RIGHT_SHIFT) && modifier == 1)
 
256
    {
 
257
      dprintf (INPUT, "Shift isn't down, but we want it to be\n");
 
258
 
 
259
      XTestFakeKeyEvent (xdisplay,
 
260
                         input_data->left_shift_keycode,
 
261
                         key_press,
 
262
                         CurrentTime);
 
263
    }
 
264
      
 
265
  if ((modifier_state & VINO_ALT_GR) && modifier != 2)
 
266
    {
 
267
      dprintf (INPUT, "Alt is down, but we don't want it to be\n");
 
268
 
 
269
      XTestFakeKeyEvent (xdisplay,
 
270
                         input_data->alt_gr_keycode,
 
271
                         !key_press,
 
272
                         CurrentTime);
 
273
    }
 
274
      
 
275
  if (!(modifier_state & VINO_ALT_GR) && modifier == 2)
 
276
    {
 
277
      dprintf (INPUT, "Alt isn't down, but we want it to be\n");
 
278
 
 
279
      XTestFakeKeyEvent (xdisplay,
 
280
                         input_data->alt_gr_keycode,
 
281
                         key_press,
 
282
                         CurrentTime);
 
283
    }
 
284
}
 
285
#endif /* HAVE_XTEST */
 
286
 
 
287
void
 
288
vino_input_handle_key_event (GdkScreen *screen,
 
289
                             guint32    keysym,
 
290
                             gboolean   key_press)
 
291
{
 
292
#ifdef HAVE_XTEST
 
293
  Display *xdisplay;
 
294
  
 
295
  xdisplay = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen));
 
296
  
 
297
  vino_input_update_modifier_state (&global_input_data,
 
298
                                    VINO_LEFT_SHIFT, XK_Shift_L,
 
299
                                    keysym, key_press);
 
300
 
 
301
  vino_input_update_modifier_state (&global_input_data,
 
302
                                    VINO_RIGHT_SHIFT, XK_Shift_R,
 
303
                                    keysym, key_press);
 
304
 
 
305
  vino_input_update_modifier_state (&global_input_data,
 
306
                                    VINO_ALT_GR, XK_Mode_switch,
 
307
                                    keysym, key_press);
 
308
 
 
309
  if (VINO_IS_LATIN1_KEYSYM (keysym))
 
310
    {
 
311
      KeyCode keycode  = global_input_data.keycodes [keysym];
 
312
      guint8  modifier = global_input_data.modifiers [keysym];
 
313
 
 
314
      if (keycode != NoSymbol)
 
315
        {
 
316
          if (key_press)
 
317
            vino_input_fake_modifier (screen, &global_input_data, modifier, TRUE);
 
318
 
 
319
          dprintf (INPUT, "Injecting keysym 0x%.2x %s (keycode %d, modifier %d)\n",
 
320
                   keysym, key_press ? "press" : "release", keycode, modifier);
 
321
 
 
322
          XTestFakeKeyEvent (xdisplay, keycode, key_press, CurrentTime);
 
323
 
 
324
          if (key_press)
 
325
            vino_input_fake_modifier (screen, &global_input_data, modifier, FALSE);
 
326
        }
 
327
    }
 
328
  else
 
329
    {
 
330
      KeyCode keycode;
 
331
 
 
332
      if ((keycode = XKeysymToKeycode (xdisplay, keysym)) != NoSymbol)
 
333
        {
 
334
          dprintf (INPUT, "Injecting keysym 0x%.2x %s (keycode %d)\n",
 
335
                   keysym, key_press ? "press" : "release", keycode);
 
336
 
 
337
          XTestFakeKeyEvent (xdisplay, keycode, key_press, CurrentTime);
 
338
        }
 
339
    }
 
340
#endif /* HAVE_XTEST */
 
341
}
 
342
 
 
343
void
 
344
vino_input_handle_clipboard_event (GdkScreen *screen,
 
345
                                   char      *text,
 
346
                                   int        len)
 
347
{
 
348
}