]> source.dussan.org Git - tigervnc.git/commitdiff
Rename Input.h to vncInput.h to fix building on case-insensitive FS 1291/head
authorAlex Richardson <Alexander.Richardson@cl.cam.ac.uk>
Wed, 14 Jul 2021 13:13:54 +0000 (14:13 +0100)
committerAlex Richardson <Alexander.Richardson@cl.cam.ac.uk>
Thu, 15 Jul 2021 08:48:00 +0000 (09:48 +0100)
I am cross-compiling from macOS for a FreeBSD-derived system so my host
file system is case insensitive but the target isn't. Without this change
I get the following warnings which show that the vnc "Input.h" is being
included from mi/mi.h instead of the xserver "input.h":
```
In file included from /Users/alex/cheri/xvnc-server/hw/vnc/Input.c:33:
/Users/alex/cheri/xvnc-server/mi/mi.h:55:10: warning: non-portable path to file '"Input.h"'; specified path differs in case from file name on disk [-Wnonportable-include-path]
#include "input.h"
         ^~~~~~~~~
         "Input.h"
```

unix/xserver/hw/vnc/Input.c [deleted file]
unix/xserver/hw/vnc/Input.h [deleted file]
unix/xserver/hw/vnc/InputXKB.c [deleted file]
unix/xserver/hw/vnc/Makefile.am
unix/xserver/hw/vnc/XserverDesktop.cc
unix/xserver/hw/vnc/XserverDesktop.h
unix/xserver/hw/vnc/vncInput.c [new file with mode: 0644]
unix/xserver/hw/vnc/vncInput.h [new file with mode: 0644]
unix/xserver/hw/vnc/vncInputXKB.c [new file with mode: 0644]

