]> git.sesse.net Git - rdpsrv/blobdiff - Xserver/programs/Xserver/hw/vnc/kbdptr.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / hw / vnc / kbdptr.c
diff --git a/Xserver/programs/Xserver/hw/vnc/kbdptr.c b/Xserver/programs/Xserver/hw/vnc/kbdptr.c
new file mode 100644 (file)
index 0000000..707755d
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ * kbdptr.c - deal with keyboard and pointer device over TCP & UDP.
+ *
+ *
+ */
+
+/*
+ *  Copyright (C) 2002-2003 RealVNC Ltd.
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ *  This is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This software is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this software; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *  USA.
+ */
+
+#include <stdio.h>
+
+#include "X11/X.h"
+#define NEED_EVENTS
+#include "X11/Xproto.h"
+#include "inputstr.h"
+#define XK_CYRILLIC
+#include <X11/keysym.h>
+#include <mi.h>
+#include <mipointer.h>
+#include <property.h>
+#include <Xatom.h>
+#include "rfb.h"
+
+extern WindowPtr *WindowTable; /* Why isn't this in a header file? */
+
+#define KEY_IS_PRESSED(keycode) \
+    (kbdDevice->key->down[(keycode) >> 3] & (1 << ((keycode) & 7)))
+
+
+static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper);
+
+static DeviceIntPtr kbdDevice;
+
+#define MIN_KEY_CODE           8
+#define MAX_KEY_CODE           255
+#define NO_OF_KEYS             (MAX_KEY_CODE - MIN_KEY_CODE + 1)
+#define GLYPHS_PER_KEY         2
+
+static KeySym kbdMap[] = {
+
+    /* Modifiers */
+
+    XK_Control_L,      NoSymbol,
+#define CONTROL_L_KEY_CODE     MIN_KEY_CODE
+
+    XK_Control_R,      NoSymbol,
+#define CONTROL_R_KEY_CODE     (MIN_KEY_CODE + 1)
+
+    XK_Shift_L,                NoSymbol,
+#define SHIFT_L_KEY_CODE       (MIN_KEY_CODE + 2)
+
+    XK_Shift_R,                NoSymbol,
+#define SHIFT_R_KEY_CODE       (MIN_KEY_CODE + 3)
+
+    XK_Meta_L,         NoSymbol,
+#define META_L_KEY_CODE                (MIN_KEY_CODE + 4)
+
+    XK_Meta_R,         NoSymbol,
+#define META_R_KEY_CODE                (MIN_KEY_CODE + 5)
+
+    XK_Alt_L,          NoSymbol,
+#define ALT_L_KEY_CODE         (MIN_KEY_CODE + 6)
+
+    XK_Alt_R,          NoSymbol,
+#define ALT_R_KEY_CODE         (MIN_KEY_CODE + 7)
+
+    /* Standard US keyboard */
+
+    XK_space,          NoSymbol,
+    XK_0,              XK_parenright,
+    XK_1,              XK_exclam,
+    XK_2,              XK_at,
+    XK_3,              XK_numbersign,
+    XK_4,              XK_dollar,
+    XK_5,              XK_percent,
+    XK_6,              XK_asciicircum,
+    XK_7,              XK_ampersand,
+    XK_8,              XK_asterisk,
+    XK_9,              XK_parenleft,
+
+    XK_minus,          XK_underscore,
+    XK_equal,          XK_plus,
+    XK_bracketleft,    XK_braceleft,
+    XK_bracketright,   XK_braceright,
+    XK_semicolon,      XK_colon,
+    XK_apostrophe,     XK_quotedbl,
+    XK_grave,          XK_asciitilde,
+    XK_comma,          XK_less,
+    XK_period,         XK_greater,
+    XK_slash,          XK_question,
+    XK_backslash,      XK_bar,
+
+    XK_a,              XK_A,
+    XK_b,              XK_B,
+    XK_c,              XK_C,
+    XK_d,              XK_D,
+    XK_e,              XK_E,
+    XK_f,              XK_F,
+    XK_g,              XK_G,
+    XK_h,              XK_H,
+    XK_i,              XK_I,
+    XK_j,              XK_J,
+    XK_k,              XK_K,
+    XK_l,              XK_L,
+    XK_m,              XK_M,
+    XK_n,              XK_N,
+    XK_o,              XK_O,
+    XK_p,              XK_P,
+    XK_q,              XK_Q,
+    XK_r,              XK_R,
+    XK_s,              XK_S,
+    XK_t,              XK_T,
+    XK_u,              XK_U,
+    XK_v,              XK_V,
+    XK_w,              XK_W,
+    XK_x,              XK_X,
+    XK_y,              XK_Y,
+    XK_z,              XK_Z,
+
+    /* Other useful keys */
+
+    XK_BackSpace,      NoSymbol,
+    XK_Return,         NoSymbol,
+    XK_Tab,            NoSymbol,
+    XK_Escape,         NoSymbol,
+    XK_Delete,         NoSymbol,
+
+    XK_Home,           NoSymbol,
+    XK_End,            NoSymbol,
+    XK_Page_Up,                NoSymbol,
+    XK_Page_Down,      NoSymbol,
+    XK_Up,             NoSymbol,
+    XK_Down,           NoSymbol,
+    XK_Left,           NoSymbol,
+    XK_Right,          NoSymbol,
+
+    XK_F1,             NoSymbol,
+    XK_F2,             NoSymbol,
+    XK_F3,             NoSymbol,
+    XK_F4,             NoSymbol,
+    XK_F5,             NoSymbol,
+    XK_F6,             NoSymbol,
+    XK_F7,             NoSymbol,
+    XK_F8,             NoSymbol,
+    XK_F9,             NoSymbol,
+    XK_F10,            NoSymbol,
+    XK_F11,            NoSymbol,
+    XK_F12,            NoSymbol,
+
+    /* Plus blank ones which can be filled in using xmodmap */
+
+};
+
+#define N_PREDEFINED_KEYS (sizeof(kbdMap) / (sizeof(KeySym) * GLYPHS_PER_KEY))
+
+
+void
+PtrDeviceInit()
+{
+}
+
+
+void
+KbdDeviceInit(pDevice, pKeySyms, pModMap)
+    DeviceIntPtr pDevice;
+    KeySymsPtr pKeySyms;
+    CARD8 *pModMap;
+{
+    int i;
+
+    kbdDevice = pDevice;
+
+    for (i = 0; i < MAP_LENGTH; i++)
+       pModMap[i] = NoSymbol;
+
+    pModMap[CONTROL_L_KEY_CODE] = ControlMask;
+    pModMap[CONTROL_R_KEY_CODE] = ControlMask;
+    pModMap[SHIFT_L_KEY_CODE] = ShiftMask;
+    pModMap[SHIFT_R_KEY_CODE] = ShiftMask;
+    pModMap[META_L_KEY_CODE] = Mod1Mask;
+    pModMap[META_R_KEY_CODE] = Mod1Mask;
+    pModMap[ALT_L_KEY_CODE] = Mod1Mask;
+    pModMap[ALT_R_KEY_CODE] = Mod1Mask;
+
+    pKeySyms->minKeyCode = MIN_KEY_CODE;
+    pKeySyms->maxKeyCode = MAX_KEY_CODE;
+    pKeySyms->mapWidth = GLYPHS_PER_KEY;
+
+    pKeySyms->map = (KeySym *)xalloc(sizeof(KeySym)
+                                    * MAP_LENGTH * GLYPHS_PER_KEY);
+
+    if (!pKeySyms->map) {
+       rfbLog("xalloc failed\n");
+       exit(1);
+    }
+
+    for (i = 0; i < MAP_LENGTH * GLYPHS_PER_KEY; i++)
+       pKeySyms->map[i] = NoSymbol;
+
+    for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) {
+       pKeySyms->map[i] = kbdMap[i];
+    }
+}
+
+
+
+void
+KbdDeviceOn()
+{
+}
+
+
+void
+KbdDeviceOff()
+{
+}
+
+
+void
+PtrDeviceOn(pDev)
+    DeviceIntPtr pDev;
+{
+}
+
+
+void
+PtrDeviceOff()
+{
+}
+
+
+void
+PtrDeviceControl(dev, ctrl)
+    DevicePtr dev;
+    PtrCtrl *ctrl;
+{
+}
+
+
+void
+KbdAddEvent(down, keySym, cl)
+    Bool down;
+    KeySym keySym;
+    rfbClientPtr cl;
+{
+    xEvent ev, fake;
+    KeySymsPtr keySyms = &kbdDevice->key->curKeySyms;
+    int i;
+    int keyCode = 0;
+    int freeIndex = -1;
+    unsigned long time;
+    Bool fakeShiftPress = FALSE;
+    Bool fakeShiftLRelease = FALSE;
+    Bool fakeShiftRRelease = FALSE;
+    Bool shiftMustBeReleased = FALSE;
+    Bool shiftMustBePressed = FALSE;
+
+    if (cl) {
+       CARD32 clientId = cl->sock;
+       ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER,
+                            32, PropModeReplace, 1, (pointer)&clientId, TRUE);
+    }
+
+    if (down) {
+        if (rfbTrace) rfbLog("KeyPress: 0x%x\n",keySym);
+       ev.u.u.type = KeyPress;
+    } else {
+       ev.u.u.type = KeyRelease;
+    }
+
+    /* First check if it's one of our predefined keys.  If so then we can make
+       some attempt at allowing an xmodmap inside a VNC desktop behave
+       something like you'd expect - e.g. if keys A & B are swapped over and
+       the VNC client sends an A, then map it to a B when generating the X
+       event.  We don't attempt to do this for keycodes which we make up on the
+       fly because it's too hard... */
+
+    for (i = 0; i < N_PREDEFINED_KEYS * GLYPHS_PER_KEY; i++) {
+       if (keySym == kbdMap[i]) {
+           keyCode = MIN_KEY_CODE + i / GLYPHS_PER_KEY;
+
+           if (kbdMap[(i/GLYPHS_PER_KEY) * GLYPHS_PER_KEY + 1] != NoSymbol) {
+
+               /* this keycode has more than one symbol associated with it,
+                  so shift state is important */
+
+               if ((i % GLYPHS_PER_KEY) == 0)
+                   shiftMustBeReleased = TRUE;
+               else
+                   shiftMustBePressed = TRUE;
+           }
+           break;
+       }
+    }
+
+    if (!keyCode) {
+
+       /* not one of our predefined keys - see if it's in the current keyboard
+           mapping (i.e. we've already allocated an extra keycode for it) */
+
+       if (keySyms->mapWidth < 2) {
+           rfbLog("KbdAddEvent: Sanity check failed - Keyboard mapping has "
+                  "less than 2 keysyms per keycode (KeySym 0x%x)\n", keySym);
+           return;
+       }
+
+       for (i = 0; i < NO_OF_KEYS * keySyms->mapWidth; i++) {
+           if (keySym == keySyms->map[i]) {
+               keyCode = MIN_KEY_CODE + i / keySyms->mapWidth;
+
+               if (keySyms->map[(i / keySyms->mapWidth)
+                                       * keySyms->mapWidth + 1] != NoSymbol) {
+
+                   /* this keycode has more than one symbol associated with
+                      it, so shift state is important */
+
+                   if ((i % keySyms->mapWidth) == 0)
+                       shiftMustBeReleased = TRUE;
+                   else
+                       shiftMustBePressed = TRUE;
+               }
+               break;
+           }
+           if ((freeIndex == -1) && (keySyms->map[i] == NoSymbol)
+               && (i % keySyms->mapWidth) == 0)
+           {
+               freeIndex = i;
+           }
+       }
+    }
+
+    if (!keyCode) {
+       KeySym lower, upper;
+
+       /* we don't have an existing keycode - make one up on the fly and add
+          it to the keyboard mapping.  Thanks to Vlad Harchev for pointing
+          out problems with non-ascii capitalisation. */
+
+       if (freeIndex == -1) {
+           rfbLog("KbdAddEvent: ignoring KeySym 0x%x - no free KeyCodes\n",
+                  keySym);
+           return;
+       }
+
+       keyCode = MIN_KEY_CODE + freeIndex / keySyms->mapWidth;
+
+       XConvertCase(keySym, &lower, &upper);
+
+       if (lower == upper) {
+           keySyms->map[freeIndex] = keySym;
+
+       } else {
+           keySyms->map[freeIndex] = lower;
+           keySyms->map[freeIndex+1] = upper;
+
+           if (keySym == lower)
+               shiftMustBeReleased = TRUE;
+           else
+               shiftMustBePressed = TRUE;
+       }
+
+       SendMappingNotify(MappingKeyboard, keyCode, 1, serverClient);
+
+       rfbLog("KbdAddEvent: unknown KeySym 0x%x - allocating KeyCode %d\n",
+              keySym, keyCode);
+    }
+
+    time = GetTimeInMillis();
+
+    if (down) {
+       if (shiftMustBePressed && !(kbdDevice->key->state & ShiftMask)) {
+           fakeShiftPress = TRUE;
+           fake.u.u.type = KeyPress;
+           fake.u.u.detail = SHIFT_L_KEY_CODE;
+           fake.u.keyButtonPointer.time = time;
+           mieqEnqueue(&fake);
+       }
+       if (shiftMustBeReleased && (kbdDevice->key->state & ShiftMask)) {
+           if (KEY_IS_PRESSED(SHIFT_L_KEY_CODE)) {
+               fakeShiftLRelease = TRUE;
+               fake.u.u.type = KeyRelease;
+               fake.u.u.detail = SHIFT_L_KEY_CODE;
+               fake.u.keyButtonPointer.time = time;
+               mieqEnqueue(&fake);
+           }
+           if (KEY_IS_PRESSED(SHIFT_R_KEY_CODE)) {
+               fakeShiftRRelease = TRUE;
+               fake.u.u.type = KeyRelease;
+               fake.u.u.detail = SHIFT_R_KEY_CODE;
+               fake.u.keyButtonPointer.time = time;
+               mieqEnqueue(&fake);
+           }
+       }
+    }
+
+    ev.u.u.detail = keyCode;
+    ev.u.keyButtonPointer.time = time;
+    mieqEnqueue(&ev);
+
+    if (fakeShiftPress) {
+       fake.u.u.type = KeyRelease;
+       fake.u.u.detail = SHIFT_L_KEY_CODE;
+       fake.u.keyButtonPointer.time = time;
+       mieqEnqueue(&fake);
+    }
+    if (fakeShiftLRelease) {
+       fake.u.u.type = KeyPress;
+       fake.u.u.detail = SHIFT_L_KEY_CODE;
+       fake.u.keyButtonPointer.time = time;
+       mieqEnqueue(&fake);
+    }
+    if (fakeShiftRRelease) {
+       fake.u.u.type = KeyPress;
+       fake.u.u.detail = SHIFT_R_KEY_CODE;
+       fake.u.keyButtonPointer.time = time;
+       mieqEnqueue(&fake);
+    }
+}
+
+void
+PtrAddEvent(buttonMask, x, y, cl)
+    int buttonMask;
+    int x;
+    int y;
+    rfbClientPtr cl;
+{
+    xEvent ev;
+    int i;
+    unsigned long time;
+    static int oldButtonMask = 0;
+
+    if (cl) {
+       CARD32 clientId = cl->sock;
+       ChangeWindowProperty(WindowTable[0], VNC_LAST_CLIENT_ID, XA_INTEGER,
+                            32, PropModeReplace, 1, (pointer)&clientId, TRUE);
+    }
+
+    time = GetTimeInMillis();
+
+    miPointerAbsoluteCursor(x, y, time);
+
+    for (i = 0; i < 5; i++) {
+       if ((buttonMask ^ oldButtonMask) & (1<<i)) {
+           if (buttonMask & (1<<i)) {
+               ev.u.u.type = ButtonPress;
+               ev.u.u.detail = i + 1;
+               ev.u.keyButtonPointer.time = time;
+               mieqEnqueue(&ev);
+           } else {
+               ev.u.u.type = ButtonRelease;
+               ev.u.u.detail = i + 1;
+               ev.u.keyButtonPointer.time = time;
+               mieqEnqueue(&ev);
+           }
+       }
+    }
+
+    oldButtonMask = buttonMask;
+}
+
+void
+KbdReleaseAllKeys()
+{
+    int i, j;
+    xEvent ev;
+    unsigned long time = GetTimeInMillis();
+
+    for (i = 0; i < DOWN_LENGTH; i++) {
+       if (kbdDevice->key->down[i] != 0) {
+           for (j = 0; j < 8; j++) {
+               if (kbdDevice->key->down[i] & (1 << j)) {
+                   ev.u.u.type = KeyRelease;
+                   ev.u.u.detail = (i << 3) | j;
+                   ev.u.keyButtonPointer.time = time;
+                   mieqEnqueue(&ev);
+               }
+           }
+       }
+    }
+}
+
+
+/* copied from Xlib source */
+
+static void XConvertCase(KeySym sym, KeySym *lower, KeySym *upper)
+{
+    *lower = sym;
+    *upper = sym;
+    switch(sym >> 8) {
+    case 0: /* Latin 1 */
+       if ((sym >= XK_A) && (sym <= XK_Z))
+           *lower += (XK_a - XK_A);
+       else if ((sym >= XK_a) && (sym <= XK_z))
+           *upper -= (XK_a - XK_A);
+       else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
+           *lower += (XK_agrave - XK_Agrave);
+       else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
+           *upper -= (XK_agrave - XK_Agrave);
+       else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
+           *lower += (XK_oslash - XK_Ooblique);
+       else if ((sym >= XK_oslash) && (sym <= XK_thorn))
+           *upper -= (XK_oslash - XK_Ooblique);
+       break;
+    case 1: /* Latin 2 */
+       /* Assume the KeySym is a legal value (ignore discontinuities) */
+       if (sym == XK_Aogonek)
+           *lower = XK_aogonek;
+       else if (sym >= XK_Lstroke && sym <= XK_Sacute)
+           *lower += (XK_lstroke - XK_Lstroke);
+       else if (sym >= XK_Scaron && sym <= XK_Zacute)
+           *lower += (XK_scaron - XK_Scaron);
+       else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
+           *lower += (XK_zcaron - XK_Zcaron);
+       else if (sym == XK_aogonek)
+           *upper = XK_Aogonek;
+       else if (sym >= XK_lstroke && sym <= XK_sacute)
+           *upper -= (XK_lstroke - XK_Lstroke);
+       else if (sym >= XK_scaron && sym <= XK_zacute)
+           *upper -= (XK_scaron - XK_Scaron);
+       else if (sym >= XK_zcaron && sym <= XK_zabovedot)
+           *upper -= (XK_zcaron - XK_Zcaron);
+       else if (sym >= XK_Racute && sym <= XK_Tcedilla)
+           *lower += (XK_racute - XK_Racute);
+       else if (sym >= XK_racute && sym <= XK_tcedilla)
+           *upper -= (XK_racute - XK_Racute);
+       break;
+    case 2: /* Latin 3 */
+       /* Assume the KeySym is a legal value (ignore discontinuities) */
+       if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
+           *lower += (XK_hstroke - XK_Hstroke);
+       else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
+           *lower += (XK_gbreve - XK_Gbreve);
+       else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
+           *upper -= (XK_hstroke - XK_Hstroke);
+       else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
+           *upper -= (XK_gbreve - XK_Gbreve);
+       else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
+           *lower += (XK_cabovedot - XK_Cabovedot);
+       else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
+           *upper -= (XK_cabovedot - XK_Cabovedot);
+       break;
+    case 3: /* Latin 4 */
+       /* Assume the KeySym is a legal value (ignore discontinuities) */
+       if (sym >= XK_Rcedilla && sym <= XK_Tslash)
+           *lower += (XK_rcedilla - XK_Rcedilla);
+       else if (sym >= XK_rcedilla && sym <= XK_tslash)
+           *upper -= (XK_rcedilla - XK_Rcedilla);
+       else if (sym == XK_ENG)
+           *lower = XK_eng;
+       else if (sym == XK_eng)
+           *upper = XK_ENG;
+       else if (sym >= XK_Amacron && sym <= XK_Umacron)
+           *lower += (XK_amacron - XK_Amacron);
+       else if (sym >= XK_amacron && sym <= XK_umacron)
+           *upper -= (XK_amacron - XK_Amacron);
+       break;
+    case 6: /* Cyrillic */
+       /* Assume the KeySym is a legal value (ignore discontinuities) */
+       if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
+           *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
+       else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
+           *upper += (XK_Serbian_DJE - XK_Serbian_dje);
+       else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
+           *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
+       else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
+           *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
+        break;
+    case 7: /* Greek */
+       /* Assume the KeySym is a legal value (ignore discontinuities) */
+       if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
+           *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+       else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
+                sym != XK_Greek_iotaaccentdieresis &&
+                sym != XK_Greek_upsilonaccentdieresis)
+           *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
+       else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
+           *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
+       else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
+                sym != XK_Greek_finalsmallsigma)
+           *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
+        break;
+    }
+}