diff -r 4678f8c1d429 -r 7bc7e624f965 open-src/xserver/xvnc/upstream-input-refactor.patch --- a/open-src/xserver/xvnc/upstream-input-refactor.patch Mon May 09 10:12:33 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1896 +0,0 @@ -From 2f97d8a75e7371ac7f3a9a1338db55888754d7c0 Mon Sep 17 00:00:00 2001 -From: atkac -Date: Fri, 28 Aug 2009 12:03:11 +0000 -Subject: [PATCH] Initialize eventq in all cases. - -git-svn-id: https://tigervnc.svn.sourceforge.net/svnroot/tigervnc/trunk@3885 3789f03b-4d11-0410-bbf8-ca57d06f2519 ---- - unix/xserver/hw/vnc/XserverDesktop.cc | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc -index d6fe993..533f31b 100644 ---- a/unix/xserver/hw/vnc/XserverDesktop.cc -+++ b/unix/xserver/hw/vnc/XserverDesktop.cc -@@ -203,6 +203,8 @@ XserverDesktop::XserverDesktop(ScreenPtr pScreen_, - eventq = (xEvent *) xcalloc(sizeof(xEvent), GetMaximumEventsNum()); - if (!eventq) - FatalError("Couldn't allocate eventq\n"); -+#else -+ GetEventList(&eventq); - #endif - - /* --- -1.5.6.5 - -From 1093aa3149c24b362781ab7f19c4c63a6eb19990 Mon Sep 17 00:00:00 2001 -From: atkac -Date: Fri, 28 Aug 2009 12:04:20 +0000 -Subject: [PATCH] Add Input.h and Input.cc and move all mouse input related code there. - -git-svn-id: https://tigervnc.svn.sourceforge.net/svnroot/tigervnc/trunk@3886 3789f03b-4d11-0410-bbf8-ca57d06f2519 ---- - unix/xserver/hw/vnc/Input.cc | 167 +++++++++++++++++++++++++++++++++ - unix/xserver/hw/vnc/Input.h | 61 ++++++++++++ - unix/xserver/hw/vnc/Makefile.am | 6 +- - unix/xserver/hw/vnc/XserverDesktop.cc | 142 +--------------------------- - unix/xserver/hw/vnc/XserverDesktop.h | 5 +- - 5 files changed, 240 insertions(+), 141 deletions(-) - create mode 100644 unix/xserver/hw/vnc/Input.cc - create mode 100644 unix/xserver/hw/vnc/Input.h - -diff --git a/unix/xserver/hw/vnc/Input.cc b/unix/xserver/hw/vnc/Input.cc -new file mode 100644 -index 0000000..ca279f0 ---- /dev/null -+++ b/unix/xserver/hw/vnc/Input.cc -@@ -0,0 +1,167 @@ -+/* Copyright (C) 2009 TightVNC Team -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * 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 -+#endif -+ -+#include "Input.h" -+#include "xorg-version.h" -+ -+extern "C" { -+#include "mi.h" -+} -+ -+/* Event queue is shared between all devices. */ -+#if XORG == 15 -+static xEvent *eventq = NULL; -+#else -+static EventList *eventq = NULL; -+#endif -+ -+static void initEventq(void) -+{ -+ /* eventq is never free()-ed because it exists during server life. */ -+ if (eventq == NULL) { -+#if XORG == 15 -+ eventq = (xEvent *)xcalloc(sizeof(xEvent), -+ GetMaximumEventsNum()); -+ if (!eventq) -+ FatalError("Couldn't allocate eventq\n"); -+#else -+ GetEventList(&eventq); -+#endif -+ } -+} -+ -+static void enqueueEvents(DeviceIntPtr dev, int n) -+{ -+ int i; -+ -+ for (i = 0; i < n; i++) { -+ /* -+ * Passing arguments in global variable eventq is probably not -+ * good programming practise but in this case it is safe and -+ * clear. -+ */ -+ mieqEnqueue(dev, -+#if XORG == 15 -+ eventq + i -+#else -+ (eventq + i)->event -+#endif -+ ); -+ } -+} -+ -+/* Pointer device pre-declarations */ -+#define BUTTONS 5 -+static int pointerProc(DeviceIntPtr pDevice, int onoff); -+ -+/* Pointer device methods */ -+ -+PointerDevice::PointerDevice(rfb::VNCServerST *_server) -+ : server(_server), oldButtonMask(0) -+{ -+ dev = AddInputDevice( -+#if XORG >= 16 -+ serverClient, -+#endif -+ pointerProc, TRUE); -+ RegisterPointerDevice(dev); -+ initEventq(); -+} -+ -+void PointerDevice::ButtonAction(int buttonMask) -+{ -+ int i, n; -+ -+ for (i = 0; i < BUTTONS; i++) { -+ if ((buttonMask ^ oldButtonMask) & (1 << i)) { -+ int action = (buttonMask & (1<setCursorPos(cursorPos); -+ server->tryUpdate(); -+} -+ -+static int pointerProc(DeviceIntPtr pDevice, int onoff) -+{ -+ BYTE map[BUTTONS + 1]; -+ DevicePtr pDev = (DevicePtr)pDevice; -+ int i; -+ -+ switch (onoff) { -+ case DEVICE_INIT: -+ for (i = 0; i < BUTTONS + 1; i++) -+ map[i] = i; -+ -+ InitPointerDeviceStruct(pDev, map, BUTTONS, -+#if XORG == 15 -+ GetMotionHistory, -+#endif -+ (PtrCtrlProcPtr)NoopDDA, -+ GetMotionHistorySize(), 2); -+ break; -+ case DEVICE_ON: -+ pDev->on = TRUE; -+ break; -+ case DEVICE_OFF: -+ pDev->on = FALSE; -+ break; -+#if 0 -+ case DEVICE_CLOSE: -+ break; -+#endif -+ } -+ -+ return Success; -+} -+ -diff --git a/unix/xserver/hw/vnc/Input.h b/unix/xserver/hw/vnc/Input.h -new file mode 100644 -index 0000000..49cedf2 ---- /dev/null -+++ b/unix/xserver/hw/vnc/Input.h -@@ -0,0 +1,61 @@ -+/* Copyright (C) 2009 TightVNC Team -+ * Copyright (C) 2009 Red Hat, Inc. -+ * -+ * 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_ -+ -+#ifdef HAVE_DIX_CONFIG_H -+#include -+#endif -+ -+#include -+ -+extern "C" { -+#include "input.h" -+}; -+ -+/* Represents pointer device. */ -+class PointerDevice { -+public: -+ /* Create new PointerDevice instance. */ -+ PointerDevice(rfb::VNCServerST *_server); -+ -+ /* -+ * Press or release buttons. Relationship between buttonMask and -+ * buttons is specified in RFB protocol. -+ */ -+ void ButtonAction(int buttonMask); -+ -+ /* Move pointer to target location (point coords are absolute). */ -+ void Move(const rfb::Point &point); -+ -+ /* -+ * Send pointer position to clients. If not called then Move() calls -+ * won't be visible to clients. -+ */ -+ void Sync(void); -+private: -+ rfb::VNCServerST *server; -+ DeviceIntPtr dev; -+ int oldButtonMask; -+ rfb::Point cursorPos, oldCursorPos; -+}; -+ -+#endif -diff --git a/unix/xserver/hw/vnc/Makefile.am b/unix/xserver/hw/vnc/Makefile.am -index a39a10d..c2e78df 100644 ---- a/unix/xserver/hw/vnc/Makefile.am -+++ b/unix/xserver/hw/vnc/Makefile.am -@@ -9,9 +9,11 @@ COMMON_LIBS=$(NETWORK_LIB) $(RFB_LIB) $(RDR_LIB) $(XREGION_LIB) - - noinst_LTLIBRARIES = libvnccommon.la - --HDRS = RegionHelper.h vncExtInit.h vncHooks.h XserverDesktop.h xorg-version.h -+HDRS = RegionHelper.h vncExtInit.h vncHooks.h XserverDesktop.h xorg-version.h \ -+ Input.h - --libvnccommon_la_SOURCES = $(HDRS) vncExtInit.cc vncHooks.cc XserverDesktop.cc -+libvnccommon_la_SOURCES = $(HDRS) vncExtInit.cc vncHooks.cc XserverDesktop.cc \ -+ Input.cc - - libvnccommon_la_CPPFLAGS = -DVENDOR_RELEASE="$(VENDOR_RELEASE)" \ - -DVENDOR_STRING="\"$(VENDOR_STRING)\"" -I$(LIB_DIR) \ -diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc -index 533f31b..58f70d9 100644 ---- a/unix/xserver/hw/vnc/XserverDesktop.cc -+++ b/unix/xserver/hw/vnc/XserverDesktop.cc -@@ -42,6 +42,7 @@ - #include "XserverDesktop.h" - #include "vncExtInit.h" - #include "xorg-version.h" -+#include "Input.h" - - extern "C" { - #define public c_public -@@ -77,7 +78,6 @@ CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); - } - - static DeviceIntPtr vncKeyboardDevice = NULL; --static DeviceIntPtr vncPointerDevice = NULL; - #if XORG == 15 - static xEvent *eventq = NULL; - #else -@@ -85,7 +85,6 @@ static EventList *eventq = NULL; - #endif - - static int vfbKeybdProc(DeviceIntPtr pDevice, int onoff); --static int vfbMouseProc(DeviceIntPtr pDevice, int onoff); - - using namespace rfb; - using namespace network; -@@ -180,7 +179,6 @@ XserverDesktop::XserverDesktop(ScreenPtr pScreen_, - listener(listener_), httpListener(httpListener_), - cmap(0), deferredUpdateTimerSet(false), - grabbing(false), ignoreHooks_(false), directFbptr(true), -- oldButtonMask(0), - queryConnectId(0) - { - format = pf; -@@ -221,14 +219,7 @@ XserverDesktop::XserverDesktop(ScreenPtr pScreen_, - RegisterKeyboardDevice(vncKeyboardDevice); - } - -- if (vncPointerDevice == NULL) { -- vncPointerDevice = AddInputDevice( --#if XORG >= 16 -- serverClient, --#endif -- vfbMouseProc, TRUE); -- RegisterPointerDevice(vncPointerDevice); -- } -+ pointerDevice = new PointerDevice(server); - } - - XserverDesktop::~XserverDesktop() -@@ -237,6 +228,7 @@ XserverDesktop::~XserverDesktop() - delete [] data; - TimerFree(deferredUpdateTimer); - TimerFree(dummyTimer); -+ delete pointerDevice; - delete httpServer; - delete server; - } -@@ -555,43 +547,9 @@ void XserverDesktop::add_copied(RegionPtr dst, int dx, int dy) - } - } - --void XserverDesktop::positionCursor() --{ -- if (!cursorPos.equals(oldCursorPos)) { -- oldCursorPos = cursorPos; -- (*pScreen->SetCursorPosition) ( --#if XORG >= 16 -- vncPointerDevice, --#endif -- pScreen, cursorPos.x, cursorPos.y, FALSE); -- server->setCursorPos(cursorPos); -- server->tryUpdate(); -- } --} -- - void XserverDesktop::blockHandler(fd_set* fds) - { - try { --#if XORG == 15 -- ScreenPtr screenWithCursor = GetCurrentRootWindow()->drawable.pScreen; --#else -- ScreenPtr screenWithCursor = -- GetCurrentRootWindow(vncPointerDevice)->drawable.pScreen; --#endif -- if (screenWithCursor == pScreen) { -- int x, y; -- GetSpritePosition( --#if XORG >= 16 -- vncPointerDevice, --#endif -- &x, &y); -- if (x != cursorPos.x || y != cursorPos.y) { -- cursorPos = oldCursorPos = Point(x, y); -- server->setCursorPos(cursorPos); -- server->tryUpdate(); -- } -- } -- - if (listener) - FD_SET(listener->getFd(), fds); - if (httpListener) -@@ -678,7 +636,7 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds) - } - } - -- positionCursor(); -+ pointerDevice->Sync(); - } - - int timeout = server->checkTimeouts(); -@@ -737,63 +695,8 @@ void XserverDesktop::approveConnection(void* opaqueId, bool accept, - - void XserverDesktop::pointerEvent(const Point& pos, int buttonMask) - { -- int i, j, n, valuators[2]; -- -- // SetCursorPosition seems to be very expensive (at least on XFree86 3.3.6 -- // for S3), so we delay calling it until positionCursor() is called at the -- // end of processing a load of RFB. -- //(*pScreen->SetCursorPosition) (pScreen, pos.x, pos.y, FALSE); -- -- NewCurrentScreen( --#if XORG >= 16 -- vncPointerDevice, --#endif -- pScreen, pos.x, pos.y); -- -- if (!pos.equals(cursorPos)) { -- valuators[0] = pos.x; -- valuators[1] = pos.y; -- --#if XORG >= 16 -- GetEventList(&eventq); --#endif -- n = GetPointerEvents (eventq, vncPointerDevice, MotionNotify, 0, -- POINTER_ABSOLUTE, 0, 2, valuators); -- -- for (i = 0; i < n; i++) { -- mieqEnqueue (vncPointerDevice, --#if XORG == 15 -- eventq + i --#else -- (eventq + i)->event --#endif -- ); -- } -- } -- -- for (i = 0; i < 5; i++) { -- if ((buttonMask ^ oldButtonMask) & (1<event --#endif -- ); -- } -- } -- } -- -- cursorPos = pos; -- oldButtonMask = buttonMask; -+ pointerDevice->Move(pos); -+ pointerDevice->ButtonAction(buttonMask); - } - - void XserverDesktop::clientCutText(const char* str, int len) -@@ -1481,36 +1384,3 @@ static int vfbKeybdProc(DeviceIntPtr pDevice, int onoff) - return Success; - } - --static int vfbMouseProc(DeviceIntPtr pDevice, int onoff) --{ -- BYTE map[6]; -- DevicePtr pDev = (DevicePtr)pDevice; -- -- switch (onoff) -- { -- case DEVICE_INIT: -- map[1] = 1; -- map[2] = 2; -- map[3] = 3; -- map[4] = 4; -- map[5] = 5; -- InitPointerDeviceStruct(pDev, map, 5, --#if XORG == 15 -- GetMotionHistory, --#endif -- (PtrCtrlProcPtr)NoopDDA, GetMotionHistorySize(), 2); -- break; -- -- case DEVICE_ON: -- pDev->on = TRUE; -- break; -- -- case DEVICE_OFF: -- pDev->on = FALSE; -- break; -- -- case DEVICE_CLOSE: -- break; -- } -- return Success; --} -diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h -index 7729d3f..9f300f5 100644 ---- a/unix/xserver/hw/vnc/XserverDesktop.h -+++ b/unix/xserver/hw/vnc/XserverDesktop.h -@@ -32,6 +32,7 @@ - #include - #include - #include -+#include "Input.h" - - extern "C" { - #define class c_class -@@ -68,7 +69,6 @@ public: - void setCursor(CursorPtr cursor); - void add_changed(RegionPtr reg); - void add_copied(RegionPtr dst, int dx, int dy); -- void positionCursor(); - void ignoreHooks(bool b) { ignoreHooks_ = b; } - void blockHandler(fd_set* fds); - void wakeupHandler(fd_set* fds, int nfds); -@@ -122,6 +122,7 @@ private: - pointer arg); - void deferUpdate(); - ScreenPtr pScreen; -+ PointerDevice *pointerDevice; - OsTimerPtr deferredUpdateTimer, dummyTimer; - rfb::VNCServerST* server; - rfb::HTTPServer* httpServer; -@@ -133,8 +134,6 @@ private: - bool grabbing; - bool ignoreHooks_; - bool directFbptr; -- int oldButtonMask; -- rfb::Point cursorPos, oldCursorPos; - - void* queryConnectId; - rfb::CharArray queryConnectAddress; --- -1.5.6.5 - -From 845dbbfbb6a2c0e1a4981920121935febe7c0a50 Mon Sep 17 00:00:00 2001 -From: atkac -Date: Fri, 28 Aug 2009 12:05:24 +0000 -Subject: [PATCH] Move keyboard input related code to Input.h and Input.cc. - -git-svn-id: https://tigervnc.svn.sourceforge.net/svnroot/tigervnc/trunk@3887 3789f03b-4d11-0410-bbf8-ca57d06f2519 ---- - unix/xserver/hw/vnc/Input.cc | 606 ++++++++++++++++++++++++++++++++- - unix/xserver/hw/vnc/Input.h | 13 + - unix/xserver/hw/vnc/XserverDesktop.cc | 589 +------------------------------- - unix/xserver/hw/vnc/XserverDesktop.h | 1 + - 4 files changed, 622 insertions(+), 587 deletions(-) - -diff --git a/unix/xserver/hw/vnc/Input.cc b/unix/xserver/hw/vnc/Input.cc -index ca279f0..478240c 100644 ---- a/unix/xserver/hw/vnc/Input.cc -+++ b/unix/xserver/hw/vnc/Input.cc -@@ -21,13 +21,49 @@ - #include - #endif - -+#include - #include "Input.h" - #include "xorg-version.h" -+#include "vncExtInit.h" - - extern "C" { -+#define public c_public -+#define class c_class -+#include "inputstr.h" - #include "mi.h" -+#ifndef XKB_IN_SERVER -+#define XKB_IN_SERVER -+#endif -+#ifdef XKB -+/* -+ * This include is needed to use XkbConvertCase instead of XConvertCase even if -+ * we don't use XKB extension. -+ */ -+#include -+#endif -+#if XORG >= 16 -+#include "exevents.h" -+extern void -+CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); -+#endif -+#include -+#include -+#undef public -+#undef class - } - -+using namespace rdr; -+using namespace rfb; -+ -+static LogWriter vlog("Input"); -+ -+#define BUTTONS 5 -+static int pointerProc(DeviceIntPtr pDevice, int onoff); -+ -+static int keyboardProc(DeviceIntPtr pDevice, int onoff); -+static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col); -+static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col); -+ - /* Event queue is shared between all devices. */ - #if XORG == 15 - static xEvent *eventq = NULL; -@@ -70,10 +106,6 @@ static void enqueueEvents(DeviceIntPtr dev, int n) - } - } - --/* Pointer device pre-declarations */ --#define BUTTONS 5 --static int pointerProc(DeviceIntPtr pDevice, int onoff); -- - /* Pointer device methods */ - - PointerDevice::PointerDevice(rfb::VNCServerST *_server) -@@ -165,3 +197,569 @@ static int pointerProc(DeviceIntPtr pDevice, int onoff) - return Success; - } - -+/* KeyboardDevice methods */ -+ -+KeyboardDevice::KeyboardDevice(void) -+{ -+ dev = AddInputDevice( -+#if XORG >= 16 -+ serverClient, -+#endif -+ keyboardProc, TRUE); -+ RegisterKeyboardDevice(dev); -+ initEventq(); -+} -+ -+#define IS_PRESSED(keyc, keycode) \ -+ ((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7))) -+ -+/* -+ * ModifierState is a class which helps simplify generating a "fake" press or -+ * release of shift, ctrl, alt, etc. An instance of the class is created for -+ * every modifier which may need to be pressed or released. Then either -+ * press() or release() may be called to make sure that the corresponding keys -+ * are in the right state. The destructor of the class automatically reverts -+ * to the previous state. Each modifier may have multiple keys associated with -+ * it, so in the case of a fake release, this may involve releasing more than -+ * one key. -+ */ -+ -+class ModifierState { -+public: -+ ModifierState(DeviceIntPtr _dev, int _modIndex) -+ : modIndex(_modIndex), nKeys(0), keys(0), pressed(false), -+ dev(_dev) {} -+ -+ ~ModifierState() -+ { -+ for (int i = 0; i < nKeys; i++) -+ generateXKeyEvent(keys[i], !pressed); -+ delete [] keys; -+ } -+ -+ void press() -+ { -+ KeyClassPtr keyc = dev->key; -+ if (!(keyc->state & (1 << modIndex))) { -+ int index = modIndex * keyc->maxKeysPerModifier; -+ tempKeyEvent(keyc->modifierKeyMap[index], true); -+ pressed = true; -+ } -+ } -+ -+ void release() -+ { -+ KeyClassPtr keyc = dev->key; -+ if ((keyc->state & (1 << modIndex)) == 0) -+ return; -+ -+ for (int k = 0; k < keyc->maxKeysPerModifier; k++) { -+ int index = modIndex * keyc->maxKeysPerModifier + k; -+ int keycode = keyc->modifierKeyMap[index]; -+ if (keycode && IS_PRESSED(keyc, keycode)) -+ tempKeyEvent(keycode, false); -+ } -+ } -+ -+private: -+ void tempKeyEvent(int keycode, bool down) -+ { -+ if (keycode) { -+ if (!keys) keys = new int[dev->key->maxKeysPerModifier]; -+ keys[nKeys++] = keycode; -+ generateXKeyEvent(keycode, down); -+ } -+ } -+ -+ void generateXKeyEvent(int keycode, bool down) -+ { -+ int n, action; -+ -+ action = down ? KeyPress : KeyRelease; -+ n = GetKeyboardEvents(eventq, dev, action, keycode); -+ enqueueEvents(dev, n); -+ -+ vlog.debug("fake keycode %d %s", keycode, -+ down ? "down" : "up"); -+ } -+ -+ int modIndex; -+ int nKeys; -+ int *keys; -+ bool pressed; -+ DeviceIntPtr dev; -+}; -+ -+ -+/* 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 }, -+}; -+ -+/* -+ * keyEvent() - work out the best keycode corresponding to the keysym sent by -+ * the viewer. This is non-trivial because we can't assume much about the -+ * local keyboard layout. We must also find out which column of the keyboard -+ * mapping the keysym is in, and alter the shift state appropriately. Column 0 -+ * means both shift and "mode_switch" (AltGr) must be released, column 1 means -+ * shift must be pressed and mode_switch released, column 2 means shift must be -+ * released and mode_switch pressed, and column 3 means both shift and -+ * mode_switch must be pressed. -+ * -+ * Magic, which dynamically adds keysym<->keycode mapping depends on X.Org -+ * version. Quick explanation of that "magic": -+ * -+ * 1.5 -+ * - has only one core keyboard so we have to keep core keyboard mapping -+ * synchronized with vncKeyboardDevice. Do it via SwitchCoreKeyboard() -+ * -+ * 1.6 (aka MPX - Multi pointer X) -+ * - multiple master devices (= core devices) exists, keep vncKeyboardDevice -+ * synchronized with proper master device -+ */ -+ -+void KeyboardDevice::keyEvent(rdr::U32 keysym, bool down) -+{ -+ DeviceIntPtr master; -+ KeyClassPtr keyc = dev->key; -+ KeySymsPtr keymap = &keyc->curKeySyms; -+ KeySym *map = keymap->map; -+ KeyCode minKeyCode = keymap->minKeyCode; -+ KeyCode maxKeyCode = keymap->maxKeyCode; -+ int mapWidth = keymap->mapWidth; -+ unsigned int i, n; -+ int j, k, action; -+ -+ if (keysym == XK_Caps_Lock) { -+ vlog.debug("Ignoring caps lock"); -+ return; -+ } -+ -+ /* find which modifier Mode_switch is on. */ -+ int modeSwitchMapIndex = 0; -+ for (i = 3; i < 8; i++) { -+ for (k = 0; k < keyc->maxKeysPerModifier; k++) { -+ int index = i * keyc->maxKeysPerModifier + k; -+ int keycode = keyc->modifierKeyMap[index]; -+ -+ if (keycode == 0) -+ continue; -+ -+ for (j = 0; j < mapWidth; j++) { -+ if (map[(keycode - minKeyCode) * mapWidth + j] -+ == XK_Mode_switch) { -+ modeSwitchMapIndex = i; -+ goto ModeSwitchFound; -+ } -+ } -+ } -+ } -+ModeSwitchFound: -+ -+ int col = 0; -+ if ((keyc->state & (1 << ShiftMapIndex)) != 0) -+ col |= 1; -+ if (modeSwitchMapIndex != 0 && -+ ((keyc->state & (1 << modeSwitchMapIndex))) != 0) -+ col |= 2; -+ -+ int kc = KeysymToKeycode(keymap, keysym, &col); -+ -+ /* -+ * Sort out the "shifted Tab" mess. If we are sent a shifted Tab, -+ * generate a local shifted Tab regardless of what the "shifted Tab" -+ * keysym is on the local keyboard (it might be Tab, ISO_Left_Tab or -+ * HP's private BackTab keysym, and quite possibly some others too). -+ * We never get ISO_Left_Tab here because it's already been translated -+ * in VNCSConnectionST. -+ */ -+ if (keysym == XK_Tab && ((keyc->state & (1 << ShiftMapIndex))) != 0) -+ col |= 1; -+ -+ if (kc == 0) { -+ /* -+ * Not a direct match in the local keyboard mapping. Check for -+ * alternative keysyms with the same meaning. -+ */ -+ for (i = 0; i < sizeof(altKeysym) / sizeof(altKeysym_t); i++) { -+ if (keysym == altKeysym[i].a) -+ kc = KeysymToKeycode(keymap, altKeysym[i].b, -+ &col); -+ else if (keysym == altKeysym[i].b) -+ kc = KeysymToKeycode(keymap, altKeysym[i].a, -+ &col); -+ if (kc) -+ break; -+ } -+ } -+ -+ if (kc == 0) { -+ /* Dynamically add a new key to the keyboard mapping. */ -+ for (kc = maxKeyCode; kc >= minKeyCode; kc--) { -+ if (map[(kc - minKeyCode) * mapWidth] != 0) -+ continue; -+ -+ map[(kc - minKeyCode) * mapWidth] = keysym; -+ col = 0; -+ -+ vlog.info("Added unknown keysym 0x%x to keycode %d", -+ keysym, kc); -+#if XORG == 15 -+ master = inputInfo.keyboard; -+#else -+ master = dev->u.master; -+#endif -+ void *slave = dixLookupPrivate(&master->devPrivates, -+ CoreDevicePrivateKey); -+ if (dev == slave) { -+ dixSetPrivate(&master->devPrivates, -+ CoreDevicePrivateKey, NULL); -+#if XORG == 15 -+ SwitchCoreKeyboard(dev); -+#else -+ CopyKeyClass(dev, master); -+#endif -+ } -+ break; -+ } -+ } -+ -+ if (kc < minKeyCode) { -+ vlog.info("Keyboard mapping full - ignoring unknown keysym " -+ "0x%x",keysym); -+ return; -+ } -+ -+ /* -+ * See if it's a modifier key. If so, then don't do any auto-repeat, -+ * because the X server will translate each press into a release -+ * followed by a press. -+ */ -+ for (i = 0; i < 8; i++) { -+ for (k = 0; k < keyc->maxKeysPerModifier; k++) { -+ int index = i * keyc->maxKeysPerModifier + k; -+ if (kc == keyc->modifierKeyMap[index] && -+ IS_PRESSED(keyc,kc) && down) -+ return; -+ } -+ } -+ -+ ModifierState shift(dev, ShiftMapIndex); -+ ModifierState modeSwitch(dev, modeSwitchMapIndex); -+ if (down) { -+ if (col & 1) -+ shift.press(); -+ else -+ shift.release(); -+ if (modeSwitchMapIndex) { -+ if (col & 2) -+ modeSwitch.press(); -+ else -+ modeSwitch.release(); -+ } -+ } -+ -+ vlog.debug("keycode %d %s", kc, down ? "down" : "up"); -+ action = down ? KeyPress : KeyRelease; -+ n = GetKeyboardEvents(eventq, dev, action, kc); -+ enqueueEvents(dev, n); -+} -+ -+static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col) -+{ -+ int per = keymap->mapWidth; -+ KeySym *syms; -+ KeySym lsym, usym; -+ -+ if ((col < 0) || ((col >= per) && (col > 3)) || -+ (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode)) -+ return NoSymbol; -+ -+ syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; -+ if (col >= 4) -+ return syms[col]; -+ -+ if (col > 1) { -+ while ((per > 2) && (syms[per - 1] == NoSymbol)) -+ per--; -+ if (per < 3) -+ col -= 2; -+ } -+ -+ if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) { -+ XConvertCase(syms[col&~1], &lsym, &usym); -+ if (!(col & 1)) -+ return lsym; -+ /* -+ * I'm commenting out this logic because it's incorrect even -+ * though it was copied from the Xlib sources. The X protocol -+ * book quite clearly states that where a group consists of -+ * element 1 being a non-alphabetic keysym and element 2 being -+ * NoSymbol that you treat the second element as being the -+ * same as the first. This also tallies with the behaviour -+ * produced by the installed Xlib on my linux box (I believe -+ * this is because it uses some XKB code rather than the -+ * original Xlib code - compare XKBBind.c with KeyBind.c in -+ * lib/X11). -+ */ -+#if 0 -+ else if (usym == lsym) -+ return NoSymbol; -+#endif -+ else -+ return usym; -+ } -+ -+ return syms[col]; -+} -+ -+/* -+ * KeysymToKeycode() - find the keycode and column corresponding to the given -+ * keysym. The value of col passed in should be the column determined from the -+ * current shift state. If the keysym can be found in that column we prefer -+ * that to finding it in a different column (which would require fake events to -+ * alter the shift state). -+ */ -+static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col) -+{ -+ int i, j; -+ -+ j = *col; -+ for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { -+ if (KeyCodetoKeySym(keymap, i, j) == ks) -+ return i; -+ } -+ -+ for (j = 0; j < keymap->mapWidth; j++) { -+ for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { -+ if (KeyCodetoKeySym(keymap, i, j) == ks) { -+ *col = j; -+ return i; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+/* Fairly standard US PC Keyboard */ -+ -+#define MIN_KEY 8 -+#define MAX_KEY 255 -+#define MAP_LEN (MAX_KEY - MIN_KEY + 1) -+#define KEYSYMS_PER_KEY 2 -+KeySym keyboardMap[MAP_LEN * KEYSYMS_PER_KEY] = { -+ NoSymbol, NoSymbol, -+ XK_Escape, NoSymbol, -+ XK_1, XK_exclam, -+ XK_2, XK_at, -+ XK_3, XK_numbersign, -+ XK_4, XK_dollar, -+ XK_5, XK_percent, -+ XK_6, XK_asciicircum, -+ XK_7, XK_ampersand, -+ XK_8, XK_asterisk, -+ XK_9, XK_parenleft, -+ XK_0, XK_parenright, -+ XK_minus, XK_underscore, -+ XK_equal, XK_plus, -+ XK_BackSpace, NoSymbol, -+ XK_Tab, NoSymbol, -+ XK_q, XK_Q, -+ XK_w, XK_W, -+ XK_e, XK_E, -+ XK_r, XK_R, -+ XK_t, XK_T, -+ XK_y, XK_Y, -+ XK_u, XK_U, -+ XK_i, XK_I, -+ XK_o, XK_O, -+ XK_p, XK_P, -+ XK_bracketleft, XK_braceleft, -+ XK_bracketright, XK_braceright, -+ XK_Return, NoSymbol, -+ XK_Control_L, NoSymbol, -+ XK_a, XK_A, -+ XK_s, XK_S, -+ XK_d, XK_D, -+ XK_f, XK_F, -+ XK_g, XK_G, -+ XK_h, XK_H, -+ XK_j, XK_J, -+ XK_k, XK_K, -+ XK_l, XK_L, -+ XK_semicolon, XK_colon, -+ XK_apostrophe, XK_quotedbl, -+ XK_grave, XK_asciitilde, -+ XK_Shift_L, NoSymbol, -+ XK_backslash, XK_bar, -+ XK_z, XK_Z, -+ XK_x, XK_X, -+ XK_c, XK_C, -+ XK_v, XK_V, -+ XK_b, XK_B, -+ XK_n, XK_N, -+ XK_m, XK_M, -+ XK_comma, XK_less, -+ XK_period, XK_greater, -+ XK_slash, XK_question, -+ XK_Shift_R, NoSymbol, -+ XK_KP_Multiply, NoSymbol, -+ XK_Alt_L, XK_Meta_L, -+ XK_space, NoSymbol, -+ /* XK_Caps_Lock */ NoSymbol, NoSymbol, -+ XK_F1, NoSymbol, -+ XK_F2, NoSymbol, -+ XK_F3, NoSymbol, -+ XK_F4, NoSymbol, -+ XK_F5, NoSymbol, -+ XK_F6, NoSymbol, -+ XK_F7, NoSymbol, -+ XK_F8, NoSymbol, -+ XK_F9, NoSymbol, -+ XK_F10, NoSymbol, -+ XK_Num_Lock, XK_Pointer_EnableKeys, -+ XK_Scroll_Lock, NoSymbol, -+ XK_KP_Home, XK_KP_7, -+ XK_KP_Up, XK_KP_8, -+ XK_KP_Prior, XK_KP_9, -+ XK_KP_Subtract, NoSymbol, -+ XK_KP_Left, XK_KP_4, -+ XK_KP_Begin, XK_KP_5, -+ XK_KP_Right, XK_KP_6, -+ XK_KP_Add, NoSymbol, -+ XK_KP_End, XK_KP_1, -+ XK_KP_Down, XK_KP_2, -+ XK_KP_Next, XK_KP_3, -+ XK_KP_Insert, XK_KP_0, -+ XK_KP_Delete, XK_KP_Decimal, -+ NoSymbol, NoSymbol, -+ NoSymbol, NoSymbol, -+ NoSymbol, NoSymbol, -+ XK_F11, NoSymbol, -+ XK_F12, NoSymbol, -+ XK_Home, NoSymbol, -+ XK_Up, NoSymbol, -+ XK_Prior, NoSymbol, -+ XK_Left, NoSymbol, -+ NoSymbol, NoSymbol, -+ XK_Right, NoSymbol, -+ XK_End, NoSymbol, -+ XK_Down, NoSymbol, -+ XK_Next, NoSymbol, -+ XK_Insert, NoSymbol, -+ XK_Delete, NoSymbol, -+ XK_KP_Enter, NoSymbol, -+ XK_Control_R, NoSymbol, -+ XK_Pause, XK_Break, -+ XK_Print, XK_Execute, -+ XK_KP_Divide, NoSymbol, -+ XK_Alt_R, XK_Meta_R, -+}; -+ -+static Bool GetMappings(KeySymsPtr pKeySyms, CARD8 *pModMap) -+{ -+ int i; -+ -+ for (i = 0; i < MAP_LENGTH; i++) -+ pModMap[i] = NoSymbol; -+ -+ for (i = 0; i < MAP_LEN; i++) { -+ if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Caps_Lock) -+ pModMap[i + MIN_KEY] = LockMask; -+ else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_L || -+ keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_R) -+ pModMap[i + MIN_KEY] = ShiftMask; -+ else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_L || -+ keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_R) -+ pModMap[i + MIN_KEY] = ControlMask; -+ else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_L || -+ keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_R) -+ pModMap[i + MIN_KEY] = Mod1Mask; -+ } -+ -+ pKeySyms->minKeyCode = MIN_KEY; -+ pKeySyms->maxKeyCode = MAX_KEY; -+ pKeySyms->mapWidth = KEYSYMS_PER_KEY; -+ pKeySyms->map = keyboardMap; -+ -+ return TRUE; -+} -+ -+static void keyboardBell(int percent, DeviceIntPtr device, pointer ctrl, -+ int class_) -+{ -+ if (percent > 0) -+ vncBell(); -+} -+ -+static int keyboardProc(DeviceIntPtr pDevice, int onoff) -+{ -+ KeySymsRec keySyms; -+ CARD8 modMap[MAP_LENGTH]; -+ DevicePtr pDev = (DevicePtr)pDevice; -+ -+ switch (onoff) { -+ case DEVICE_INIT: -+ GetMappings(&keySyms, modMap); -+ InitKeyboardDeviceStruct(pDev, &keySyms, modMap, keyboardBell, -+ (KbdCtrlProcPtr)NoopDDA); -+ break; -+ case DEVICE_ON: -+ pDev->on = TRUE; -+ break; -+ case DEVICE_OFF: -+ pDev->on = FALSE; -+ break; -+#if 0 -+ case DEVICE_CLOSE: -+ break; -+#endif -+ } -+ -+ return Success; -+} -+ -diff --git a/unix/xserver/hw/vnc/Input.h b/unix/xserver/hw/vnc/Input.h -index 49cedf2..1bfec92 100644 ---- a/unix/xserver/hw/vnc/Input.h -+++ b/unix/xserver/hw/vnc/Input.h -@@ -58,4 +58,17 @@ private: - rfb::Point cursorPos, oldCursorPos; - }; - -+/* Represents keyboard device. */ -+class KeyboardDevice { -+public: -+ /* Create new Keyboard device instance. */ -+ KeyboardDevice(void); -+ -+ void Press(rdr::U32 keysym) { keyEvent(keysym, true); } -+ void Release(rdr::U32 keysym) { keyEvent(keysym, false); } -+private: -+ void keyEvent(rdr::U32 keysym, bool down); -+ DeviceIntPtr dev; -+}; -+ - #endif -diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc -index 58f70d9..66c92d2 100644 ---- a/unix/xserver/hw/vnc/XserverDesktop.cc -+++ b/unix/xserver/hw/vnc/XserverDesktop.cc -@@ -50,26 +50,7 @@ extern "C" { - - extern char *display; - --#include "inputstr.h" --#include "servermd.h" - #include "colormapst.h" --#include "resource.h" --#include "cursorstr.h" --#include "windowstr.h" --#include "mi.h" --#define XK_CYRILLIC --#include --#ifndef XKB_IN_SERVER --#define XKB_IN_SERVER --#endif --#ifdef XKB --#include --#endif --#if XORG >= 16 --#include "exevents.h" --extern void --CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); --#endif - #ifdef RANDR - #include "randrstr.h" - #endif -@@ -77,15 +58,6 @@ CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master); - #undef class - } - --static DeviceIntPtr vncKeyboardDevice = NULL; --#if XORG == 15 --static xEvent *eventq = NULL; --#else --static EventList *eventq = NULL; --#endif -- --static int vfbKeybdProc(DeviceIntPtr pDevice, int onoff); -- - using namespace rfb; - using namespace network; - -@@ -102,8 +74,6 @@ IntParameter queryConnectTimeout("QueryConnectTimeout", - "rejecting the connection", - 10); - --static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col); -- - static rdr::U8 reverseBits[] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, - 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, -@@ -193,33 +163,8 @@ XserverDesktop::XserverDesktop(ScreenPtr pScreen_, - if (httpListener) - httpServer = new FileHTTPServer(this); - --#if XORG == 15 -- /* -- * XXX eventq is never free()-ed because it has to exist during server life -- * */ -- if (!eventq) -- eventq = (xEvent *) xcalloc(sizeof(xEvent), GetMaximumEventsNum()); -- if (!eventq) -- FatalError("Couldn't allocate eventq\n"); --#else -- GetEventList(&eventq); --#endif -- -- /* -- * NOTE: -- * We _might_ have to call ActivateDevice function for both keyboard and -- * mouse. For Xvnc it's not needed but I have to check libvnc.so module. -- */ -- if (vncKeyboardDevice == NULL) { -- vncKeyboardDevice = AddInputDevice( --#if XORG >= 16 -- serverClient, --#endif -- vfbKeybdProc, TRUE); -- RegisterKeyboardDevice(vncKeyboardDevice); -- } -- - pointerDevice = new PointerDevice(server); -+ keyboardDevice = new KeyboardDevice(); - } - - XserverDesktop::~XserverDesktop() -@@ -229,6 +174,7 @@ XserverDesktop::~XserverDesktop() - TimerFree(deferredUpdateTimer); - TimerFree(dummyTimer); - delete pointerDevice; -+ delete keyboardDevice; - delete httpServer; - delete server; - } -@@ -854,550 +800,10 @@ - } - } - --// --// Keyboard handling --// -- --#define IS_PRESSED(keyc, keycode) \ -- ((keyc)->down[(keycode) >> 3] & (1 << ((keycode) & 7))) -- --// ModifierState is a class which helps simplify generating a "fake" press --// or release of shift, ctrl, alt, etc. An instance of the class is created --// for every modifier which may need to be pressed or released. Then either --// press() or release() may be called to make sure that the corresponding keys --// are in the right state. The destructor of the class automatically reverts --// to the previous state. Each modifier may have multiple keys associated with --// it, so in the case of a fake release, this may involve releasing more than --// one key. -- --class ModifierState { --public: -- ModifierState(int modIndex_) -- : modIndex(modIndex_), nKeys(0), keys(0), pressed(false) -- { -- } -- ~ModifierState() { -- for (int i = 0; i < nKeys; i++) -- generateXKeyEvent(keys[i], !pressed); -- delete [] keys; -- } -- void press() { -- KeyClassPtr keyc = vncKeyboardDevice->key; -- if (!(keyc->state & (1<modifierKeyMap[modIndex * keyc->maxKeysPerModifier], -- true); -- pressed = true; -- } -- } -- void release() { -- KeyClassPtr keyc = vncKeyboardDevice->key; -- if (keyc->state & (1<maxKeysPerModifier; k++) { -- int keycode -- = keyc->modifierKeyMap[modIndex * keyc->maxKeysPerModifier + k]; -- if (keycode && IS_PRESSED(keyc, keycode)) -- tempKeyEvent(keycode, false); -- } -- } -- } --private: -- void tempKeyEvent(int keycode, bool down) { -- if (keycode) { -- if (!keys) keys = new int[vncKeyboardDevice->key->maxKeysPerModifier]; -- keys[nKeys++] = keycode; -- generateXKeyEvent(keycode, down); -- } -- } -- void generateXKeyEvent(int keycode, bool down) { -- int i, n; -- n = GetKeyboardEvents (eventq, vncKeyboardDevice, -- down ? KeyPress : KeyRelease, keycode); -- for (i = 0; i < n; i++) { -- mieqEnqueue (vncKeyboardDevice, --#if XORG == 15 -- eventq + i --#else -- (eventq + i)->event --#endif -- ); -- } -- vlog.debug("fake keycode %d %s", keycode, down ? "down" : "up"); -- } -- int modIndex; -- int nKeys; -- int* keys; -- bool pressed; --}; -- -- --// altKeysym is a table of alternative keysyms which have the same meaning. -- --struct altKeysym_t { -- KeySym a, b; --}; -- --altKeysym_t 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 }, --}; -- --/* -- * keyEvent() - work out the best keycode corresponding to the keysym sent by -- * the viewer. This is non-trivial because we can't assume much about the -- * local keyboard layout. We must also find out which column of the keyboard -- * mapping the keysym is in, and alter the shift state appropriately. Column 0 -- * means both shift and "mode_switch" (AltGr) must be released, column 1 means -- * shift must be pressed and mode_switch released, column 2 means shift must be -- * released and mode_switch pressed, and column 3 means both shift and -- * mode_switch must be pressed. -- * -- * Magic, which dynamically adds keysym<->keycode mapping depends on X.Org -- * version. Quick explanation of that "magic": -- * -- * 1.5 -- * - has only one core keyboard so we have to keep core keyboard mapping -- * synchronized with vncKeyboardDevice. Do it via SwitchCoreKeyboard() -- * -- * 1.6 (aka MPX - Multi pointer X) -- * - multiple master devices (= core devices) exists, keep vncKeyboardDevice -- * synchronized with proper master device -- */ -- - void XserverDesktop::keyEvent(rdr::U32 keysym, bool down) - { -- DeviceIntPtr master; -- KeyClassPtr keyc = vncKeyboardDevice->key; -- KeySymsPtr keymap = &keyc->curKeySyms; -- unsigned int i, n; -- int j, k; -- -- /* -- * 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(); -- -- if (keysym == XK_Caps_Lock) { -- vlog.debug("Ignoring caps lock"); -- return; -- } -- -- // find which modifier Mode_switch is on. -- int modeSwitchMapIndex = 0; -- for (i = 3; i < 8; i++) { -- for (k = 0; k < keyc->maxKeysPerModifier; k++) { -- int keycode = keyc->modifierKeyMap[i * keyc->maxKeysPerModifier + k]; -- for (j = 0; j < keymap->mapWidth; j++) { -- if (keycode != 0 && -- keymap->map[(keycode - keymap->minKeyCode) -- * keymap->mapWidth + j] == XK_Mode_switch) -- { -- modeSwitchMapIndex = i; -- break; -- } -- } -- } -- } -- -- int col = 0; -- if (keyc->state & (1<state & (1<state & (1<maxKeyCode; kc >= keymap->minKeyCode; kc--) { -- if (!keymap->map[(kc - keymap->minKeyCode) * keymap->mapWidth]) { -- keymap->map[(kc - keymap->minKeyCode) * keymap->mapWidth] = keysym; -- col = 0; -- -- vlog.info("Added unknown keysym 0x%x to keycode %d",keysym,kc); -- --#if XORG == 15 -- master = inputInfo.keyboard; --#else -- master = vncKeyboardDevice->u.master; --#endif -- if (vncKeyboardDevice == -- dixLookupPrivate(&master->devPrivates, CoreDevicePrivateKey)) { -- dixSetPrivate(&master->devPrivates, CoreDevicePrivateKey, NULL); --#if XORG == 15 -- SwitchCoreKeyboard(vncKeyboardDevice); --#else -- CopyKeyClass(vncKeyboardDevice, master); --#endif -- } -- break; -- } -- } -- if (kc < keymap->minKeyCode) { -- vlog.info("Keyboard mapping full - ignoring unknown keysym 0x%x",keysym); -- return; -- } -- } -- -- // See if it's a modifier key. If so, then don't do any auto-repeat, because -- // the X server will translate each press into a release followed by a press. -- for (i = 0; i < 8; i++) { -- for (k = 0; k < keyc->maxKeysPerModifier; k++) { -- if (kc == keyc->modifierKeyMap[i * keyc->maxKeysPerModifier + k] && -- IS_PRESSED(keyc,kc) && down) -- return; -- } -- } -- -- ModifierState shift(ShiftMapIndex); -- ModifierState modeSwitch(modeSwitchMapIndex); -- if (down) { -- if (col & 1) -- shift.press(); -- else -- shift.release(); -- if (modeSwitchMapIndex) { -- if (col & 2) -- modeSwitch.press(); -- else -- modeSwitch.release(); -- } -- } -- vlog.debug("keycode %d %s", kc, down ? "down" : "up"); -- n = GetKeyboardEvents (eventq, vncKeyboardDevice, down ? -- KeyPress : KeyRelease, kc); -- for (i = 0; i < n; i++) { -- mieqEnqueue (vncKeyboardDevice, --#if XORG == 15 -- eventq + i --#else -- (eventq + i)->event --#endif -- ); -- } -- -- /* -- * 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(); -+ if (down) -+ keyboardDevice->Press(keysym); -+ else -+ keyboardDevice->Release(keysym); - } -- --static KeySym KeyCodetoKeySym(KeySymsPtr keymap, int keycode, int col) --{ -- register int per = keymap->mapWidth; -- register KeySym *syms; -- KeySym lsym, usym; -- -- if ((col < 0) || ((col >= per) && (col > 3)) || -- (keycode < keymap->minKeyCode) || (keycode > keymap->maxKeyCode)) -- return NoSymbol; -- -- syms = &keymap->map[(keycode - keymap->minKeyCode) * per]; -- if (col < 4) { -- if (col > 1) { -- while ((per > 2) && (syms[per - 1] == NoSymbol)) -- per--; -- if (per < 3) -- col -= 2; -- } -- if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) { -- XConvertCase(syms[col&~1], &lsym, &usym); -- if (!(col & 1)) -- return lsym; -- // I'm commenting out this logic because it's incorrect even though it -- // was copied from the Xlib sources. The X protocol book quite clearly -- // states that where a group consists of element 1 being a non-alphabetic -- // keysym and element 2 being NoSymbol that you treat the second element -- // as being the same as the first. This also tallies with the behaviour -- // produced by the installed Xlib on my linux box (I believe this is -- // because it uses some XKB code rather than the original Xlib code - -- // compare XKBBind.c with KeyBind.c in lib/X11). -- // else if (usym == lsym) -- // return NoSymbol; -- else -- return usym; -- } -- } -- return syms[col]; --} -- --// KeysymToKeycode() - find the keycode and column corresponding to the given --// keysym. The value of col passed in should be the column determined from the --// current shift state. If the keysym can be found in that column we prefer --// that to finding it in a different column (which would require fake events to --// alter the shift state). -- --static KeyCode KeysymToKeycode(KeySymsPtr keymap, KeySym ks, int* col) --{ -- register int i, j; -- -- j = *col; -- for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { -- if (KeyCodetoKeySym(keymap, i, j) == ks) -- return i; -- } -- -- for (j = 0; j < keymap->mapWidth; j++) { -- for (i = keymap->minKeyCode; i <= keymap->maxKeyCode; i++) { -- if (KeyCodetoKeySym(keymap, i, j) == ks) { -- *col = j; -- return i; -- } -- } -- } -- return 0; --} -- --/* Fairly standard US PC Keyboard */ -- --#define VFB_MIN_KEY 8 --#define VFB_MAX_KEY 255 --#define VFB_MAP_LEN (VFB_MAX_KEY - VFB_MIN_KEY + 1) --#define KEYSYMS_PER_KEY 2 --KeySym keyboardMap[VFB_MAP_LEN * KEYSYMS_PER_KEY] = { -- NoSymbol, NoSymbol, -- XK_Escape, NoSymbol, -- XK_1, XK_exclam, -- XK_2, XK_at, -- XK_3, XK_numbersign, -- XK_4, XK_dollar, -- XK_5, XK_percent, -- XK_6, XK_asciicircum, -- XK_7, XK_ampersand, -- XK_8, XK_asterisk, -- XK_9, XK_parenleft, -- XK_0, XK_parenright, -- XK_minus, XK_underscore, -- XK_equal, XK_plus, -- XK_BackSpace, NoSymbol, -- XK_Tab, NoSymbol, -- XK_q, XK_Q, -- XK_w, XK_W, -- XK_e, XK_E, -- XK_r, XK_R, -- XK_t, XK_T, -- XK_y, XK_Y, -- XK_u, XK_U, -- XK_i, XK_I, -- XK_o, XK_O, -- XK_p, XK_P, -- XK_bracketleft, XK_braceleft, -- XK_bracketright, XK_braceright, -- XK_Return, NoSymbol, -- XK_Control_L, NoSymbol, -- XK_a, XK_A, -- XK_s, XK_S, -- XK_d, XK_D, -- XK_f, XK_F, -- XK_g, XK_G, -- XK_h, XK_H, -- XK_j, XK_J, -- XK_k, XK_K, -- XK_l, XK_L, -- XK_semicolon, XK_colon, -- XK_apostrophe, XK_quotedbl, -- XK_grave, XK_asciitilde, -- XK_Shift_L, NoSymbol, -- XK_backslash, XK_bar, -- XK_z, XK_Z, -- XK_x, XK_X, -- XK_c, XK_C, -- XK_v, XK_V, -- XK_b, XK_B, -- XK_n, XK_N, -- XK_m, XK_M, -- XK_comma, XK_less, -- XK_period, XK_greater, -- XK_slash, XK_question, -- XK_Shift_R, NoSymbol, -- XK_KP_Multiply, NoSymbol, -- XK_Alt_L, XK_Meta_L, -- XK_space, NoSymbol, -- /*XK_Caps_Lock*/ NoSymbol, NoSymbol, -- XK_F1, NoSymbol, -- XK_F2, NoSymbol, -- XK_F3, NoSymbol, -- XK_F4, NoSymbol, -- XK_F5, NoSymbol, -- XK_F6, NoSymbol, -- XK_F7, NoSymbol, -- XK_F8, NoSymbol, -- XK_F9, NoSymbol, -- XK_F10, NoSymbol, -- XK_Num_Lock, XK_Pointer_EnableKeys, -- XK_Scroll_Lock, NoSymbol, -- XK_KP_Home, XK_KP_7, -- XK_KP_Up, XK_KP_8, -- XK_KP_Prior, XK_KP_9, -- XK_KP_Subtract, NoSymbol, -- XK_KP_Left, XK_KP_4, -- XK_KP_Begin, XK_KP_5, -- XK_KP_Right, XK_KP_6, -- XK_KP_Add, NoSymbol, -- XK_KP_End, XK_KP_1, -- XK_KP_Down, XK_KP_2, -- XK_KP_Next, XK_KP_3, -- XK_KP_Insert, XK_KP_0, -- XK_KP_Delete, XK_KP_Decimal, -- NoSymbol, NoSymbol, -- NoSymbol, NoSymbol, -- NoSymbol, NoSymbol, -- XK_F11, NoSymbol, -- XK_F12, NoSymbol, -- XK_Home, NoSymbol, -- XK_Up, NoSymbol, -- XK_Prior, NoSymbol, -- XK_Left, NoSymbol, -- NoSymbol, NoSymbol, -- XK_Right, NoSymbol, -- XK_End, NoSymbol, -- XK_Down, NoSymbol, -- XK_Next, NoSymbol, -- XK_Insert, NoSymbol, -- XK_Delete, NoSymbol, -- XK_KP_Enter, NoSymbol, -- XK_Control_R, NoSymbol, -- XK_Pause, XK_Break, -- XK_Print, XK_Execute, -- XK_KP_Divide, NoSymbol, -- XK_Alt_R, XK_Meta_R, --}; -- --static Bool GetMappings(KeySymsPtr pKeySyms, CARD8 *pModMap) --{ -- int i; -- -- for (i = 0; i < MAP_LENGTH; i++) -- pModMap[i] = NoSymbol; -- -- for (i = 0; i < VFB_MAP_LEN; i++) { -- if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Caps_Lock) -- pModMap[i + VFB_MIN_KEY] = LockMask; -- else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_L || -- keyboardMap[i * KEYSYMS_PER_KEY] == XK_Shift_R) -- pModMap[i + VFB_MIN_KEY] = ShiftMask; -- else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_L || -- keyboardMap[i * KEYSYMS_PER_KEY] == XK_Control_R) { -- pModMap[i + VFB_MIN_KEY] = ControlMask; -- } -- else if (keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_L || -- keyboardMap[i * KEYSYMS_PER_KEY] == XK_Alt_R) -- pModMap[i + VFB_MIN_KEY] = Mod1Mask; -- } -- -- pKeySyms->minKeyCode = VFB_MIN_KEY; -- pKeySyms->maxKeyCode = VFB_MAX_KEY; -- pKeySyms->mapWidth = KEYSYMS_PER_KEY; -- pKeySyms->map = keyboardMap; -- -- return TRUE; --} -- --static void vfbBell(int percent, DeviceIntPtr device, pointer ctrl, int class_) --{ -- if (percent > 0) -- vncBell(); --} -- --static int vfbKeybdProc(DeviceIntPtr pDevice, int onoff) --{ -- KeySymsRec keySyms; -- CARD8 modMap[MAP_LENGTH]; -- DevicePtr pDev = (DevicePtr)pDevice; --#ifdef XKB -- XkbComponentNamesRec names; --#endif -- -- switch (onoff) -- { -- case DEVICE_INIT: -- GetMappings(&keySyms, modMap); --#ifdef XKB -- if (!noXkbExtension) { -- memset(&names, 0, sizeof (names)); -- XkbSetRulesDflts("base", "pc105", "us", NULL, NULL); -- XkbInitKeyboardDeviceStruct(pDevice, &names, &keySyms, modMap, -- (BellProcPtr)vfbBell, -- (KbdCtrlProcPtr)NoopDDA); -- } else --#endif -- { -- InitKeyboardDeviceStruct(pDev, &keySyms, modMap, -- (BellProcPtr)vfbBell, (KbdCtrlProcPtr)NoopDDA); -- } -- break; -- case DEVICE_ON: -- pDev->on = TRUE; -- break; -- case DEVICE_OFF: -- pDev->on = FALSE; -- break; -- case DEVICE_CLOSE: -- break; -- } -- return Success; --} -- -diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h -index 9f300f5..6e4f609 100644 ---- a/unix/xserver/hw/vnc/XserverDesktop.h -+++ b/unix/xserver/hw/vnc/XserverDesktop.h -@@ -123,6 +123,7 @@ private: - void deferUpdate(); - ScreenPtr pScreen; - PointerDevice *pointerDevice; -+ KeyboardDevice *keyboardDevice; - OsTimerPtr deferredUpdateTimer, dummyTimer; - rfb::VNCServerST* server; - rfb::HTTPServer* httpServer; - --- -1.5.6.5 -