diff --git a/unix/xserver/hw/vnc/Input.c b/unix/xserver/hw/vnc/Input.c
deleted file mode 100644 (file)
index 2a154ad..0000000
+++ /dev/null
@@ -1,644 +0,0 @@
-/* Copyright (C) 2009 TightVNC Team
- * Copyright (C) 2009, 2014 Red Hat, Inc.
- * Copyright 2013-2015 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include "xorg-version.h"
-
-#include "Input.h"
-#include "vncExtInit.h"
-#include "RFBGlue.h"
-
-#include "inputstr.h"
-#include "inpututils.h"
-#include "mi.h"
-#include "mipointer.h"
-#include "exevents.h"
-#include "scrnintstr.h"
-#include "xkbsrv.h"
-#include "xkbstr.h"
-#include "xserver-properties.h"
-extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey;
-#include <X11/keysym.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-extern const unsigned short code_map_qnum_to_xorgevdev[];
-extern const unsigned int code_map_qnum_to_xorgevdev_len;
-extern const unsigned short code_map_qnum_to_xorgkbd[];
-extern const unsigned int code_map_qnum_to_xorgkbd_len;
-
-#define BUTTONS 7
-
-DeviceIntPtr vncKeyboardDev;
-DeviceIntPtr vncPointerDev;
-
-static int oldButtonMask;
-static int cursorPosX, cursorPosY;
-
-static const unsigned short *codeMap;
-static unsigned int codeMapLen;
-
-static KeySym pressedKeys[256];
-
-static int vncPointerProc(DeviceIntPtr pDevice, int onoff);
-static void vncKeyboardBell(int percent, DeviceIntPtr device,
-                            void * ctrl, int class);
-static int vncKeyboardProc(DeviceIntPtr pDevice, int onoff);
-
-static void vncKeysymKeyboardEvent(KeySym keysym, int down);
-
-#define LOG_NAME "Input"
-
-#define LOG_ERROR(...) vncLogError(LOG_NAME, __VA_ARGS__)
-#define LOG_STATUS(...) vncLogStatus(LOG_NAME, __VA_ARGS__)
-#define LOG_INFO(...) vncLogInfo(LOG_NAME, __VA_ARGS__)
-#define LOG_DEBUG(...) vncLogDebug(LOG_NAME, __VA_ARGS__)
-
-/*
- * Init input device.
- * This has to be called after core pointer/keyboard
- * initialization which unfortunately is after extensions
- * initialization (which means we cannot call it in
- * vncExtensionInit(). Check InitExtensions(),
- * InitCoreDevices() and InitInput() calls in dix/main.c.
- * Instead we call it from XserverDesktop at an appropriate
- * time.
- */
-void vncInitInputDevice(void)
-{
-       int i, ret;
-
-       if ((vncPointerDev != NULL) || (vncKeyboardDev != NULL))
-               return;
-
-       /*
-        * On Linux we try to provide the same key codes as Xorg with
-        * the evdev driver. On other platforms we mimic the older
-        * Xorg KBD driver.
-        */
-#ifdef __linux__
-       codeMap = code_map_qnum_to_xorgevdev;
-       codeMapLen = code_map_qnum_to_xorgevdev_len;
-#else
-       codeMap = code_map_qnum_to_xorgkbd;
-       codeMapLen = code_map_qnum_to_xorgkbd_len;
-#endif
-
-       for (i = 0;i < 256;i++)
-               pressedKeys[i] = NoSymbol;
-
-       ret = AllocDevicePair(serverClient, "TigerVNC",
-                             &vncPointerDev, &vncKeyboardDev,
-                             vncPointerProc, vncKeyboardProc,
-                             FALSE);
-
-       if (ret != Success)
-               FatalError("Failed to initialize TigerVNC input devices\n");
-
-       if (ActivateDevice(vncPointerDev, TRUE) != Success ||
-           ActivateDevice(vncKeyboardDev, TRUE) != Success)
-               FatalError("Failed to activate TigerVNC devices\n");
-
-       if (!EnableDevice(vncPointerDev, TRUE) ||
-           !EnableDevice(vncKeyboardDev, TRUE))
-               FatalError("Failed to activate TigerVNC devices\n");
-
-       vncPrepareInputDevices();
-}
-
-void vncPointerButtonAction(int buttonMask)
-{
-       int i;
-       ValuatorMask mask;
-
-       for (i = 0; i < BUTTONS; i++) {
-               if ((buttonMask ^ oldButtonMask) & (1 << i)) {
-                       int action = (buttonMask & (1<<i)) ?
-                                    ButtonPress : ButtonRelease;
-                       valuator_mask_set_range(&mask, 0, 0, NULL);
-                       QueuePointerEvents(vncPointerDev, action, i + 1,
-                                          POINTER_RELATIVE, &mask);
-               }
-       }
-
-       oldButtonMask = buttonMask;
-}
-
-void vncPointerMove(int x, int y)
-{
-       int valuators[2];
-       ValuatorMask mask;
-
-       if (cursorPosX == x && cursorPosY == y)
-               return;
-
-       valuators[0] = x;
-       valuators[1] = y;
-       valuator_mask_set_range(&mask, 0, 2, valuators);
-       QueuePointerEvents(vncPointerDev, MotionNotify, 0,
-                          POINTER_ABSOLUTE, &mask);
-
-       cursorPosX = x;
-       cursorPosY = y;
-}
-
-void vncGetPointerPos(int *x, int *y)
-{
-       if (vncPointerDev != NULL) {
-               ScreenPtr ptrScreen;
-
-               miPointerGetPosition(vncPointerDev, &cursorPosX, &cursorPosY);
-
-               /* Pointer coordinates are screen relative */
-               ptrScreen = miPointerGetScreen(vncPointerDev);
-               cursorPosX += ptrScreen->x;
-               cursorPosY += ptrScreen->y;
-       }
-
-       *x = cursorPosX;
-       *y = cursorPosY;
-}
-
-static int vncPointerProc(DeviceIntPtr pDevice, int onoff)
-{
-       BYTE map[BUTTONS + 1];
-       DevicePtr pDev = (DevicePtr)pDevice;
-       int i;
-       /*
-        * NOTE: map[] array is one element longer than btn_labels[] array. This
-        * is not a bug.
-        */
-       Atom btn_labels[BUTTONS];
-       Atom axes_labels[2];
-
-       switch (onoff) {
-       case DEVICE_INIT:
-               for (i = 0; i < BUTTONS + 1; i++)
-                       map[i] = i;
-
-               btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
-               btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
-               btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
-               btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
-               btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
-               btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
-               btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
-
-               axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
-               axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
-
-               InitPointerDeviceStruct(pDev, map, BUTTONS, btn_labels,
-                                       (PtrCtrlProcPtr)NoopDDA,
-                                       GetMotionHistorySize(),
-                                       2, axes_labels);
-               break;
-       case DEVICE_ON:
-               pDev->on = TRUE;
-               break;
-       case DEVICE_OFF:
-               pDev->on = FALSE;
-               break;
-       case DEVICE_CLOSE:
-               vncPointerDev = NULL;
-               break;
-       }
-
-       return Success;
-}
-
-static void vncKeyboardBell(int percent, DeviceIntPtr device,
-                            void * ctrl, int class)
-{
-       if (percent > 0)
-               vncBell();
-}
-
-static void vncKeyboardCtrl(DeviceIntPtr pDevice, KeybdCtrl *ctrl)
-{
-       vncSetLEDState(ctrl->leds);
-}
-
-static int vncKeyboardProc(DeviceIntPtr pDevice, int onoff)
-{
-       DevicePtr pDev = (DevicePtr)pDevice;
-
-       switch (onoff) {
-       case DEVICE_INIT:
-               InitKeyboardDeviceStruct(pDevice, NULL, vncKeyboardBell,
-                                        vncKeyboardCtrl);
-               break;
-       case DEVICE_ON:
-               pDev->on = TRUE;
-               break;
-       case DEVICE_OFF:
-               pDev->on = FALSE;
-               break;
-       case DEVICE_CLOSE:
-               vncKeyboardDev = NULL;
-               break;
-       }
-
-       return Success;
-}
-
-static inline void pressKey(DeviceIntPtr dev, int kc, Bool down, const char *msg)
-{
-       int action;
-
-       if (msg != NULL)
-               LOG_DEBUG("%s %d %s", msg, kc, down ? "down" : "up");
-
-       action = down ? KeyPress : KeyRelease;
-#if XORG_OLDER_THAN(1, 18, 0)
-       QueueKeyboardEvents(dev, action, kc, NULL);
-#else
-       QueueKeyboardEvents(dev, action, kc);
-#endif
-}
-
-/*
- * vncKeyboardEvent() - add X11 events for the given RFB key event
- */
-void vncKeyboardEvent(KeySym keysym, unsigned xtcode, int down)
-{
-       /* Simple case: the client has specified the key */
-       if (xtcode && xtcode < codeMapLen) {
-               int keycode;
-
-               keycode = codeMap[xtcode];
-               if (!keycode) {
-                       /*
-                        * Figure something out based on keysym if we
-                        * cannot find a mapping.
-                        */
-                       if (keysym)
-                               vncKeysymKeyboardEvent(keysym, down);
-                       return;
-               }
-
-               /*
-                * We update the state table in case we get a mix of
-                * events with and without key codes.
-                */
-               if (down)
-                       pressedKeys[keycode] = keysym;
-               else
-                       pressedKeys[keycode] = NoSymbol;
-
-               pressKey(vncKeyboardDev, keycode, down, "raw keycode");
-               mieqProcessInputEvents();
-               return;
-       }
-
-       /*
-        * Advanced case: We have to figure out a sequence of keys that
-        *                result in the given keysym
-        */
-       if (keysym)
-               vncKeysymKeyboardEvent(keysym, down);
-}
-
-/* altKeysym is a table of alternative keysyms which have the same meaning. */
-
-static struct altKeysym_t {
-       KeySym a, b;
-} altKeysym[] = {
-       { XK_Shift_L,           XK_Shift_R },
-       { XK_Control_L,         XK_Control_R },
-       { XK_Meta_L,            XK_Meta_R },
-       { XK_Alt_L,             XK_Alt_R },
-       { XK_Super_L,           XK_Super_R },
-       { XK_Hyper_L,           XK_Hyper_R },
-       { XK_KP_Space,          XK_space },
-       { XK_KP_Tab,            XK_Tab },
-       { XK_KP_Enter,          XK_Return },
-       { XK_KP_F1,             XK_F1 },
-       { XK_KP_F2,             XK_F2 },
-       { XK_KP_F3,             XK_F3 },
-       { XK_KP_F4,             XK_F4 },
-       { XK_KP_Home,           XK_Home },
-       { XK_KP_Left,           XK_Left },
-       { XK_KP_Up,             XK_Up },
-       { XK_KP_Right,          XK_Right },
-       { XK_KP_Down,           XK_Down },
-       { XK_KP_Page_Up,        XK_Page_Up },
-       { XK_KP_Page_Down,      XK_Page_Down },
-       { XK_KP_End,            XK_End },
-       { XK_KP_Begin,          XK_Begin },
-       { XK_KP_Insert,         XK_Insert },
-       { XK_KP_Delete,         XK_Delete },
-       { XK_KP_Equal,          XK_equal },
-       { XK_KP_Multiply,       XK_asterisk },
-       { XK_KP_Add,            XK_plus },
-       { XK_KP_Separator,      XK_comma },
-       { XK_KP_Subtract,       XK_minus },
-       { XK_KP_Decimal,        XK_period },
-       { XK_KP_Divide,         XK_slash },
-       { XK_KP_0,              XK_0 },
-       { XK_KP_1,              XK_1 },
-       { XK_KP_2,              XK_2 },
-       { XK_KP_3,              XK_3 },
-       { XK_KP_4,              XK_4 },
-       { XK_KP_5,              XK_5 },
-       { XK_KP_6,              XK_6 },
-       { XK_KP_7,              XK_7 },
-       { XK_KP_8,              XK_8 },
-       { XK_KP_9,              XK_9 },
-       { XK_ISO_Level3_Shift,  XK_Mode_switch },
-};
-
-/*
- * vncKeysymKeyboardEvent() - work out the best keycode corresponding
- * to the keysym sent by the viewer. This is basically impossible in
- * the general case, but we make a best effort by assuming that all
- * useful keysyms can be reached using just the Shift and
- * Level 3 (AltGr) modifiers. For core keyboards this is basically
- * always true, and should be true for most sane, western XKB layouts.
- */
-static void vncKeysymKeyboardEvent(KeySym keysym, int down)
-{
-       int i;
-       unsigned state, new_state;
-       KeyCode keycode;
-
-       unsigned level_three_mask;
-       KeyCode shift_press, level_three_press;
-       KeyCode shift_release[8], level_three_release[8];
-       size_t shift_release_count, level_three_release_count;
-
-       /*
-        * Release events must match the press event, so look up what
-        * keycode we sent for the press.
-        */
-       if (!down) {
-               for (i = 0;i < 256;i++) {
-                       if (pressedKeys[i] == keysym) {
-                               pressedKeys[i] = NoSymbol;
-                               pressKey(vncKeyboardDev, i, FALSE, "keycode");
-                               mieqProcessInputEvents();
-                               return;
-                       }
-               }
-
-               /*
-                * This can happen quite often as we ignore some
-                * key presses.
-                */
-               LOG_DEBUG("Unexpected release of keysym 0x%x", keysym);
-               return;
-       }
-
-       /* 
-        * Since we are checking the current state to determine if we need
-        * to fake modifiers, we must make sure that everything put on the
-        * input queue is processed before we start. Otherwise, shift may be
-        * stuck down.
-        */ 
-       mieqProcessInputEvents();
-
-       state = vncGetKeyboardState();
-
-       keycode = vncKeysymToKeycode(keysym, state, &new_state);
-
-       /*
-        * Shift+Alt is often mapped to Meta, so try that rather than
-        * allocating a new entry, faking shift, or using the dummy
-        * key entries that many layouts have.
-        */
-       if ((state & ShiftMask) &&
-           ((keysym == XK_Alt_L) || (keysym == XK_Alt_R))) {
-               KeyCode alt, meta;
-
-               if (keysym == XK_Alt_L) {
-                       alt = vncKeysymToKeycode(XK_Alt_L, state & ~ShiftMask, NULL);
-                       meta = vncKeysymToKeycode(XK_Meta_L, state, NULL);
-               } else {
-                       alt = vncKeysymToKeycode(XK_Alt_R, state & ~ShiftMask, NULL);
-                       meta = vncKeysymToKeycode(XK_Meta_R, state, NULL);
-               }
-
-               if ((meta != 0) && (alt == meta)) {
-                       LOG_DEBUG("Replacing Shift+Alt with Shift+Meta");
-                       keycode = meta;
-                       new_state = state;
-               }
-       }
-
-       /* Try some equivalent keysyms if we couldn't find a perfect match */
-       if (keycode == 0) {
-               for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
-                       KeySym altsym;
-
-                       if (altKeysym[i].a == keysym)
-                               altsym = altKeysym[i].b;
-                       else if (altKeysym[i].b == keysym)
-                               altsym = altKeysym[i].a;
-                       else
-                               continue;
-
-                       keycode = vncKeysymToKeycode(altsym, state, &new_state);
-                       if (keycode != 0)
-                               break;
-               }
-       }
-
-       /* No matches. Will have to add a new entry... */
-       if (keycode == 0) {
-               keycode = vncAddKeysym(keysym, state);
-               if (keycode == 0) {
-                       LOG_ERROR("Failure adding new keysym 0x%x", keysym);
-                       return;
-               }
-
-               LOG_INFO("Added unknown keysym 0x%x to keycode %d",
-                        keysym, keycode);
-
-               /*
-                * The state given to addKeysym() is just a hint and
-                * the actual result might still require some state
-                * changes.
-                */
-               keycode = vncKeysymToKeycode(keysym, state, &new_state);
-               if (keycode == 0) {
-                       LOG_ERROR("Newly added keysym 0x%x cannot be generated", keysym);
-                       return;
-               }
-       }
-
-       /*
-        * X11 generally lets shift toggle the keys on the numeric pad
-        * the same way NumLock does. This is however not the case on
-        * other systems like Windows. As a result, some applications
-        * get confused when we do a fake shift to get the same effect
-        * that having NumLock active would produce.
-        *
-        * Not all clients have proper NumLock synchronisation (so we
-        * can avoid faking shift) so we try to avoid the fake shifts
-        * if we can use an alternative keysym.
-        */
-       if (((state & ShiftMask) != (new_state & ShiftMask)) &&
-           vncGetAvoidShiftNumLock() && vncIsAffectedByNumLock(keycode)) {
-               KeyCode keycode2;
-               unsigned new_state2;
-
-               LOG_DEBUG("Finding alternative to keysym 0x%x to avoid fake shift for numpad", keysym);
-
-               for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
-                       KeySym altsym;
-
-                       if (altKeysym[i].a == keysym)
-                               altsym = altKeysym[i].b;
-                       else if (altKeysym[i].b == keysym)
-                               altsym = altKeysym[i].a;
-                       else
-                               continue;
-
-                       keycode2 = vncKeysymToKeycode(altsym, state, &new_state2);
-                       if (keycode2 == 0)
-                               continue;
-
-                       if (((state & ShiftMask) != (new_state2 & ShiftMask)) &&
-                           vncIsAffectedByNumLock(keycode2))
-                               continue;
-
-                       break;
-               }
-
-               if (i == sizeof(altKeysym)/sizeof(altKeysym[0]))
-                       LOG_DEBUG("No alternative keysym found");
-               else {
-                       keycode = keycode2;
-                       new_state = new_state2;
-               }
-       }
-
-       /*
-        * "Shifted Tab" is a bit of a mess. Some systems have varying,
-        * special keysyms for this symbol. VNC mandates that clients
-        * should always send the plain XK_Tab keysym and the server
-        * should deduce the meaning based on current Shift state.
-        * To comply with this, we will find the keycode that sends
-        * XK_Tab, and make sure that Shift isn't cleared. This can
-        * possibly result in a different keysym than XK_Tab, but that
-        * is the desired behaviour.
-        *
-        * Note: We never get ISO_Left_Tab here because it's already
-        *       been translated in VNCSConnectionST.
-        */
-       if (keysym == XK_Tab && (state & ShiftMask))
-               new_state |= ShiftMask;
-
-       /*
-        * We need a bigger state change than just shift,
-        * so we need to know what the mask is for level 3 shifts.
-        */
-       if ((new_state & ~ShiftMask) != (state & ~ShiftMask))
-               level_three_mask = vncGetLevelThreeMask();
-       else
-               level_three_mask = 0;
-
-       shift_press = level_three_press = 0;
-       shift_release_count = level_three_release_count = 0;
-
-       /* Need a fake press or release of shift? */
-       if (!(state & ShiftMask) && (new_state & ShiftMask)) {
-               shift_press = vncPressShift();
-               if (shift_press == 0) {
-                       LOG_ERROR("Unable to find a modifier key for Shift");
-                       return;
-               }
-
-               pressKey(vncKeyboardDev, shift_press, TRUE, "temp shift");
-       } else if ((state & ShiftMask) && !(new_state & ShiftMask)) {
-               shift_release_count = vncReleaseShift(shift_release,
-                                                     sizeof(shift_release)/sizeof(*shift_release));
-               if (shift_release_count == 0) {
-                       LOG_ERROR("Unable to find the modifier key(s) for releasing Shift");
-                       return;
-               }
-
-               for (i = 0;i < shift_release_count;i++)
-                       pressKey(vncKeyboardDev, shift_release[i], FALSE, "temp shift");
-       }
-
-       /* Need a fake press or release of level three shift? */
-       if (!(state & level_three_mask) && (new_state & level_three_mask)) {
-               level_three_press = vncPressLevelThree();
-               if (level_three_press == 0) {
-                       LOG_ERROR("Unable to find a modifier key for ISO_Level3_Shift/Mode_Switch");
-                       return;
-               }
-
-               pressKey(vncKeyboardDev, level_three_press, TRUE, "temp level 3 shift");
-       } else if ((state & level_three_mask) && !(new_state & level_three_mask)) {
-               level_three_release_count = vncReleaseLevelThree(level_three_release,
-                                                                sizeof(level_three_release)/sizeof(*level_three_release));
-               if (level_three_release_count == 0) {
-                       LOG_ERROR("Unable to find the modifier key(s) for releasing ISO_Level3_Shift/Mode_Switch");
-                       return;
-               }
-
-               for (i = 0;i < level_three_release_count;i++)
-                       pressKey(vncKeyboardDev, level_three_release[i], FALSE, "temp level 3 shift");
-       }
-
-       /* Now press the actual key */
-       pressKey(vncKeyboardDev, keycode, TRUE, "keycode");
-
-       /* And store the mapping so that we can do a proper release later */
-       for (i = 0;i < 256;i++) {
-               if (i == keycode)
-                       continue;
-               if (pressedKeys[i] == keysym) {
-                       LOG_ERROR("Keysym 0x%x generated by both keys %d and %d", keysym, i, keycode);
-                       pressedKeys[i] = NoSymbol;
-               }
-       }
-
-       pressedKeys[keycode] = keysym;
-
-       /* Undo any fake level three shift */
-       if (level_three_press != 0)
-               pressKey(vncKeyboardDev, level_three_press, FALSE, "temp level 3 shift");
-       else if (level_three_release_count != 0) {
-               for (i = 0;i < level_three_release_count;i++)
-                       pressKey(vncKeyboardDev, level_three_release[i], TRUE, "temp level 3 shift");
-       }
-
-       /* Undo any fake shift */
-       if (shift_press != 0)
-               pressKey(vncKeyboardDev, shift_press, FALSE, "temp shift");
-       else if (shift_release_count != 0) {
-               for (i = 0;i < shift_release_count;i++)
-                       pressKey(vncKeyboardDev, shift_release[i], TRUE, "temp shift");
-       }
-
-       /*
-        * When faking a modifier we are putting a keycode (which can
-        * currently activate the desired modifier) on the input
-        * queue. A future modmap change can change the mapping so
-        * that this keycode means something else entirely. Guard
-        * against this by processing the queue now.
-        */
-       mieqProcessInputEvents();
-}
diff --git a/unix/xserver/hw/vnc/Input.h b/unix/xserver/hw/vnc/Input.h
deleted file mode 100644 (file)
index a9d067f..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Copyright (C) 2009 TightVNC Team
- * Copyright (C) 2009, 2010 Red Hat, Inc.
- * Copyright (C) 2009, 2010 TigerVNC Team
- * Copyright 2013-2015 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-/* Make sure macro doesn't conflict with macro in include/input.h. */
-#ifndef INPUT_H_
-#define INPUT_H_
-
-#include <stdlib.h>
-#include <X11/X.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void vncInitInputDevice(void);
-
-void vncPointerButtonAction(int buttonMask);
-void vncPointerMove(int x, int y);
-void vncGetPointerPos(int *x, int *y);
-
-void vncKeyboardEvent(KeySym keysym, unsigned xtcode, int down);
-
-/* Backend dependent functions below here */
-
-void vncPrepareInputDevices(void);
-
-unsigned vncGetKeyboardState(void);
-unsigned vncGetLevelThreeMask(void);
-
-KeyCode vncPressShift(void);
-size_t vncReleaseShift(KeyCode *keys, size_t maxKeys);
-
-KeyCode vncPressLevelThree(void);
-size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys);
-
-KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
-
-int vncIsAffectedByNumLock(KeyCode keycode);
-
-KeyCode vncAddKeysym(KeySym keysym, unsigned state);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/unix/xserver/hw/vnc/InputXKB.c b/unix/xserver/hw/vnc/InputXKB.c
deleted file mode 100644 (file)
index de6c1d3..0000000
+++ /dev/null
@@ -1,678 +0,0 @@
-/* Copyright (C) 2009 TightVNC Team
- * Copyright (C) 2009 Red Hat, Inc.
- * Copyright 2013-2018 Pierre Ossman for Cendio AB
- *
- * 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.
- */
-
-#ifdef HAVE_DIX_CONFIG_H
-#include <dix-config.h>
-#endif
-
-#include "xorg-version.h"
-
-#include <stdio.h>
-
-#include <X11/keysym.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-#include "xkbsrv.h"
-#include "xkbstr.h"
-#include "eventstr.h"
-#include "scrnintstr.h"
-#include "mi.h"
-
-#include "Input.h"
-
-#ifndef KEYBOARD_OR_FLOAT
-#define KEYBOARD_OR_FLOAT MASTER_KEYBOARD
-#endif
-
-#if XORG_OLDER_THAN(1, 18, 0)
-#define GetMaster(dev, type) ((dev)->master)
-#endif
-
-extern DeviceIntPtr vncKeyboardDev;
-
-static const KeyCode fakeKeys[] = {
-#ifdef __linux__
-    92, 203, 204, 205, 206, 207
-#else
-    8, 124, 125, 156, 127, 128
-#endif
-    };
-
-static void vncXkbProcessDeviceEvent(int screenNum,
-                                     InternalEvent *event,
-                                     DeviceIntPtr dev);
-
-/* Stolen from libX11 */
-static Bool
-XkbTranslateKeyCode(register XkbDescPtr xkb, KeyCode key,
-                    register unsigned int mods, unsigned int *mods_rtrn,
-                    KeySym *keysym_rtrn)
-{
-       XkbKeyTypeRec *type;
-       int col,nKeyGroups;
-       unsigned preserve,effectiveGroup;
-       KeySym *syms;
-
-       if (mods_rtrn!=NULL)
-               *mods_rtrn = 0;
-
-       nKeyGroups= XkbKeyNumGroups(xkb,key);
-       if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
-               if (keysym_rtrn!=NULL)
-                       *keysym_rtrn = NoSymbol;
-               return False;
-       }
-
-       syms = XkbKeySymsPtr(xkb,key);
-
-       /* find the offset of the effective group */
-       col = 0;
-       effectiveGroup= XkbGroupForCoreState(mods);
-       if ( effectiveGroup>=nKeyGroups ) {
-               unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
-               switch (XkbOutOfRangeGroupAction(groupInfo)) {
-               default:
-                       effectiveGroup %= nKeyGroups;
-                       break;
-               case XkbClampIntoRange:
-                       effectiveGroup = nKeyGroups-1;
-                       break;
-               case XkbRedirectIntoRange:
-                       effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
-                       if (effectiveGroup>=nKeyGroups)
-                               effectiveGroup= 0;
-                       break;
-               }
-       }
-       col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
-       type = XkbKeyKeyType(xkb,key,effectiveGroup);
-
-       preserve= 0;
-       if (type->map) { /* find the column (shift level) within the group */
-               register int i;
-               register XkbKTMapEntryPtr entry;
-               for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
-                       if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
-                               col+= entry->level;
-                               if (type->preserve)
-                                       preserve= type->preserve[i].mask;
-                               break;
-                       }
-               }
-       }
-
-       if (keysym_rtrn!=NULL)
-               *keysym_rtrn= syms[col];
-       if (mods_rtrn)
-               *mods_rtrn= type->mods.mask&(~preserve);
-
-       return (syms[col]!=NoSymbol);
-}
-
-static XkbAction *XkbKeyActionPtr(XkbDescPtr xkb, KeyCode key, unsigned int mods)
-{
-       XkbKeyTypeRec *type;
-       int col,nKeyGroups;
-       unsigned effectiveGroup;
-       XkbAction *acts;
-
-       if (!XkbKeyHasActions(xkb, key))
-               return NULL;
-
-       nKeyGroups= XkbKeyNumGroups(xkb,key);
-       if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
-               return NULL;
-
-       acts = XkbKeyActionsPtr(xkb,key);
-
-       /* find the offset of the effective group */
-       col = 0;
-       effectiveGroup= XkbGroupForCoreState(mods);
-       if ( effectiveGroup>=nKeyGroups ) {
-               unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
-               switch (XkbOutOfRangeGroupAction(groupInfo)) {
-               default:
-                       effectiveGroup %= nKeyGroups;
-                       break;
-               case XkbClampIntoRange:
-                       effectiveGroup = nKeyGroups-1;
-                       break;
-               case XkbRedirectIntoRange:
-                       effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
-                       if (effectiveGroup>=nKeyGroups)
-                               effectiveGroup= 0;
-                       break;
-               }
-       }
-       col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
-       type = XkbKeyKeyType(xkb,key,effectiveGroup);
-
-       if (type->map) { /* find the column (shift level) within the group */
-               register int i;
-               register XkbKTMapEntryPtr entry;
-               for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
-                       if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
-                               col+= entry->level;
-                               break;
-                       }
-               }
-       }
-
-       return &acts[col];
-}
-
-static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int mods)
-{
-       int nKeyGroups;
-       unsigned effectiveGroup;
-
-       nKeyGroups= XkbKeyNumGroups(xkb,key);
-       if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
-               return 0;
-
-       effectiveGroup= XkbGroupForCoreState(mods);
-       if ( effectiveGroup>=nKeyGroups ) {
-               unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
-               switch (XkbOutOfRangeGroupAction(groupInfo)) {
-               default:
-                       effectiveGroup %= nKeyGroups;
-                       break;
-               case XkbClampIntoRange:
-                       effectiveGroup = nKeyGroups-1;
-                       break;
-               case XkbRedirectIntoRange:
-                       effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
-                       if (effectiveGroup>=nKeyGroups)
-                               effectiveGroup= 0;
-                       break;
-               }
-       }
-
-       return effectiveGroup;
-}
-
-void vncPrepareInputDevices(void)
-{
-       /*
-        * Not ideal since these callbacks do not stack, but it's the only
-        * decent way we can reliably catch events for both the slave and
-        * master device.
-        */
-       mieqSetHandler(ET_KeyPress, vncXkbProcessDeviceEvent);
-       mieqSetHandler(ET_KeyRelease, vncXkbProcessDeviceEvent);
-}
-
-unsigned vncGetKeyboardState(void)
-{
-       DeviceIntPtr master;
-
-       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
-       return XkbStateFieldFromRec(&master->key->xkbInfo->state);
-}
-
-unsigned vncGetLevelThreeMask(void)
-{
-       unsigned state;
-       KeyCode keycode;
-       XkbDescPtr xkb;
-       XkbAction *act;
-
-       /* Group state is still important */
-       state = vncGetKeyboardState();
-       state &= ~0xff;
-
-       keycode = vncKeysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
-       if (keycode == 0) {
-               keycode = vncKeysymToKeycode(XK_Mode_switch, state, NULL);
-               if (keycode == 0)
-                       return 0;
-       }
-
-       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
-
-       act = XkbKeyActionPtr(xkb, keycode, state);
-       if (act == NULL)
-               return 0;
-       if (act->type != XkbSA_SetMods)
-               return 0;
-
-       if (act->mods.flags & XkbSA_UseModMapMods)
-               return xkb->map->modmap[keycode];
-       else
-               return act->mods.mask;
-}
-
-KeyCode vncPressShift(void)
-{
-       unsigned state;
-
-       XkbDescPtr xkb;
-       unsigned int key;
-
-       state = vncGetKeyboardState();
-       if (state & ShiftMask)
-               return 0;
-
-       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
-       for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
-               XkbAction *act;
-               unsigned char mask;
-
-               act = XkbKeyActionPtr(xkb, key, state);
-               if (act == NULL)
-                       continue;
-
-               if (act->type != XkbSA_SetMods)
-                       continue;
-
-               if (act->mods.flags & XkbSA_UseModMapMods)
-                       mask = xkb->map->modmap[key];
-               else
-                       mask = act->mods.mask;
-
-               if ((mask & ShiftMask) == ShiftMask)
-                       return key;
-       }
-
-       return 0;
-}
-
-size_t vncReleaseShift(KeyCode *keys, size_t maxKeys)
-{
-       size_t count;
-
-       unsigned state;
-
-       DeviceIntPtr master;
-       XkbDescPtr xkb;
-       unsigned int key;
-
-       state = vncGetKeyboardState();
-       if (!(state & ShiftMask))
-               return 0;
-
-       count = 0;
-
-       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
-       xkb = master->key->xkbInfo->desc;
-       for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
-               XkbAction *act;
-               unsigned char mask;
-
-               if (!key_is_down(master, key, KEY_PROCESSED))
-                       continue;
-
-               act = XkbKeyActionPtr(xkb, key, state);
-               if (act == NULL)
-                       continue;
-
-               if (act->type != XkbSA_SetMods)
-                       continue;
-
-               if (act->mods.flags & XkbSA_UseModMapMods)
-                       mask = xkb->map->modmap[key];
-               else
-                       mask = act->mods.mask;
-
-               if (!(mask & ShiftMask))
-                       continue;
-
-               if (count >= maxKeys)
-                       return 0;
-
-               keys[count++] = key;
-       }
-
-       return count;
-}
-
-KeyCode vncPressLevelThree(void)
-{
-       unsigned state, mask;
-
-       KeyCode keycode;
-       XkbDescPtr xkb;
-       XkbAction *act;
-
-       mask = vncGetLevelThreeMask();
-       if (mask == 0)
-               return 0;
-
-       state = vncGetKeyboardState();
-       if (state & mask)
-               return 0;
-
-       keycode = vncKeysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
-       if (keycode == 0) {
-               keycode = vncKeysymToKeycode(XK_Mode_switch, state, NULL);
-               if (keycode == 0)
-                       return 0;
-       }
-
-       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
-
-       act = XkbKeyActionPtr(xkb, keycode, state);
-       if (act == NULL)
-               return 0;
-       if (act->type != XkbSA_SetMods)
-               return 0;
-
-       return keycode;
-}
-
-size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys)
-{
-       size_t count;
-
-       unsigned state, mask;
-
-       DeviceIntPtr master;
-       XkbDescPtr xkb;
-       unsigned int key;
-
-       mask = vncGetLevelThreeMask();
-       if (mask == 0)
-               return 0;
-
-       state = vncGetKeyboardState();
-       if (!(state & mask))
-               return 0;
-
-       count = 0;
-
-       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
-       xkb = master->key->xkbInfo->desc;
-       for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
-               XkbAction *act;
-               unsigned char key_mask;
-
-               if (!key_is_down(master, key, KEY_PROCESSED))
-                       continue;
-
-               act = XkbKeyActionPtr(xkb, key, state);
-               if (act == NULL)
-                       continue;
-
-               if (act->type != XkbSA_SetMods)
-                       continue;
-
-               if (act->mods.flags & XkbSA_UseModMapMods)
-                       key_mask = xkb->map->modmap[key];
-               else
-                       key_mask = act->mods.mask;
-
-               if (!(key_mask & mask))
-                       continue;
-
-               if (count >= maxKeys)
-                       return 0;
-
-               keys[count++] = key;
-       }
-
-       return count;
-}
-
-KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
-{
-       XkbDescPtr xkb;
-       unsigned int key; // KeyCode has insufficient range for the loop
-       KeyCode fallback;
-       KeySym ks;
-       unsigned level_three_mask;
-
-       if (new_state != NULL)
-               *new_state = state;
-
-       fallback = 0;
-       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
-       for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
-               unsigned int state_out;
-               KeySym dummy;
-               size_t fakeIdx;
-
-               XkbTranslateKeyCode(xkb, key, state, &state_out, &ks);
-               if (ks == NoSymbol)
-                       continue;
-
-               /*
-                * Despite every known piece of documentation on
-                * XkbTranslateKeyCode() stating that mods_rtrn returns
-                * the unconsumed modifiers, in reality it always
-                * returns the _potentially consumed_ modifiers.
-                */
-               state_out = state & ~state_out;
-               if (state_out & LockMask)
-                       XkbConvertCase(ks, &dummy, &ks);
-
-               if (ks != keysym)
-                       continue;
-
-               /*
-                * Some keys are never sent by a real keyboard and are
-                * used in the default layouts as a fallback for
-                * modifiers. Make sure we use them last as some
-                * applications can be confused by these normally
-                * unused keys.
-                */
-               for (fakeIdx = 0;
-                    fakeIdx < sizeof(fakeKeys)/sizeof(fakeKeys[0]);
-                    fakeIdx++) {
-                       if (key == fakeKeys[fakeIdx]) {
-                               if (fallback == 0)
-                                       fallback = key;
-                               break;
-                       }
-               }
-               if (fakeIdx < sizeof(fakeKeys)/sizeof(fakeKeys[0]))
-                       continue;
-
-               return key;
-       }
-
-       /* Use the fallback key, if one was found */
-       if (fallback != 0)
-               return fallback;
-
-       if (new_state == NULL)
-               return 0;
-
-       *new_state = (state & ~ShiftMask) |
-                    ((state & ShiftMask) ? 0 : ShiftMask);
-       key = vncKeysymToKeycode(keysym, *new_state, NULL);
-       if (key != 0)
-               return key;
-
-       level_three_mask = vncGetLevelThreeMask();
-       if (level_three_mask == 0)
-               return 0;
-
-       *new_state = (state & ~level_three_mask) | 
-                    ((state & level_three_mask) ? 0 : level_three_mask);
-       key = vncKeysymToKeycode(keysym, *new_state, NULL);
-       if (key != 0)
-               return key;
-
-       *new_state = (state & ~(ShiftMask | level_three_mask)) | 
-                    ((state & ShiftMask) ? 0 : ShiftMask) |
-                    ((state & level_three_mask) ? 0 : level_three_mask);
-       key = vncKeysymToKeycode(keysym, *new_state, NULL);
-       if (key != 0)
-               return key;
-
-       return 0;
-}
-
-int vncIsAffectedByNumLock(KeyCode keycode)
-{
-       unsigned state;
-
-       KeyCode numlock_keycode;
-       unsigned numlock_mask;
-
-       XkbDescPtr xkb;
-       XkbAction *act;
-
-       unsigned group;
-       XkbKeyTypeRec *type;
-
-       /* Group state is still important */
-       state = vncGetKeyboardState();
-       state &= ~0xff;
-
-       /*
-        * Not sure if hunting for a virtual modifier called "NumLock",
-        * or following the keysym Num_Lock is the best approach. We
-        * try the latter.
-        */
-       numlock_keycode = vncKeysymToKeycode(XK_Num_Lock, state, NULL);
-       if (numlock_keycode == 0)
-               return 0;
-
-       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
-
-       act = XkbKeyActionPtr(xkb, numlock_keycode, state);
-       if (act == NULL)
-               return 0;
-       if (act->type != XkbSA_LockMods)
-               return 0;
-
-       if (act->mods.flags & XkbSA_UseModMapMods)
-               numlock_mask = xkb->map->modmap[keycode];
-       else
-               numlock_mask = act->mods.mask;
-
-       group = XkbKeyEffectiveGroup(xkb, keycode, state);
-       type = XkbKeyKeyType(xkb, keycode, group);
-       if ((type->mods.mask & numlock_mask) == 0)
-               return 0;
-
-       return 1;
-}
-
-KeyCode vncAddKeysym(KeySym keysym, unsigned state)
-{
-       DeviceIntPtr master;
-       XkbDescPtr xkb;
-       unsigned int key;
-
-       XkbEventCauseRec cause;
-       XkbChangesRec changes;
-
-       int types[1];
-       KeySym *syms;
-       KeySym upper, lower;
-
-       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
-       xkb = master->key->xkbInfo->desc;
-       for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) {
-               if (XkbKeyNumGroups(xkb, key) == 0)
-                       break;
-       }
-
-       if (key < xkb->min_key_code)
-               return 0;
-
-       memset(&changes, 0, sizeof(changes));
-       memset(&cause, 0, sizeof(cause));
-
-       XkbSetCauseUnknown(&cause);
-
-       /*
-        * Tools like xkbcomp get confused if there isn't a name
-        * assigned to the keycode we're trying to use.
-        */
-       if (xkb->names && xkb->names->keys &&
-           (xkb->names->keys[key].name[0] == '\0')) {
-               xkb->names->keys[key].name[0] = 'I';
-               xkb->names->keys[key].name[1] = '0' + (key / 100) % 10;
-               xkb->names->keys[key].name[2] = '0' + (key /  10) % 10;
-               xkb->names->keys[key].name[3] = '0' + (key /   1) % 10;
-
-               changes.names.changed |= XkbKeyNamesMask;
-               changes.names.first_key = key;
-               changes.names.num_keys = 1;
-       }
-
-       /* FIXME: Verify that ONE_LEVEL/ALPHABETIC isn't screwed up */
-
-       /*
-        * For keysyms that are affected by Lock, we are better off
-        * using ALPHABETIC rather than ONE_LEVEL as the latter
-        * generally cannot produce lower case when Lock is active.
-        */
-       XkbConvertCase(keysym, &lower, &upper);
-       if (upper == lower)
-               types[XkbGroup1Index] = XkbOneLevelIndex;
-       else
-               types[XkbGroup1Index] = XkbAlphabeticIndex;
-
-       XkbChangeTypesOfKey(xkb, key, 1, XkbGroup1Mask, types, &changes.map);
-
-       syms = XkbKeySymsPtr(xkb,key);
-       if (upper == lower)
-               syms[0] = keysym;
-       else {
-               syms[0] = lower;
-               syms[1] = upper;
-       }
-
-       changes.map.changed |= XkbKeySymsMask;
-       changes.map.first_key_sym = key;
-       changes.map.num_key_syms = 1;
-
-       XkbSendNotification(master, &changes, &cause);
-
-       return key;
-}
-
-static void vncXkbProcessDeviceEvent(int screenNum,
-                                     InternalEvent *event,
-                                     DeviceIntPtr dev)
-{
-       unsigned int backupctrls;
-       XkbControlsPtr ctrls;
-
-       if (event->device_event.sourceid != vncKeyboardDev->id) {
-               dev->public.processInputProc(event, dev);
-               return;
-       }
-
-       /*
-        * We need to bypass AccessX since it is timing sensitive and
-        * the network can cause fake event delays.
-        */
-       ctrls = dev->key->xkbInfo->desc->ctrls;
-       backupctrls = ctrls->enabled_ctrls;
-       ctrls->enabled_ctrls &= ~XkbAllFilteredEventsMask;
-
-       /*
-        * This flag needs to be set for key repeats to be properly
-        * respected.
-        */
-       if ((event->device_event.type == ET_KeyPress) &&
-           key_is_down(dev, event->device_event.detail.key, KEY_PROCESSED))
-               event->device_event.key_repeat = TRUE;
-
-       dev->public.processInputProc(event, dev);
-
-       ctrls->enabled_ctrls = backupctrls;
-}
index d2d0265bb593a66529b37bde1b0d802accbbdc11..f3abd8a09da3b7d12c1c121793e3adef654ac5b8 100644 (file)
@@ -13,12 +13,12 @@ noinst_LTLIBRARIES = libvnccommon.la
 HDRS = vncExtInit.h vncHooks.h \
        vncBlockHandler.h vncSelection.h \
        XorgGlue.h XserverDesktop.h xorg-version.h \
-       Input.h RFBGlue.h
+       vncInput.h RFBGlue.h
 
 libvnccommon_la_SOURCES = $(HDRS) \
        vncExt.c vncExtInit.cc vncHooks.c vncSelection.c \
        vncBlockHandler.c XorgGlue.c RandrGlue.c RFBGlue.cc XserverDesktop.cc \
-       Input.c InputXKB.c qnum_to_xorgevdev.c qnum_to_xorgkbd.c
+       vncInput.c vncInputXKB.c qnum_to_xorgevdev.c qnum_to_xorgkbd.c
 
 libvnccommon_la_CPPFLAGS = -DVENDOR_RELEASE="$(VENDOR_RELEASE)" -I$(TIGERVNC_SRCDIR)/unix/common \
        -DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(TIGERVNC_SRCDIR)/common -UHAVE_CONFIG_H \
index 25dcd845b1fd086e2166b52abb0f313c5d795c71..d9f47f204c183d1fa0eab3202f1bc23b14a5139b 100644 (file)
@@ -46,7 +46,7 @@
 #include "vncHooks.h"
 #include "vncSelection.h"
 #include "XorgGlue.h"
-#include "Input.h"
+#include "vncInput.h"
 
 extern "C" {
 void vncSetGlueContext(int screenIndex);
index 383e0bbff446f51f7d467bfa106636f9f6676745..57ee80832d6fa3ae89d913f61a77dd89799459bb 100644 (file)
@@ -36,7 +36,7 @@
 #include <rfb/Configuration.h>
 #include <rfb/Timer.h>
 #include <unixcommon.h>
-#include "Input.h"
+#include "vncInput.h"
 
 namespace rfb {
   class VNCServerST;
diff --git a/unix/xserver/hw/vnc/vncInput.c b/unix/xserver/hw/vnc/vncInput.c
new file mode 100644 (file)
index 0000000..16ac25e
--- /dev/null
@@ -0,0 +1,644 @@
+/* Copyright (C) 2009 TightVNC Team
+ * Copyright (C) 2009, 2014 Red Hat, Inc.
+ * Copyright 2013-2015 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "xorg-version.h"
+
+#include "vncInput.h"
+#include "vncExtInit.h"
+#include "RFBGlue.h"
+
+#include "inputstr.h"
+#include "inpututils.h"
+#include "mi.h"
+#include "mipointer.h"
+#include "exevents.h"
+#include "scrnintstr.h"
+#include "xkbsrv.h"
+#include "xkbstr.h"
+#include "xserver-properties.h"
+extern _X_EXPORT DevPrivateKey CoreDevicePrivateKey;
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+extern const unsigned short code_map_qnum_to_xorgevdev[];
+extern const unsigned int code_map_qnum_to_xorgevdev_len;
+extern const unsigned short code_map_qnum_to_xorgkbd[];
+extern const unsigned int code_map_qnum_to_xorgkbd_len;
+
+#define BUTTONS 7
+
+DeviceIntPtr vncKeyboardDev;
+DeviceIntPtr vncPointerDev;
+
+static int oldButtonMask;
+static int cursorPosX, cursorPosY;
+
+static const unsigned short *codeMap;
+static unsigned int codeMapLen;
+
+static KeySym pressedKeys[256];
+
+static int vncPointerProc(DeviceIntPtr pDevice, int onoff);
+static void vncKeyboardBell(int percent, DeviceIntPtr device,
+                            void * ctrl, int class);
+static int vncKeyboardProc(DeviceIntPtr pDevice, int onoff);
+
+static void vncKeysymKeyboardEvent(KeySym keysym, int down);
+
+#define LOG_NAME "Input"
+
+#define LOG_ERROR(...) vncLogError(LOG_NAME, __VA_ARGS__)
+#define LOG_STATUS(...) vncLogStatus(LOG_NAME, __VA_ARGS__)
+#define LOG_INFO(...) vncLogInfo(LOG_NAME, __VA_ARGS__)
+#define LOG_DEBUG(...) vncLogDebug(LOG_NAME, __VA_ARGS__)
+
+/*
+ * Init input device.
+ * This has to be called after core pointer/keyboard
+ * initialization which unfortunately is after extensions
+ * initialization (which means we cannot call it in
+ * vncExtensionInit(). Check InitExtensions(),
+ * InitCoreDevices() and InitInput() calls in dix/main.c.
+ * Instead we call it from XserverDesktop at an appropriate
+ * time.
+ */
+void vncInitInputDevice(void)
+{
+       int i, ret;
+
+       if ((vncPointerDev != NULL) || (vncKeyboardDev != NULL))
+               return;
+
+       /*
+        * On Linux we try to provide the same key codes as Xorg with
+        * the evdev driver. On other platforms we mimic the older
+        * Xorg KBD driver.
+        */
+#ifdef __linux__
+       codeMap = code_map_qnum_to_xorgevdev;
+       codeMapLen = code_map_qnum_to_xorgevdev_len;
+#else
+       codeMap = code_map_qnum_to_xorgkbd;
+       codeMapLen = code_map_qnum_to_xorgkbd_len;
+#endif
+
+       for (i = 0;i < 256;i++)
+               pressedKeys[i] = NoSymbol;
+
+       ret = AllocDevicePair(serverClient, "TigerVNC",
+                             &vncPointerDev, &vncKeyboardDev,
+                             vncPointerProc, vncKeyboardProc,
+                             FALSE);
+
+       if (ret != Success)
+               FatalError("Failed to initialize TigerVNC input devices\n");
+
+       if (ActivateDevice(vncPointerDev, TRUE) != Success ||
+           ActivateDevice(vncKeyboardDev, TRUE) != Success)
+               FatalError("Failed to activate TigerVNC devices\n");
+
+       if (!EnableDevice(vncPointerDev, TRUE) ||
+           !EnableDevice(vncKeyboardDev, TRUE))
+               FatalError("Failed to activate TigerVNC devices\n");
+
+       vncPrepareInputDevices();
+}
+
+void vncPointerButtonAction(int buttonMask)
+{
+       int i;
+       ValuatorMask mask;
+
+       for (i = 0; i < BUTTONS; i++) {
+               if ((buttonMask ^ oldButtonMask) & (1 << i)) {
+                       int action = (buttonMask & (1<<i)) ?
+                                    ButtonPress : ButtonRelease;
+                       valuator_mask_set_range(&mask, 0, 0, NULL);
+                       QueuePointerEvents(vncPointerDev, action, i + 1,
+                                          POINTER_RELATIVE, &mask);
+               }
+       }
+
+       oldButtonMask = buttonMask;
+}
+
+void vncPointerMove(int x, int y)
+{
+       int valuators[2];
+       ValuatorMask mask;
+
+       if (cursorPosX == x && cursorPosY == y)
+               return;
+
+       valuators[0] = x;
+       valuators[1] = y;
+       valuator_mask_set_range(&mask, 0, 2, valuators);
+       QueuePointerEvents(vncPointerDev, MotionNotify, 0,
+                          POINTER_ABSOLUTE, &mask);
+
+       cursorPosX = x;
+       cursorPosY = y;
+}
+
+void vncGetPointerPos(int *x, int *y)
+{
+       if (vncPointerDev != NULL) {
+               ScreenPtr ptrScreen;
+
+               miPointerGetPosition(vncPointerDev, &cursorPosX, &cursorPosY);
+
+               /* Pointer coordinates are screen relative */
+               ptrScreen = miPointerGetScreen(vncPointerDev);
+               cursorPosX += ptrScreen->x;
+               cursorPosY += ptrScreen->y;
+       }
+
+       *x = cursorPosX;
+       *y = cursorPosY;
+}
+
+static int vncPointerProc(DeviceIntPtr pDevice, int onoff)
+{
+       BYTE map[BUTTONS + 1];
+       DevicePtr pDev = (DevicePtr)pDevice;
+       int i;
+       /*
+        * NOTE: map[] array is one element longer than btn_labels[] array. This
+        * is not a bug.
+        */
+       Atom btn_labels[BUTTONS];
+       Atom axes_labels[2];
+
+       switch (onoff) {
+       case DEVICE_INIT:
+               for (i = 0; i < BUTTONS + 1; i++)
+                       map[i] = i;
+
+               btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
+               btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE);
+               btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT);
+               btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP);
+               btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN);
+               btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT);
+               btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT);
+
+               axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X);
+               axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y);
+
+               InitPointerDeviceStruct(pDev, map, BUTTONS, btn_labels,
+                                       (PtrCtrlProcPtr)NoopDDA,
+                                       GetMotionHistorySize(),
+                                       2, axes_labels);
+               break;
+       case DEVICE_ON:
+               pDev->on = TRUE;
+               break;
+       case DEVICE_OFF:
+               pDev->on = FALSE;
+               break;
+       case DEVICE_CLOSE:
+               vncPointerDev = NULL;
+               break;
+       }
+
+       return Success;
+}
+
+static void vncKeyboardBell(int percent, DeviceIntPtr device,
+                            void * ctrl, int class)
+{
+       if (percent > 0)
+               vncBell();
+}
+
+static void vncKeyboardCtrl(DeviceIntPtr pDevice, KeybdCtrl *ctrl)
+{
+       vncSetLEDState(ctrl->leds);
+}
+
+static int vncKeyboardProc(DeviceIntPtr pDevice, int onoff)
+{
+       DevicePtr pDev = (DevicePtr)pDevice;
+
+       switch (onoff) {
+       case DEVICE_INIT:
+               InitKeyboardDeviceStruct(pDevice, NULL, vncKeyboardBell,
+                                        vncKeyboardCtrl);
+               break;
+       case DEVICE_ON:
+               pDev->on = TRUE;
+               break;
+       case DEVICE_OFF:
+               pDev->on = FALSE;
+               break;
+       case DEVICE_CLOSE:
+               vncKeyboardDev = NULL;
+               break;
+       }
+
+       return Success;
+}
+
+static inline void pressKey(DeviceIntPtr dev, int kc, Bool down, const char *msg)
+{
+       int action;
+
+       if (msg != NULL)
+               LOG_DEBUG("%s %d %s", msg, kc, down ? "down" : "up");
+
+       action = down ? KeyPress : KeyRelease;
+#if XORG_OLDER_THAN(1, 18, 0)
+       QueueKeyboardEvents(dev, action, kc, NULL);
+#else
+       QueueKeyboardEvents(dev, action, kc);
+#endif
+}
+
+/*
+ * vncKeyboardEvent() - add X11 events for the given RFB key event
+ */
+void vncKeyboardEvent(KeySym keysym, unsigned xtcode, int down)
+{
+       /* Simple case: the client has specified the key */
+       if (xtcode && xtcode < codeMapLen) {
+               int keycode;
+
+               keycode = codeMap[xtcode];
+               if (!keycode) {
+                       /*
+                        * Figure something out based on keysym if we
+                        * cannot find a mapping.
+                        */
+                       if (keysym)
+                               vncKeysymKeyboardEvent(keysym, down);
+                       return;
+               }
+
+               /*
+                * We update the state table in case we get a mix of
+                * events with and without key codes.
+                */
+               if (down)
+                       pressedKeys[keycode] = keysym;
+               else
+                       pressedKeys[keycode] = NoSymbol;
+
+               pressKey(vncKeyboardDev, keycode, down, "raw keycode");
+               mieqProcessInputEvents();
+               return;
+       }
+
+       /*
+        * Advanced case: We have to figure out a sequence of keys that
+        *                result in the given keysym
+        */
+       if (keysym)
+               vncKeysymKeyboardEvent(keysym, down);
+}
+
+/* altKeysym is a table of alternative keysyms which have the same meaning. */
+
+static struct altKeysym_t {
+       KeySym a, b;
+} altKeysym[] = {
+       { XK_Shift_L,           XK_Shift_R },
+       { XK_Control_L,         XK_Control_R },
+       { XK_Meta_L,            XK_Meta_R },
+       { XK_Alt_L,             XK_Alt_R },
+       { XK_Super_L,           XK_Super_R },
+       { XK_Hyper_L,           XK_Hyper_R },
+       { XK_KP_Space,          XK_space },
+       { XK_KP_Tab,            XK_Tab },
+       { XK_KP_Enter,          XK_Return },
+       { XK_KP_F1,             XK_F1 },
+       { XK_KP_F2,             XK_F2 },
+       { XK_KP_F3,             XK_F3 },
+       { XK_KP_F4,             XK_F4 },
+       { XK_KP_Home,           XK_Home },
+       { XK_KP_Left,           XK_Left },
+       { XK_KP_Up,             XK_Up },
+       { XK_KP_Right,          XK_Right },
+       { XK_KP_Down,           XK_Down },
+       { XK_KP_Page_Up,        XK_Page_Up },
+       { XK_KP_Page_Down,      XK_Page_Down },
+       { XK_KP_End,            XK_End },
+       { XK_KP_Begin,          XK_Begin },
+       { XK_KP_Insert,         XK_Insert },
+       { XK_KP_Delete,         XK_Delete },
+       { XK_KP_Equal,          XK_equal },
+       { XK_KP_Multiply,       XK_asterisk },
+       { XK_KP_Add,            XK_plus },
+       { XK_KP_Separator,      XK_comma },
+       { XK_KP_Subtract,       XK_minus },
+       { XK_KP_Decimal,        XK_period },
+       { XK_KP_Divide,         XK_slash },
+       { XK_KP_0,              XK_0 },
+       { XK_KP_1,              XK_1 },
+       { XK_KP_2,              XK_2 },
+       { XK_KP_3,              XK_3 },
+       { XK_KP_4,              XK_4 },
+       { XK_KP_5,              XK_5 },
+       { XK_KP_6,              XK_6 },
+       { XK_KP_7,              XK_7 },
+       { XK_KP_8,              XK_8 },
+       { XK_KP_9,              XK_9 },
+       { XK_ISO_Level3_Shift,  XK_Mode_switch },
+};
+
+/*
+ * vncKeysymKeyboardEvent() - work out the best keycode corresponding
+ * to the keysym sent by the viewer. This is basically impossible in
+ * the general case, but we make a best effort by assuming that all
+ * useful keysyms can be reached using just the Shift and
+ * Level 3 (AltGr) modifiers. For core keyboards this is basically
+ * always true, and should be true for most sane, western XKB layouts.
+ */
+static void vncKeysymKeyboardEvent(KeySym keysym, int down)
+{
+       int i;
+       unsigned state, new_state;
+       KeyCode keycode;
+
+       unsigned level_three_mask;
+       KeyCode shift_press, level_three_press;
+       KeyCode shift_release[8], level_three_release[8];
+       size_t shift_release_count, level_three_release_count;
+
+       /*
+        * Release events must match the press event, so look up what
+        * keycode we sent for the press.
+        */
+       if (!down) {
+               for (i = 0;i < 256;i++) {
+                       if (pressedKeys[i] == keysym) {
+                               pressedKeys[i] = NoSymbol;
+                               pressKey(vncKeyboardDev, i, FALSE, "keycode");
+                               mieqProcessInputEvents();
+                               return;
+                       }
+               }
+
+               /*
+                * This can happen quite often as we ignore some
+                * key presses.
+                */
+               LOG_DEBUG("Unexpected release of keysym 0x%x", keysym);
+               return;
+       }
+
+       /* 
+        * Since we are checking the current state to determine if we need
+        * to fake modifiers, we must make sure that everything put on the
+        * input queue is processed before we start. Otherwise, shift may be
+        * stuck down.
+        */ 
+       mieqProcessInputEvents();
+
+       state = vncGetKeyboardState();
+
+       keycode = vncKeysymToKeycode(keysym, state, &new_state);
+
+       /*
+        * Shift+Alt is often mapped to Meta, so try that rather than
+        * allocating a new entry, faking shift, or using the dummy
+        * key entries that many layouts have.
+        */
+       if ((state & ShiftMask) &&
+           ((keysym == XK_Alt_L) || (keysym == XK_Alt_R))) {
+               KeyCode alt, meta;
+
+               if (keysym == XK_Alt_L) {
+                       alt = vncKeysymToKeycode(XK_Alt_L, state & ~ShiftMask, NULL);
+                       meta = vncKeysymToKeycode(XK_Meta_L, state, NULL);
+               } else {
+                       alt = vncKeysymToKeycode(XK_Alt_R, state & ~ShiftMask, NULL);
+                       meta = vncKeysymToKeycode(XK_Meta_R, state, NULL);
+               }
+
+               if ((meta != 0) && (alt == meta)) {
+                       LOG_DEBUG("Replacing Shift+Alt with Shift+Meta");
+                       keycode = meta;
+                       new_state = state;
+               }
+       }
+
+       /* Try some equivalent keysyms if we couldn't find a perfect match */
+       if (keycode == 0) {
+               for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
+                       KeySym altsym;
+
+                       if (altKeysym[i].a == keysym)
+                               altsym = altKeysym[i].b;
+                       else if (altKeysym[i].b == keysym)
+                               altsym = altKeysym[i].a;
+                       else
+                               continue;
+
+                       keycode = vncKeysymToKeycode(altsym, state, &new_state);
+                       if (keycode != 0)
+                               break;
+               }
+       }
+
+       /* No matches. Will have to add a new entry... */
+       if (keycode == 0) {
+               keycode = vncAddKeysym(keysym, state);
+               if (keycode == 0) {
+                       LOG_ERROR("Failure adding new keysym 0x%x", keysym);
+                       return;
+               }
+
+               LOG_INFO("Added unknown keysym 0x%x to keycode %d",
+                        keysym, keycode);
+
+               /*
+                * The state given to addKeysym() is just a hint and
+                * the actual result might still require some state
+                * changes.
+                */
+               keycode = vncKeysymToKeycode(keysym, state, &new_state);
+               if (keycode == 0) {
+                       LOG_ERROR("Newly added keysym 0x%x cannot be generated", keysym);
+                       return;
+               }
+       }
+
+       /*
+        * X11 generally lets shift toggle the keys on the numeric pad
+        * the same way NumLock does. This is however not the case on
+        * other systems like Windows. As a result, some applications
+        * get confused when we do a fake shift to get the same effect
+        * that having NumLock active would produce.
+        *
+        * Not all clients have proper NumLock synchronisation (so we
+        * can avoid faking shift) so we try to avoid the fake shifts
+        * if we can use an alternative keysym.
+        */
+       if (((state & ShiftMask) != (new_state & ShiftMask)) &&
+           vncGetAvoidShiftNumLock() && vncIsAffectedByNumLock(keycode)) {
+               KeyCode keycode2;
+               unsigned new_state2;
+
+               LOG_DEBUG("Finding alternative to keysym 0x%x to avoid fake shift for numpad", keysym);
+
+               for (i = 0;i < sizeof(altKeysym)/sizeof(altKeysym[0]);i++) {
+                       KeySym altsym;
+
+                       if (altKeysym[i].a == keysym)
+                               altsym = altKeysym[i].b;
+                       else if (altKeysym[i].b == keysym)
+                               altsym = altKeysym[i].a;
+                       else
+                               continue;
+
+                       keycode2 = vncKeysymToKeycode(altsym, state, &new_state2);
+                       if (keycode2 == 0)
+                               continue;
+
+                       if (((state & ShiftMask) != (new_state2 & ShiftMask)) &&
+                           vncIsAffectedByNumLock(keycode2))
+                               continue;
+
+                       break;
+               }
+
+               if (i == sizeof(altKeysym)/sizeof(altKeysym[0]))
+                       LOG_DEBUG("No alternative keysym found");
+               else {
+                       keycode = keycode2;
+                       new_state = new_state2;
+               }
+       }
+
+       /*
+        * "Shifted Tab" is a bit of a mess. Some systems have varying,
+        * special keysyms for this symbol. VNC mandates that clients
+        * should always send the plain XK_Tab keysym and the server
+        * should deduce the meaning based on current Shift state.
+        * To comply with this, we will find the keycode that sends
+        * XK_Tab, and make sure that Shift isn't cleared. This can
+        * possibly result in a different keysym than XK_Tab, but that
+        * is the desired behaviour.
+        *
+        * Note: We never get ISO_Left_Tab here because it's already
+        *       been translated in VNCSConnectionST.
+        */
+       if (keysym == XK_Tab && (state & ShiftMask))
+               new_state |= ShiftMask;
+
+       /*
+        * We need a bigger state change than just shift,
+        * so we need to know what the mask is for level 3 shifts.
+        */
+       if ((new_state & ~ShiftMask) != (state & ~ShiftMask))
+               level_three_mask = vncGetLevelThreeMask();
+       else
+               level_three_mask = 0;
+
+       shift_press = level_three_press = 0;
+       shift_release_count = level_three_release_count = 0;
+
+       /* Need a fake press or release of shift? */
+       if (!(state & ShiftMask) && (new_state & ShiftMask)) {
+               shift_press = vncPressShift();
+               if (shift_press == 0) {
+                       LOG_ERROR("Unable to find a modifier key for Shift");
+                       return;
+               }
+
+               pressKey(vncKeyboardDev, shift_press, TRUE, "temp shift");
+       } else if ((state & ShiftMask) && !(new_state & ShiftMask)) {
+               shift_release_count = vncReleaseShift(shift_release,
+                                                     sizeof(shift_release)/sizeof(*shift_release));
+               if (shift_release_count == 0) {
+                       LOG_ERROR("Unable to find the modifier key(s) for releasing Shift");
+                       return;
+               }
+
+               for (i = 0;i < shift_release_count;i++)
+                       pressKey(vncKeyboardDev, shift_release[i], FALSE, "temp shift");
+       }
+
+       /* Need a fake press or release of level three shift? */
+       if (!(state & level_three_mask) && (new_state & level_three_mask)) {
+               level_three_press = vncPressLevelThree();
+               if (level_three_press == 0) {
+                       LOG_ERROR("Unable to find a modifier key for ISO_Level3_Shift/Mode_Switch");
+                       return;
+               }
+
+               pressKey(vncKeyboardDev, level_three_press, TRUE, "temp level 3 shift");
+       } else if ((state & level_three_mask) && !(new_state & level_three_mask)) {
+               level_three_release_count = vncReleaseLevelThree(level_three_release,
+                                                                sizeof(level_three_release)/sizeof(*level_three_release));
+               if (level_three_release_count == 0) {
+                       LOG_ERROR("Unable to find the modifier key(s) for releasing ISO_Level3_Shift/Mode_Switch");
+                       return;
+               }
+
+               for (i = 0;i < level_three_release_count;i++)
+                       pressKey(vncKeyboardDev, level_three_release[i], FALSE, "temp level 3 shift");
+       }
+
+       /* Now press the actual key */
+       pressKey(vncKeyboardDev, keycode, TRUE, "keycode");
+
+       /* And store the mapping so that we can do a proper release later */
+       for (i = 0;i < 256;i++) {
+               if (i == keycode)
+                       continue;
+               if (pressedKeys[i] == keysym) {
+                       LOG_ERROR("Keysym 0x%x generated by both keys %d and %d", keysym, i, keycode);
+                       pressedKeys[i] = NoSymbol;
+               }
+       }
+
+       pressedKeys[keycode] = keysym;
+
+       /* Undo any fake level three shift */
+       if (level_three_press != 0)
+               pressKey(vncKeyboardDev, level_three_press, FALSE, "temp level 3 shift");
+       else if (level_three_release_count != 0) {
+               for (i = 0;i < level_three_release_count;i++)
+                       pressKey(vncKeyboardDev, level_three_release[i], TRUE, "temp level 3 shift");
+       }
+
+       /* Undo any fake shift */
+       if (shift_press != 0)
+               pressKey(vncKeyboardDev, shift_press, FALSE, "temp shift");
+       else if (shift_release_count != 0) {
+               for (i = 0;i < shift_release_count;i++)
+                       pressKey(vncKeyboardDev, shift_release[i], TRUE, "temp shift");
+       }
+
+       /*
+        * When faking a modifier we are putting a keycode (which can
+        * currently activate the desired modifier) on the input
+        * queue. A future modmap change can change the mapping so
+        * that this keycode means something else entirely. Guard
+        * against this by processing the queue now.
+        */
+       mieqProcessInputEvents();
+}
diff --git a/unix/xserver/hw/vnc/vncInput.h b/unix/xserver/hw/vnc/vncInput.h
new file mode 100644 (file)
index 0000000..08cab6c
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright (C) 2009 TightVNC Team
+ * Copyright (C) 2009, 2010 Red Hat, Inc.
+ * Copyright (C) 2009, 2010 TigerVNC Team
+ * Copyright 2013-2015 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifndef __VNCINPUT_H__
+#define __VNCINPUT_H__
+
+#include <stdlib.h>
+#include <X11/X.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void vncInitInputDevice(void);
+
+void vncPointerButtonAction(int buttonMask);
+void vncPointerMove(int x, int y);
+void vncGetPointerPos(int *x, int *y);
+
+void vncKeyboardEvent(KeySym keysym, unsigned xtcode, int down);
+
+/* Backend dependent functions below here */
+
+void vncPrepareInputDevices(void);
+
+unsigned vncGetKeyboardState(void);
+unsigned vncGetLevelThreeMask(void);
+
+KeyCode vncPressShift(void);
+size_t vncReleaseShift(KeyCode *keys, size_t maxKeys);
+
+KeyCode vncPressLevelThree(void);
+size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys);
+
+KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state);
+
+int vncIsAffectedByNumLock(KeyCode keycode);
+
+KeyCode vncAddKeysym(KeySym keysym, unsigned state);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/unix/xserver/hw/vnc/vncInputXKB.c b/unix/xserver/hw/vnc/vncInputXKB.c
new file mode 100644 (file)
index 0000000..d5fe286
--- /dev/null
@@ -0,0 +1,678 @@
+/* Copyright (C) 2009 TightVNC Team
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright 2013-2018 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include "xorg-version.h"
+
+#include <stdio.h>
+
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "xkbsrv.h"
+#include "xkbstr.h"
+#include "eventstr.h"
+#include "scrnintstr.h"
+#include "mi.h"
+
+#include "vncInput.h"
+
+#ifndef KEYBOARD_OR_FLOAT
+#define KEYBOARD_OR_FLOAT MASTER_KEYBOARD
+#endif
+
+#if XORG_OLDER_THAN(1, 18, 0)
+#define GetMaster(dev, type) ((dev)->master)
+#endif
+
+extern DeviceIntPtr vncKeyboardDev;
+
+static const KeyCode fakeKeys[] = {
+#ifdef __linux__
+    92, 203, 204, 205, 206, 207
+#else
+    8, 124, 125, 156, 127, 128
+#endif
+    };
+
+static void vncXkbProcessDeviceEvent(int screenNum,
+                                     InternalEvent *event,
+                                     DeviceIntPtr dev);
+
+/* Stolen from libX11 */
+static Bool
+XkbTranslateKeyCode(register XkbDescPtr xkb, KeyCode key,
+                    register unsigned int mods, unsigned int *mods_rtrn,
+                    KeySym *keysym_rtrn)
+{
+       XkbKeyTypeRec *type;
+       int col,nKeyGroups;
+       unsigned preserve,effectiveGroup;
+       KeySym *syms;
+
+       if (mods_rtrn!=NULL)
+               *mods_rtrn = 0;
+
+       nKeyGroups= XkbKeyNumGroups(xkb,key);
+       if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
+               if (keysym_rtrn!=NULL)
+                       *keysym_rtrn = NoSymbol;
+               return False;
+       }
+
+       syms = XkbKeySymsPtr(xkb,key);
+
+       /* find the offset of the effective group */
+       col = 0;
+       effectiveGroup= XkbGroupForCoreState(mods);
+       if ( effectiveGroup>=nKeyGroups ) {
+               unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
+               switch (XkbOutOfRangeGroupAction(groupInfo)) {
+               default:
+                       effectiveGroup %= nKeyGroups;
+                       break;
+               case XkbClampIntoRange:
+                       effectiveGroup = nKeyGroups-1;
+                       break;
+               case XkbRedirectIntoRange:
+                       effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
+                       if (effectiveGroup>=nKeyGroups)
+                               effectiveGroup= 0;
+                       break;
+               }
+       }
+       col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
+       type = XkbKeyKeyType(xkb,key,effectiveGroup);
+
+       preserve= 0;
+       if (type->map) { /* find the column (shift level) within the group */
+               register int i;
+               register XkbKTMapEntryPtr entry;
+               for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
+                       if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
+                               col+= entry->level;
+                               if (type->preserve)
+                                       preserve= type->preserve[i].mask;
+                               break;
+                       }
+               }
+       }
+
+       if (keysym_rtrn!=NULL)
+               *keysym_rtrn= syms[col];
+       if (mods_rtrn)
+               *mods_rtrn= type->mods.mask&(~preserve);
+
+       return (syms[col]!=NoSymbol);
+}
+
+static XkbAction *XkbKeyActionPtr(XkbDescPtr xkb, KeyCode key, unsigned int mods)
+{
+       XkbKeyTypeRec *type;
+       int col,nKeyGroups;
+       unsigned effectiveGroup;
+       XkbAction *acts;
+
+       if (!XkbKeyHasActions(xkb, key))
+               return NULL;
+
+       nKeyGroups= XkbKeyNumGroups(xkb,key);
+       if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
+               return NULL;
+
+       acts = XkbKeyActionsPtr(xkb,key);
+
+       /* find the offset of the effective group */
+       col = 0;
+       effectiveGroup= XkbGroupForCoreState(mods);
+       if ( effectiveGroup>=nKeyGroups ) {
+               unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
+               switch (XkbOutOfRangeGroupAction(groupInfo)) {
+               default:
+                       effectiveGroup %= nKeyGroups;
+                       break;
+               case XkbClampIntoRange:
+                       effectiveGroup = nKeyGroups-1;
+                       break;
+               case XkbRedirectIntoRange:
+                       effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
+                       if (effectiveGroup>=nKeyGroups)
+                               effectiveGroup= 0;
+                       break;
+               }
+       }
+       col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
+       type = XkbKeyKeyType(xkb,key,effectiveGroup);
+
+       if (type->map) { /* find the column (shift level) within the group */
+               register int i;
+               register XkbKTMapEntryPtr entry;
+               for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
+                       if ((entry->active)&&((mods&type->mods.mask)==entry->mods.mask)) {
+                               col+= entry->level;
+                               break;
+                       }
+               }
+       }
+
+       return &acts[col];
+}
+
+static unsigned XkbKeyEffectiveGroup(XkbDescPtr xkb, KeyCode key, unsigned int mods)
+{
+       int nKeyGroups;
+       unsigned effectiveGroup;
+
+       nKeyGroups= XkbKeyNumGroups(xkb,key);
+       if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0))
+               return 0;
+
+       effectiveGroup= XkbGroupForCoreState(mods);
+       if ( effectiveGroup>=nKeyGroups ) {
+               unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
+               switch (XkbOutOfRangeGroupAction(groupInfo)) {
+               default:
+                       effectiveGroup %= nKeyGroups;
+                       break;
+               case XkbClampIntoRange:
+                       effectiveGroup = nKeyGroups-1;
+                       break;
+               case XkbRedirectIntoRange:
+                       effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
+                       if (effectiveGroup>=nKeyGroups)
+                               effectiveGroup= 0;
+                       break;
+               }
+       }
+
+       return effectiveGroup;
+}
+
+void vncPrepareInputDevices(void)
+{
+       /*
+        * Not ideal since these callbacks do not stack, but it's the only
+        * decent way we can reliably catch events for both the slave and
+        * master device.
+        */
+       mieqSetHandler(ET_KeyPress, vncXkbProcessDeviceEvent);
+       mieqSetHandler(ET_KeyRelease, vncXkbProcessDeviceEvent);
+}
+
+unsigned vncGetKeyboardState(void)
+{
+       DeviceIntPtr master;
+
+       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+       return XkbStateFieldFromRec(&master->key->xkbInfo->state);
+}
+
+unsigned vncGetLevelThreeMask(void)
+{
+       unsigned state;
+       KeyCode keycode;
+       XkbDescPtr xkb;
+       XkbAction *act;
+
+       /* Group state is still important */
+       state = vncGetKeyboardState();
+       state &= ~0xff;
+
+       keycode = vncKeysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
+       if (keycode == 0) {
+               keycode = vncKeysymToKeycode(XK_Mode_switch, state, NULL);
+               if (keycode == 0)
+                       return 0;
+       }
+
+       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+
+       act = XkbKeyActionPtr(xkb, keycode, state);
+       if (act == NULL)
+               return 0;
+       if (act->type != XkbSA_SetMods)
+               return 0;
+
+       if (act->mods.flags & XkbSA_UseModMapMods)
+               return xkb->map->modmap[keycode];
+       else
+               return act->mods.mask;
+}
+
+KeyCode vncPressShift(void)
+{
+       unsigned state;
+
+       XkbDescPtr xkb;
+       unsigned int key;
+
+       state = vncGetKeyboardState();
+       if (state & ShiftMask)
+               return 0;
+
+       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+       for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
+               XkbAction *act;
+               unsigned char mask;
+
+               act = XkbKeyActionPtr(xkb, key, state);
+               if (act == NULL)
+                       continue;
+
+               if (act->type != XkbSA_SetMods)
+                       continue;
+
+               if (act->mods.flags & XkbSA_UseModMapMods)
+                       mask = xkb->map->modmap[key];
+               else
+                       mask = act->mods.mask;
+
+               if ((mask & ShiftMask) == ShiftMask)
+                       return key;
+       }
+
+       return 0;
+}
+
+size_t vncReleaseShift(KeyCode *keys, size_t maxKeys)
+{
+       size_t count;
+
+       unsigned state;
+
+       DeviceIntPtr master;
+       XkbDescPtr xkb;
+       unsigned int key;
+
+       state = vncGetKeyboardState();
+       if (!(state & ShiftMask))
+               return 0;
+
+       count = 0;
+
+       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+       xkb = master->key->xkbInfo->desc;
+       for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
+               XkbAction *act;
+               unsigned char mask;
+
+               if (!key_is_down(master, key, KEY_PROCESSED))
+                       continue;
+
+               act = XkbKeyActionPtr(xkb, key, state);
+               if (act == NULL)
+                       continue;
+
+               if (act->type != XkbSA_SetMods)
+                       continue;
+
+               if (act->mods.flags & XkbSA_UseModMapMods)
+                       mask = xkb->map->modmap[key];
+               else
+                       mask = act->mods.mask;
+
+               if (!(mask & ShiftMask))
+                       continue;
+
+               if (count >= maxKeys)
+                       return 0;
+
+               keys[count++] = key;
+       }
+
+       return count;
+}
+
+KeyCode vncPressLevelThree(void)
+{
+       unsigned state, mask;
+
+       KeyCode keycode;
+       XkbDescPtr xkb;
+       XkbAction *act;
+
+       mask = vncGetLevelThreeMask();
+       if (mask == 0)
+               return 0;
+
+       state = vncGetKeyboardState();
+       if (state & mask)
+               return 0;
+
+       keycode = vncKeysymToKeycode(XK_ISO_Level3_Shift, state, NULL);
+       if (keycode == 0) {
+               keycode = vncKeysymToKeycode(XK_Mode_switch, state, NULL);
+               if (keycode == 0)
+                       return 0;
+       }
+
+       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+
+       act = XkbKeyActionPtr(xkb, keycode, state);
+       if (act == NULL)
+               return 0;
+       if (act->type != XkbSA_SetMods)
+               return 0;
+
+       return keycode;
+}
+
+size_t vncReleaseLevelThree(KeyCode *keys, size_t maxKeys)
+{
+       size_t count;
+
+       unsigned state, mask;
+
+       DeviceIntPtr master;
+       XkbDescPtr xkb;
+       unsigned int key;
+
+       mask = vncGetLevelThreeMask();
+       if (mask == 0)
+               return 0;
+
+       state = vncGetKeyboardState();
+       if (!(state & mask))
+               return 0;
+
+       count = 0;
+
+       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+       xkb = master->key->xkbInfo->desc;
+       for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
+               XkbAction *act;
+               unsigned char key_mask;
+
+               if (!key_is_down(master, key, KEY_PROCESSED))
+                       continue;
+
+               act = XkbKeyActionPtr(xkb, key, state);
+               if (act == NULL)
+                       continue;
+
+               if (act->type != XkbSA_SetMods)
+                       continue;
+
+               if (act->mods.flags & XkbSA_UseModMapMods)
+                       key_mask = xkb->map->modmap[key];
+               else
+                       key_mask = act->mods.mask;
+
+               if (!(key_mask & mask))
+                       continue;
+
+               if (count >= maxKeys)
+                       return 0;
+
+               keys[count++] = key;
+       }
+
+       return count;
+}
+
+KeyCode vncKeysymToKeycode(KeySym keysym, unsigned state, unsigned *new_state)
+{
+       XkbDescPtr xkb;
+       unsigned int key; // KeyCode has insufficient range for the loop
+       KeyCode fallback;
+       KeySym ks;
+       unsigned level_three_mask;
+
+       if (new_state != NULL)
+               *new_state = state;
+
+       fallback = 0;
+       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+       for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
+               unsigned int state_out;
+               KeySym dummy;
+               size_t fakeIdx;
+
+               XkbTranslateKeyCode(xkb, key, state, &state_out, &ks);
+               if (ks == NoSymbol)
+                       continue;
+
+               /*
+                * Despite every known piece of documentation on
+                * XkbTranslateKeyCode() stating that mods_rtrn returns
+                * the unconsumed modifiers, in reality it always
+                * returns the _potentially consumed_ modifiers.
+                */
+               state_out = state & ~state_out;
+               if (state_out & LockMask)
+                       XkbConvertCase(ks, &dummy, &ks);
+
+               if (ks != keysym)
+                       continue;
+
+               /*
+                * Some keys are never sent by a real keyboard and are
+                * used in the default layouts as a fallback for
+                * modifiers. Make sure we use them last as some
+                * applications can be confused by these normally
+                * unused keys.
+                */
+               for (fakeIdx = 0;
+                    fakeIdx < sizeof(fakeKeys)/sizeof(fakeKeys[0]);
+                    fakeIdx++) {
+                       if (key == fakeKeys[fakeIdx]) {
+                               if (fallback == 0)
+                                       fallback = key;
+                               break;
+                       }
+               }
+               if (fakeIdx < sizeof(fakeKeys)/sizeof(fakeKeys[0]))
+                       continue;
+
+               return key;
+       }
+
+       /* Use the fallback key, if one was found */
+       if (fallback != 0)
+               return fallback;
+
+       if (new_state == NULL)
+               return 0;
+
+       *new_state = (state & ~ShiftMask) |
+                    ((state & ShiftMask) ? 0 : ShiftMask);
+       key = vncKeysymToKeycode(keysym, *new_state, NULL);
+       if (key != 0)
+               return key;
+
+       level_three_mask = vncGetLevelThreeMask();
+       if (level_three_mask == 0)
+               return 0;
+
+       *new_state = (state & ~level_three_mask) | 
+                    ((state & level_three_mask) ? 0 : level_three_mask);
+       key = vncKeysymToKeycode(keysym, *new_state, NULL);
+       if (key != 0)
+               return key;
+
+       *new_state = (state & ~(ShiftMask | level_three_mask)) | 
+                    ((state & ShiftMask) ? 0 : ShiftMask) |
+                    ((state & level_three_mask) ? 0 : level_three_mask);
+       key = vncKeysymToKeycode(keysym, *new_state, NULL);
+       if (key != 0)
+               return key;
+
+       return 0;
+}
+
+int vncIsAffectedByNumLock(KeyCode keycode)
+{
+       unsigned state;
+
+       KeyCode numlock_keycode;
+       unsigned numlock_mask;
+
+       XkbDescPtr xkb;
+       XkbAction *act;
+
+       unsigned group;
+       XkbKeyTypeRec *type;
+
+       /* Group state is still important */
+       state = vncGetKeyboardState();
+       state &= ~0xff;
+
+       /*
+        * Not sure if hunting for a virtual modifier called "NumLock",
+        * or following the keysym Num_Lock is the best approach. We
+        * try the latter.
+        */
+       numlock_keycode = vncKeysymToKeycode(XK_Num_Lock, state, NULL);
+       if (numlock_keycode == 0)
+               return 0;
+
+       xkb = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT)->key->xkbInfo->desc;
+
+       act = XkbKeyActionPtr(xkb, numlock_keycode, state);
+       if (act == NULL)
+               return 0;
+       if (act->type != XkbSA_LockMods)
+               return 0;
+
+       if (act->mods.flags & XkbSA_UseModMapMods)
+               numlock_mask = xkb->map->modmap[keycode];
+       else
+               numlock_mask = act->mods.mask;
+
+       group = XkbKeyEffectiveGroup(xkb, keycode, state);
+       type = XkbKeyKeyType(xkb, keycode, group);
+       if ((type->mods.mask & numlock_mask) == 0)
+               return 0;
+
+       return 1;
+}
+
+KeyCode vncAddKeysym(KeySym keysym, unsigned state)
+{
+       DeviceIntPtr master;
+       XkbDescPtr xkb;
+       unsigned int key;
+
+       XkbEventCauseRec cause;
+       XkbChangesRec changes;
+
+       int types[1];
+       KeySym *syms;
+       KeySym upper, lower;
+
+       master = GetMaster(vncKeyboardDev, KEYBOARD_OR_FLOAT);
+       xkb = master->key->xkbInfo->desc;
+       for (key = xkb->max_key_code; key >= xkb->min_key_code; key--) {
+               if (XkbKeyNumGroups(xkb, key) == 0)
+                       break;
+       }
+
+       if (key < xkb->min_key_code)
+               return 0;
+
+       memset(&changes, 0, sizeof(changes));
+       memset(&cause, 0, sizeof(cause));
+
+       XkbSetCauseUnknown(&cause);
+
+       /*
+        * Tools like xkbcomp get confused if there isn't a name
+        * assigned to the keycode we're trying to use.
+        */
+       if (xkb->names && xkb->names->keys &&
+           (xkb->names->keys[key].name[0] == '\0')) {
+               xkb->names->keys[key].name[0] = 'I';
+               xkb->names->keys[key].name[1] = '0' + (key / 100) % 10;
+               xkb->names->keys[key].name[2] = '0' + (key /  10) % 10;
+               xkb->names->keys[key].name[3] = '0' + (key /   1) % 10;
+
+               changes.names.changed |= XkbKeyNamesMask;
+               changes.names.first_key = key;
+               changes.names.num_keys = 1;
+       }
+
+       /* FIXME: Verify that ONE_LEVEL/ALPHABETIC isn't screwed up */
+
+       /*
+        * For keysyms that are affected by Lock, we are better off
+        * using ALPHABETIC rather than ONE_LEVEL as the latter
+        * generally cannot produce lower case when Lock is active.
+        */
+       XkbConvertCase(keysym, &lower, &upper);
+       if (upper == lower)
+               types[XkbGroup1Index] = XkbOneLevelIndex;
+       else
+               types[XkbGroup1Index] = XkbAlphabeticIndex;
+
+       XkbChangeTypesOfKey(xkb, key, 1, XkbGroup1Mask, types, &changes.map);
+
+       syms = XkbKeySymsPtr(xkb,key);
+       if (upper == lower)
+               syms[0] = keysym;
+       else {
+               syms[0] = lower;
+               syms[1] = upper;
+       }
+
+       changes.map.changed |= XkbKeySymsMask;
+       changes.map.first_key_sym = key;
+       changes.map.num_key_syms = 1;
+
+       XkbSendNotification(master, &changes, &cause);
+
+       return key;
+}
+
+static void vncXkbProcessDeviceEvent(int screenNum,
+                                     InternalEvent *event,
+                                     DeviceIntPtr dev)
+{
+       unsigned int backupctrls;
+       XkbControlsPtr ctrls;
+
+       if (event->device_event.sourceid != vncKeyboardDev->id) {
+               dev->public.processInputProc(event, dev);
+               return;
+       }
+
+       /*
+        * We need to bypass AccessX since it is timing sensitive and
+        * the network can cause fake event delays.
+        */
+       ctrls = dev->key->xkbInfo->desc->ctrls;
+       backupctrls = ctrls->enabled_ctrls;
+       ctrls->enabled_ctrls &= ~XkbAllFilteredEventsMask;
+
+       /*
+        * This flag needs to be set for key repeats to be properly
+        * respected.
+        */
+       if ((event->device_event.type == ET_KeyPress) &&
+           key_is_down(dev, event->device_event.detail.key, KEY_PROCESSED))
+               event->device_event.key_repeat = TRUE;
+
+       dev->public.processInputProc(event, dev);
+
+       ctrls->enabled_ctrls = backupctrls;
+}