summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@lamia.panaceas.james.local>2015-05-25 17:59:50 +0100
committerroot <root@lamia.panaceas.james.local>2015-05-25 17:59:50 +0100
commit8907955471eb1e6507b3e1a7a2ca2ce0849b7766 (patch)
treed576b2b5522f6307767de6d6039a893013fe6714
downloadx2usb-8907955471eb1e6507b3e1a7a2ca2ce0849b7766.tar.gz
x2usb-8907955471eb1e6507b3e1a7a2ca2ce0849b7766.tar.bz2
x2usb-8907955471eb1e6507b3e1a7a2ca2ce0849b7766.zip
fish
-rw-r--r--Changes113
-rw-r--r--Imakefile20
-rw-r--r--format.c239
-rw-r--r--format.h74
-rw-r--r--keymap.c261
-rw-r--r--keymap.h56
-rw-r--r--lawyerese.c74
-rw-r--r--nocursor.curbin0 -> 326 bytes
-rw-r--r--resource.h2
-rw-r--r--usb.c1282
-rw-r--r--x2usb.man270
-rw-r--r--x2x.c1440
12 files changed, 3831 insertions, 0 deletions
diff --git a/Changes b/Changes
new file mode 100644
index 0000000..65dbe1f
--- /dev/null
+++ b/Changes
@@ -0,0 +1,113 @@
+RCS 1.1 -nAlpha1 : First release for Puneet and David to play with
+Files:
+Imakefile
+format.c
+format.h
+keymap.c
+keymap.h
+lawyerese.c
+x2x.1
+x2x.c
+
+
+22 Sept 03 released Alpha2
+--------------------------
+- Modify Imakefile to recognize cygwin or not
+- Adapt to load null cursor
+- Add Windows resources (for cursor, but alos has version info)
+- Initializae some variables (unused in -fromwin) to keep compiler happy
+- Add casts in printfs to remover warnings
+- Don't grab clipboard from X if its what we added to Windows
+- Force redraw when big window goes away (may not be strictly needed)
+- Intersept windows screenblank and forward to X if connected
+- Intersept ERASEBKGND and prevent Windows drawing black in big window
+- Don't register for property notify (on -to) in fromWin case
+- Bump version to 1.30 per Chaiken
+Add files:
+resource.h
+nocursor.cur (copy from win2vnc)
+x2xwin.rc (resource description)
+
+02 Oct 03 released Alpha3
+
+- After MAX_UNREASONABLES "unreasonable" coordinates they become reasonable
+ (helps recovery from errors that would otherwise loose the mouse)
+
+- Add 1 second tick to cause X events to be polled, sets max bound
+ when doing a paste to the X side [bug from pkumar]
+
+- Check number of buttons on -to side and don't send mousewheel events
+ if buttons 4/5 are not ok. [bug from chaiken]
+
+- Check for not becomming foreground, and try to recover, become aggresive
+ if events are turning up on the wrong window [Bug from Thomas]
+
+- Fix cursor warp (west) so it goes one left of return coordinate
+ [Bug from Thomas]
+
+- Extra message printing if -DDEBUGCHATTY [mdh]
+
+- Version of -capslockhack code in Windows KeyEvent processing
+ [Bug from Thomas and mdh]
+
+- Add magic key sequences for -fromwin:
+ RightAlt-Home to force cursor back to Windows
+ RightAlt-End to exit x2x
+
+- Known issue: Both left and right shift keys on Windows cause left shift on X.
+
+- make -fromwin imply -capslockhack, and add -nocapslockhack option
+
+- Fix to allow -east work before -fromwin on command line [Bug from Thomas]
+
+- Add comment in usage with Thomas' tip on making a shortcut to launch x2x
+
+- Fix Imakefile LOCAL_LIBRARIES to only include windows libs on cygwin
+- Add comments on -D to Imakefile
+
+Changed files:
+Imakefile
+keymap.c
+x2x.c
+x2xwin.rc (bump version)
+
+Added files:
+winmsg.c - This is a quick hack to turn Windows message numbers into
+ a string so I can print them. Only when -DDEBUGCHATTY
+
+
+27 Oct 2003 Beta 1
+------------------
+
+- Added code from Thomas Chadwick to save Windows focus when going to X
+ and restore on the way back (good for click-to-focus)
+
+- Added code from Thomas Chadwick to send a fake mouse click to Windows
+ when x2x is havig problems getting the focus (good for click-to-focus)
+
+- Support the -buttonblock flag in the -fromwin code
+
+- Add description of -fromwin to the manpage
+
+- Make man file x2x.man so that the makefile will build x2x.1.html
+ and the install will install x2x.1
+
+- Add to BUGS section of the man page that Ctrl-Alt-Del on the Windows
+side will leave the Ctrl and Alt keys stuck down on the X server and that
+pressing and releasing Ctrl and Alt should fix this.
+
+- Default to no -DDEBUG
+
+- Bump version to Beta
+
+- Add -clipcheck option and relax clipboard copy checking to windows
+if it is not given (allows other than plain XA_STRING copies, eg emacs
+keeps giving me a COMPOUND_TEXT type)
+
+Changed files:
+x2x.c
+x2x.man
+x2xwin.rc
+Imakefile
+
+
diff --git a/Imakefile b/Imakefile
new file mode 100644
index 0000000..6730ba8
--- /dev/null
+++ b/Imakefile
@@ -0,0 +1,20 @@
+XCOMM $XConsortium: Imakefile,v 1.5 91/07/17 16:07:10 gildea Exp $
+ DEPLIBS = $(DEPXTESTLIB) $(DEPEXTENSIONLIB) $(DEPXLIB)
+
+LOCAL_LIBRARIES = $(XTESTLIB) $(EXTENSIONLIB) $(XLIB)
+ SRCS = lawyerese.c x2x.c format.c usb.c
+ OBJS = lawyerese.o x2x.o format.o usb.o
+ PROTO_DEFINES =
+
+ CC = gcc
+
+XCOMM Add
+XCOMM -DDEBUG for debugging printfs
+XCOMM -DDEBUGCHATTY for printfs of every Windows message
+XCOMM -DDEBUGMOUSE for printfs of every Windows mouse coordinates
+
+ CDEBUGFLAGS = -O
+
+ LOCAL_LIBRARIES = -lX11 -lusb
+
+ComplexProgramTarget(x2usb)
diff --git a/format.c b/format.c
new file mode 100644
index 0000000..edcbf3a
--- /dev/null
+++ b/format.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 1997
+ * Digital Equipment Corporation. All rights reserved.
+ *
+ * By downloading, installing, using, modifying or distributing this
+ * software, you agree to the following:
+ *
+ * 1. CONDITIONS. Subject to the following conditions, you may download,
+ * install, use, modify and distribute this software in source and binary
+ * forms:
+ *
+ * a) Any source code, binary code and associated documentation
+ * (including the online manual) used, modified or distributed must
+ * reproduce and retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * b) No right is granted to use any trade name, trademark or logo of
+ * Digital Equipment Corporation. Neither the "Digital Equipment
+ * Corporation" name nor any trademark or logo of Digital Equipment
+ * Corporation may be used to endorse or promote products derived from
+ * this software without the prior written permission of Digital
+ * Equipment Corporation.
+ *
+ * 2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <X11/Xlib.h>
+#include <string.h>
+#include "format.h"
+
+static void formatMeasureText();
+
+void formatText(dpy, textw, pgc, tfont, nformats, formatv, pwidth, pheight)
+Display *dpy;
+Window textw;
+GC *pgc;
+XFS *tfont;
+int nformats;
+Format *formatv;
+int *pwidth, *pheight;
+{
+ int fontheight, fontwidth;
+ int x, y;
+ int len, textwidth, xoffset;
+ int format;
+ int top, left, lmargin, rmargin;
+ int width, height;
+ char *buffer;
+ Bool bMLineCenter;
+
+ top = left = lmargin = rmargin = x = y = width = height = 0;
+ fontheight = tfont->ascent + tfont->descent;
+ fontwidth = tfont->max_bounds.width;
+ bMLineCenter = False;
+
+ for (format = 0; format < nformats; ++format) {
+ switch (formatv[format]) {
+ case FormatSetTop:
+ y = top = formatv[++format];
+ break;
+ case FormatSetLeft:
+ x = left = formatv[++format];
+ break;
+ case FormatHome:
+ x = left + lmargin;
+ y = top;
+ break;
+ case FormatCR:
+ x = left + lmargin;
+ break;
+ case FormatNL:
+ x = left + lmargin;
+ y += fontheight;
+ break;
+ case FormatSetY:
+ y = top + formatv[++format];
+ break;
+ case FormatSetTextY:
+ y = top + fontheight * formatv[++format];
+ break;
+ case FormatAddY:
+ y += formatv[++format];
+ break;
+ case FormatAddTextY:
+ y += fontheight * formatv[++format];
+ break;
+ case FormatAddHalfTextY:
+ y += (fontheight >> 1) * formatv[++format];
+ break;
+ case FormatSetX:
+ x = left + formatv[++format];
+ break;
+ case FormatSetTextX:
+ x = left + fontwidth * formatv[++format];
+ break;
+ case FormatAddX:
+ x += formatv[++format];
+ break;
+ case FormatAddTextX:
+ x += fontwidth * formatv[++format];
+ break;
+ case FormatAddHalfTextX:
+ x += (fontwidth >> 1) * formatv[++format];
+ break;
+ case FormatString:
+ len = strlen((char *)formatv[++format]);
+ if (textw)
+ XDrawString(dpy, textw, *pgc, x, y, (char *)formatv[format], len);
+ x += XTextWidth(tfont, (char *)formatv[format], len);
+ break;
+ case FormatStringCenter:
+ x = left;
+ len = strlen((char *)formatv[++format]);
+ textwidth = XTextWidth(tfont, (char *)formatv[format], len);
+ xoffset = MAX(lmargin, ((width >> 1) - (textwidth >> 1)));
+ if (textw)
+ XDrawString(dpy, textw, *pgc, x + xoffset, y,
+ (char *)formatv[format], len);
+ x += textwidth;
+ break;
+ case FormatMultiLine:
+ buffer = (char *)formatv[++format];
+ len = 0;
+ x = left;
+ while (*buffer) {
+ /* if first character in the line is a tab, then center */
+ if (buffer[len] == '\t') {
+ buffer++; /* don't print the tab */
+ bMLineCenter = True;
+ }
+ while ((buffer[len] != '\n') && buffer[len])
+ len++;
+ textwidth = XTextWidth(tfont, buffer, len);
+ if (textw) {
+ if (bMLineCenter) {
+ xoffset = MAX(lmargin, ((width >> 1) - (textwidth >> 1)));
+ bMLineCenter = False; /* ready for next line */
+ } else { /* normal print */
+ xoffset = lmargin;
+ }
+ XDrawString(dpy, textw, *pgc, left + xoffset, y,
+ (char *)buffer, len);
+ }
+ if (buffer[len]) {
+ width = MAX(width, left + lmargin + textwidth + rmargin);
+ buffer += len + 1;
+ len = 0;
+ y += fontheight;
+ }
+ else {
+ x = left + lmargin + textwidth;
+ break;
+ }
+ }
+ break;
+ case FormatMeasureText:
+ formatMeasureText(tfont, (nformats - format - 1),
+ &formatv[format + 1], &fontwidth, &fontheight);
+ break;
+ case FormatSetWidth:
+ width = formatv[++format];
+ break;
+ case FormatSetLMargin:
+ if ((lmargin = formatv[++format]) == -1)
+ lmargin = MAX(0, x - left);
+ break;
+ case FormatSetRMargin:
+ if ((rmargin = formatv[++format]) == -1)
+ rmargin = MAX(0, x - left);
+ break;
+ default: /* might want an error message here */
+ break;
+ } /* END switch */
+
+ width = MAX(width, x - left + rmargin);
+ height = MAX(height, y - top);
+
+ } /* END for */
+
+ if (pwidth) *pwidth = width;
+ if (pheight) *pheight = height;
+
+} /* END formatText */
+
+static void formatMeasureText(tfont, nformats, formatv, pwidth, pheight)
+XFS *tfont;
+int nformats;
+Format *formatv;
+int *pwidth, *pheight;
+{
+ int fontheight, fontwidth;
+ int width, height;
+ int format;
+ unsigned minchar, maxchar;
+ unsigned char *buffer, thechar;
+ XCharStruct *xcs;
+
+ fontheight = fontwidth = 0;
+ minchar = tfont->min_char_or_byte2;
+ maxchar = tfont->max_char_or_byte2;
+
+ for (format = 0; format < nformats; ++format) {
+ switch (formatv[format]) {
+ case FormatHome: case FormatCR: case FormatNL: case FormatMeasureText:
+ /* nothing to do */
+ break;
+ case FormatString: case FormatStringCenter: case FormatMultiLine:
+ for (buffer = (unsigned char *)formatv[++format];
+ (thechar = *buffer);
+ buffer++) {
+ if ((thechar != '\n') && (thechar != '\t') &&
+ (minchar <= thechar) && (thechar <= maxchar)) {
+ xcs = &(tfont->per_char[thechar]);
+ if (fontwidth < (width = xcs->width))
+ fontwidth = width;
+ if (fontheight < (height = (xcs->ascent + xcs->descent)))
+ fontheight = height;
+ } /* END if thechar */
+ } /* END for buffer */
+ break;
+ default: /* most format instructions need to increment the counter */
+ format++;
+ break;
+ } /* END switch */
+ } /* END for */
+
+ if (pwidth) *pwidth = fontwidth;
+ if (pheight) *pheight = fontheight;
+
+} /* END formatMeasureText */
diff --git a/format.h b/format.h
new file mode 100644
index 0000000..fc21dd3
--- /dev/null
+++ b/format.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1997
+ * Digital Equipment Corporation. All rights reserved.
+ *
+ * By downloading, installing, using, modifying or distributing this
+ * software, you agree to the following:
+ *
+ * 1. CONDITIONS. Subject to the following conditions, you may download,
+ * install, use, modify and distribute this software in source and binary
+ * forms:
+ *
+ * a) Any source code, binary code and associated documentation
+ * (including the online manual) used, modified or distributed must
+ * reproduce and retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * b) No right is granted to use any trade name, trademark or logo of
+ * Digital Equipment Corporation. Neither the "Digital Equipment
+ * Corporation" name nor any trademark or logo of Digital Equipment
+ * Corporation may be used to endorse or promote products derived from
+ * this software without the prior written permission of Digital
+ * Equipment Corporation.
+ *
+ * 2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _FORMAT_H_
+#define _FORMAT_H_
+
+#ifndef MIN
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#endif
+#ifndef MAX
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+#endif
+
+void formatText();
+
+typedef XFontStruct XFS, *PXFS;
+
+typedef long Format;
+
+#define FormatSetTop 1 /* set top margin */
+#define FormatSetLeft 2 /* set left margin */
+#define FormatHome 3 /* home coordinates */
+#define FormatCR 4 /* carriage return */
+#define FormatNL 5 /* new line */
+#define FormatSetY 6 /* set absolute Y coordinate */
+#define FormatSetTextY 7 /* set Y coordinate to line */
+#define FormatAddY 8 /* add absolute Y */
+#define FormatAddTextY 9 /* add lines to Y */
+#define FormatAddHalfTextY 10 /* add half lines to Y */
+#define FormatSetX 11 /* set X absolute */
+#define FormatSetTextX 12 /* set X to character */
+#define FormatAddX 13 /* add absolute X */
+#define FormatAddTextX 14 /* add characters to X */
+#define FormatAddHalfTextX 15 /* add characters to X */
+#define FormatString 16 /* draw string and advance X */
+#define FormatStringCenter 17 /* draw string, centered on current width */
+#define FormatMultiLine 18 /* draw line string with newlines */
+#define FormatMeasureText 19 /* get font measurements based on strings */
+#define FormatSetWidth 20 /* set width for centering */
+#define FormatSetLMargin 21 /* set left margin. -1 = current x */
+#define FormatSetRMargin 22 /* set right margin. -1 = current x */
+#endif /* _FORMAT_H_ */
diff --git a/keymap.c b/keymap.c
new file mode 100644
index 0000000..7da942b
--- /dev/null
+++ b/keymap.c
@@ -0,0 +1,261 @@
+// This file comes from the vncviewer source
+// Converted to C from C++ and used in -fromwin version of x2x
+// 2003 By Mark Hayter
+
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// This file is part of the VNC system.
+//
+// The VNC system 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 program 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 program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+// If the source code for the VNC system is not available from the place
+// whence you received this file, check http://www.uk.research.att.com/vnc or contact
+// the authors on vnc@uk.research.att.com for information on obtaining it.
+
+// Thanks to Martin C. Mueller <mcm@itwm.uni-kl.de> for assistance with the
+// international keyboard mapping stuff.
+
+// KeyMap.cpp
+
+#ifdef WIN_2_X
+#include <stdio.h>
+#include <windows.h>
+#define XK_MISCELLANY
+#define XK_LATIN1
+#define XK_XKB_KEYS
+#include "keymap.h"
+
+// Define the keymap structure
+ typedef struct vncKeymapping_struct
+{
+ unsigned int wincode;
+ KeySym Xcode;
+ } vncKeymapping;
+ static const vncKeymapping keymap[] = {
+ {VK_BACK, XK_BackSpace},
+ {VK_TAB, XK_Tab},
+ {VK_CLEAR, XK_Clear},
+ {VK_RETURN, XK_Return},
+ {VK_LSHIFT, XK_Shift_L},
+ {VK_RSHIFT, XK_Shift_L}, /* XXX mdh - never gen SHIFT_R */
+{VK_SHIFT, XK_Shift_L}, {VK_LCONTROL, XK_Control_L}, {VK_RCONTROL, XK_Control_R}, {VK_CONTROL, XK_Control_L}, {VK_LMENU, XK_Alt_L}, {VK_RMENU, XK_Alt_R}, {VK_MENU, XK_Alt_L}, {VK_PAUSE, XK_Pause}, {VK_CAPITAL, XK_Caps_Lock}, {VK_ESCAPE, XK_Escape}, {VK_SPACE, XK_space}, {VK_PRIOR, XK_Page_Up}, {VK_NEXT, XK_Page_Down}, {VK_END, XK_End}, {VK_HOME, XK_Home}, {VK_LEFT, XK_Left}, {VK_UP, XK_Up}, {VK_RIGHT, XK_Right}, {VK_DOWN, XK_Down}, {VK_SELECT, XK_Select}, {VK_EXECUTE, XK_Execute}, {VK_SNAPSHOT, XK_Print}, {VK_INSERT, XK_Insert}, {VK_DELETE, XK_Delete}, {VK_HELP, XK_Help}, {VK_NUMPAD0, XK_KP_0}, {VK_NUMPAD1, XK_KP_1}, {VK_NUMPAD2, XK_KP_2}, {VK_NUMPAD3, XK_KP_3}, {VK_NUMPAD4, XK_KP_4}, {VK_NUMPAD5, XK_KP_5}, {VK_NUMPAD6, XK_KP_6}, {VK_NUMPAD7, XK_KP_7}, {VK_NUMPAD8, XK_KP_8}, {VK_NUMPAD9, XK_KP_9}, {VK_MULTIPLY, XK_KP_Multiply}, {VK_ADD, XK_KP_Add}, {VK_SEPARATOR, XK_KP_Separator}, // often comma
+{VK_SUBTRACT, XK_KP_Subtract},
+ {VK_DECIMAL, XK_KP_Decimal},
+ {VK_DIVIDE, XK_KP_Divide},
+ {VK_F1, XK_F1},
+ {VK_F2, XK_F2},
+ {VK_F3, XK_F3},
+ {VK_F4, XK_F4},
+ {VK_F5, XK_F5},
+ {VK_F6, XK_F6},
+ {VK_F7, XK_F7},
+ {VK_F8, XK_F8},
+ {VK_F9, XK_F9},
+ {VK_F10, XK_F10},
+ {VK_F11, XK_F11},
+ {VK_F12, XK_F12},
+ {VK_F13, XK_F13},
+ {VK_F14, XK_F14},
+ {VK_F15, XK_F15},
+ {VK_F16, XK_F16},
+ {VK_F17, XK_F17},
+ {VK_F18, XK_F18},
+ {VK_F19, XK_F19},
+ {VK_F20, XK_F20},
+ {VK_F21, XK_F21},
+ {VK_F22, XK_F22},
+ {VK_F23, XK_F23},
+ {VK_F24, XK_F24}, {VK_NUMLOCK, XK_Num_Lock}, {VK_SCROLL, XK_Scroll_Lock}
+};
+
+ static unsigned char buf[4];
+ static unsigned char keystate[256];
+ KeyActionSpec PCtoX (UINT virtkey, DWORD keyData)
+{
+ int numkeys = 0;
+ int mapsize, i;
+ int extended;
+ int ret;
+ KeyActionSpec kas;
+ kas.releaseModifiers = 0;
+ extended = ((keyData & 0x1000000) != 0);
+
+#ifdef DEBUG
+ printf (" keyData %04x ", (unsigned int) keyData);
+
+#endif /* */
+ if (extended)
+ {
+
+#ifdef DEBUG
+ printf (" (extended) ");
+
+#endif /* */
+ switch (virtkey)
+ {
+ case VK_MENU:
+ virtkey = VK_RMENU;
+ break;
+ case VK_CONTROL:
+ virtkey = VK_RCONTROL;
+ break;
+ }
+ }
+
+ // We try looking it up in our table
+ mapsize = sizeof (keymap) / sizeof (vncKeymapping);
+
+ // Look up the desired code in the table
+ for (i = 0; i < mapsize; i++)
+ {
+ if (keymap[i].wincode == virtkey)
+ {
+ kas.keycodes[numkeys++] = keymap[i].Xcode;
+ break;
+ }
+ }
+ if (numkeys != 0)
+ {
+
+#ifdef DEBUG
+ UINT key = kas.keycodes[numkeys - 1];
+ printf ("keymap gives %u (%x) ", key, key);
+
+#endif /* */
+ }
+ else
+ {
+
+ // not found in table
+#ifdef DEBUG
+ printf ("not in special keymap, ");
+
+#endif /* */
+ // we try a simple conversion to Ascii, using the current keyboard mapping
+ GetKeyboardState (keystate);
+ ret = ToAscii (virtkey, 0, keystate, (WORD *) buf, 0);
+
+ // If Left Ctrl & Alt both pressed and ToAscii gives a valid keysym
+ // This is for AltGr on international keyboards (= LCtrl-Alt).
+ // e.g. Ctrl-Alt-Q gives @ on German keyboards
+ if (((keystate[VK_MENU] & 0x80) != 0) &&
+ ((keystate[VK_CONTROL] & 0x80) != 0))
+ {
+
+ // If the key means anything in this keyboard layout
+ if ((ret >= 1) &&
+ (((*buf >= 32) && (*buf <= 126)) ||
+ ((*buf >= 160) && (*buf <= 255))) )
+ {
+
+ // Send the modifiers up, then the keystroke, then mods down
+ // We don't release the right control; this allows German users
+ // to use it for doing Ctl-@ etc. (though not under Win95 --
+ // see below)
+ if (GetKeyState (VK_LCONTROL) & 0x8000)
+ kas.releaseModifiers |= KEYMAP_LCONTROL;
+ if (GetKeyState (VK_LMENU) & 0x8000)
+ kas.releaseModifiers |= KEYMAP_LALT;
+ if (GetKeyState (VK_RMENU) & 0x8000)
+ kas.releaseModifiers |= KEYMAP_RALT;
+
+ // This is for windows 95, and possibly other systems.
+ // The above GetKeyState calls don't work in 95 - they always return 0.
+ // But if we're here at all we know that control and alt are pressed, so let's
+ // raise all Control and Alt keys if we haven't registered any yet.
+ if (kas.releaseModifiers == 0)
+ kas.releaseModifiers =
+ KEYMAP_LCONTROL | KEYMAP_LALT | KEYMAP_RALT;
+
+#ifdef DEBUG
+ printf
+ ("Ctrl-Alt pressed ToAscii(without modifiers)returns %d bytes: ",
+ ret);
+
+#endif /* */
+ for (i = 0; i < ret; i++)
+ {
+ kas.keycodes[numkeys++] = *(buf + i);
+
+#ifdef DEBUG
+ printf ("%02x (%c) ", *(buf + i), *(buf + i));
+
+#endif /* */
+ }
+
+#ifdef DEBUG
+ printf ("\n");
+
+#endif /* */
+ }
+ }
+
+ // If not a ctrl-alt key
+ if (numkeys == 0)
+ {
+
+ // There are no keysyms corresponding to control characters
+ // Eg Ctrl F. The server already knows whether the control
+ // key is pressed. So we are interested in the key that would be
+ // there if the Ctrl were not pressed.
+ keystate[VK_CONTROL] = keystate[VK_LCONTROL] =
+ keystate[VK_RCONTROL] = 0;
+ ret = ToAscii (virtkey, 0, keystate, (WORD *) buf, 0);
+ if (ret < 0)
+ {
+ switch (*buf)
+ {
+ case '`':
+ kas.keycodes[numkeys++] = XK_dead_grave;
+ break;
+ case '\'':
+ kas.keycodes[numkeys++] = XK_dead_acute;
+ break;
+ case '~':
+ kas.keycodes[numkeys++] = XK_dead_tilde;
+ break;
+ case '^':
+ kas.keycodes[numkeys++] = XK_dead_circumflex;
+ break;
+ }
+ }
+
+ // if this works, and it's a regular printable character, just send that
+ if (ret >= 1)
+ {
+
+#ifdef DEBUG
+ printf ("ToAscii (without ctrl) returns %d byte(s): ", ret);
+
+#endif /* */
+ for (i = 0; i < ret; i++)
+ {
+ kas.keycodes[numkeys++] = *(buf + i);
+
+#ifdef DEBUG
+ printf ("%02x (%c) ", *(buf + i), *(buf + i));
+
+#endif /* */
+ }
+ }
+ }
+ }
+ kas.keycodes[numkeys] = VoidKeyCode;
+ return kas;
+ }
+
+
+#endif /* */
diff --git a/keymap.h b/keymap.h
new file mode 100644
index 0000000..dde55d3
--- /dev/null
+++ b/keymap.h
@@ -0,0 +1,56 @@
+
+// This file comes from the vncviewer source
+// Converted to C from C++ and used in -fromwin version of x2x
+// 2003 By Mark Hayter
+
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// This file is part of the VNC system.
+//
+// The VNC system 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 program 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 program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+// If the source code for the VNC system is not available from the place
+// whence you received this file, check http://www.uk.research.att.com/vnc or contact
+// the authors on vnc@uk.research.att.com for information on obtaining it.
+
+// KeyMap.h
+// mapping of windows virtual key codes to X keysyms.
+
+#include <X11/Xlib.h>
+#include <X11/keysymdef.h>
+
+// A single key press on the client may result in more than one
+// going to the server.
+
+#define MaxKeysPerKey 4
+#define VoidKeyCode XK_VoidSymbol
+
+// keycodes contains the keysyms terminated by an VoidKeyCode.
+// The releaseModifiers is a set of ORed flags indicating whether
+// particular modifier-up messages should be sent before the keys
+// and modifier-down after.
+
+#define KEYMAP_LCONTROL 0x0001
+#define KEYMAP_RCONTROL 0x0002
+#define KEYMAP_LALT 0x0004
+#define KEYMAP_RALT 0x0008
+ typedef struct
+{
+ KeySym keycodes[MaxKeysPerKey];
+ int releaseModifiers;
+ } KeyActionSpec;
+ KeyActionSpec PCtoX (unsigned int virtkey, DWORD keyData);
+
diff --git a/lawyerese.c b/lawyerese.c
new file mode 100644
index 0000000..57cdca5
--- /dev/null
+++ b/lawyerese.c
@@ -0,0 +1,74 @@
+char *lawyerese =
+#ifdef WIN_2_X
+" Cygwin version with -fromwin to allow source to be a Windows\n"
+" machine that is not running a X server.\n"
+" Adapted by Mark Hayter 2003 using win2vnc ClientConnect.cpp code\n"
+"\n"
+"The x2x code is coverd by the following:\n\n"
+#endif
+"Copyright (c) 1997\n\
+Digital Equipment Corporation. All rights reserved.\n\
+\n\
+By downloading, installing, using, modifying or distributing this\n\
+software, you agree to the following:\n\
+\n\
+1. CONDITIONS. Subject to the following conditions, you may download,\n\
+install, use, modify and distribute this software in source and binary\n\
+forms:\n\
+\n\
+a) Any source code, binary code and associated documentation\n\
+(including the online manual) used, modified or distributed must\n\
+reproduce and retain the above copyright notice, this list of\n\
+conditions and the following disclaimer.\n\
+\n\
+b) No right is granted to use any trade name, trademark or logo of\n\
+Digital Equipment Corporation. Neither the \"Digital Equipment\n\
+Corporation\" name nor any trademark or logo of Digital Equipment\n\
+Corporation may be used to endorse or promote products derived from\n\
+this software without the prior written permission of Digital\n\
+Equipment Corporation.\n\
+\n\
+2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL \"AS IS\" AND ANY\n\
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n\
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n\
+PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY\n\
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n\
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n\
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n\
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n\
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n\
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n\
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\
+"
+#ifdef WIN_2_X
+"\n"
+"The win2vnc code was itself adapted from vncviewer for windows\n"
+"\n"
+" win2vnc, adapted from vncviewer by Fredrik Hubinette 2001\n"
+"\n"
+" Original copyright follows:\n"
+"\n"
+" Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.\n"
+"\n"
+" This file is part of the VNC system.\n"
+"\n"
+" The VNC system is free software; you can redistribute it and/or modify\n"
+" it under the terms of the GNU General Public License as published by\n"
+" the Free Software Foundation; either version 2 of the License, or\n"
+" (at your option) any later version.\n"
+"\n"
+" This program is distributed in the hope that it will be useful,\n"
+" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+" GNU General Public License for more details.\n"
+"\n"
+" You should have received a copy of the GNU General Public License\n"
+" along with this program; if not, write to the Free Software\n"
+" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,\n"
+" USA.\n"
+"\n"
+" If the source code for the VNC system is not available from the place \n"
+" whence you received this file, check http://www.uk.research.att.com/vnc or contact\n"
+" the authors on vnc@uk.research.att.com for information on obtaining it.\n"
+#endif
+;
diff --git a/nocursor.cur b/nocursor.cur
new file mode 100644
index 0000000..6bb01a5
--- /dev/null
+++ b/nocursor.cur
Binary files differ
diff --git a/resource.h b/resource.h
new file mode 100644
index 0000000..996a83b
--- /dev/null
+++ b/resource.h
@@ -0,0 +1,2 @@
+// Communication between the .rc file and code
+#define IDC_NOCURSOR 100
diff --git a/usb.c b/usb.c
new file mode 100644
index 0000000..1212486
--- /dev/null
+++ b/usb.c
@@ -0,0 +1,1282 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <stdint.h>
+
+#include <usb.h>
+
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+
+#define KEY_LIST_LEN 10
+
+
+static struct usb_dev_handle *devh;
+
+
+#define HACK_NONE 0UL /*Do nothing special */
+
+#define HACK_CTRL_L 1UL<<0
+#define HACK_SHIFT_L 1UL<<1
+#define HACK_ALT_L 1UL<<2
+#define HACK_SUPER_L 1UL<<3
+
+#define HACK_CTRL_R 1UL<<4
+#define HACK_SHIFT_R 1UL<<5
+#define HACK_ALT_R 1UL<<6
+#define HACK_SUPER_R 1UL<<7
+
+#define HACK_SHIFT_MASK 0x22
+#define HACK_MODIFIER_MASK 0xff
+
+#define HACK_RCS 1UL<<16 /*Require a shift key to be pressed and pass it through */
+#define HACK_HS 1UL<<17 /*Require and then hide a shift key */
+#define HACK_ILS 1UL<<18 /*Insert left shift */
+
+
+static struct map_ent
+{
+ uint32_t hacks;
+ uint8_t code;
+ KeySym keysym;
+ int keycode;
+} map[] =
+{
+/* Crazy parenthesis*/
+ {
+ HACK_RCS, 0x26, 0x28}, /* parenleft */
+ {
+ HACK_RCS, 0x27, 0x29}, /* parenright */
+#if 0
+/* UK - US misery for windows UK map*/
+ {
+ HACK_RCS, 0x34, 0x32}, /* shift 2 ->shift ' */
+ {
+ HACK_RCS, 0x1f, 0x27}, /* shift ' -> shift 2 */
+ {
+ HACK_RCS, 0x31, 0x60}, /* shift ` -> shift # */
+ {
+ HACK_HS, 0x31, 0x33}, /* shift 3 -> # */
+ {
+ HACK_NONE, 0x64, 0x5c}, /* backslash -> backslash */
+#endif
+#if 1
+/*misery for james' gbus keymap */
+ {
+ HACK_CTRL_L, 0xE0, 0xffe5}, /* Caps_Lock */
+ {
+ HACK_NONE, 0x39, 0xffe3}, /* Control_L */
+ {
+ HACK_NONE, 0x31, 0x60}, /* ` -> ` */
+ {
+ HACK_NONE, 0x64, 0x5c}, /* backslash -> backslash */
+#endif
+/*Modifier keys*/
+ {
+ HACK_CTRL_L, 0xE0, 0xffe3}, /* Control_L */
+ {
+ HACK_SHIFT_L, 0xE1, 0xffe1}, /* Shift_L */
+ {
+ HACK_ALT_L, 0xE2, 0xffe9}, /* Alt_L */
+ {
+ HACK_SUPER_L, 0xE3, 0xffeb}, /* Super_L */
+ {
+ HACK_CTRL_R, 0xE4, 0xffe4}, /* Control_R */
+ {
+ HACK_SHIFT_R, 0xE5, 0xffe2}, /* Shift_R */
+ {
+ HACK_ALT_R, 0xE6, 0xffea}, /* Alt_R */
+ {
+ HACK_SUPER_R, 0xE7, 0xffec}, /* Super_R */
+/* normal service below here */
+ {
+ HACK_NONE, 0x04, 0x61}, /* a */
+ {
+ HACK_NONE, 0x05, 0x62}, /* b */
+ {
+ HACK_NONE, 0x06, 0x63}, /* c */
+ {
+ HACK_NONE, 0x07, 0x64}, /* d */
+ {
+ HACK_NONE, 0x08, 0x65}, /* e */
+ {
+ HACK_NONE, 0x09, 0x66}, /* f */
+ {
+ HACK_NONE, 0x0a, 0x67}, /* g */
+ {
+ HACK_NONE, 0x0b, 0x68}, /* h */
+ {
+ HACK_NONE, 0x0c, 0x69}, /* i */
+ {
+ HACK_NONE, 0x0d, 0x6a}, /* j */
+ {
+ HACK_NONE, 0x0e, 0x6b}, /* k */
+ {
+ HACK_NONE, 0x0f, 0x6c}, /* l */
+ {
+ HACK_NONE, 0x10, 0x6d}, /* m */
+ {
+ HACK_NONE, 0x11, 0x6e}, /* n */
+ {
+ HACK_NONE, 0x12, 0x6f}, /* o */
+ {
+ HACK_NONE, 0x13, 0x70}, /* p */
+ {
+ HACK_NONE, 0x14, 0x71}, /* q */
+ {
+ HACK_NONE, 0x15, 0x72}, /* r */
+ {
+ HACK_NONE, 0x16, 0x73}, /* s */
+ {
+ HACK_NONE, 0x17, 0x74}, /* t */
+ {
+ HACK_NONE, 0x18, 0x75}, /* u */
+ {
+ HACK_NONE, 0x19, 0x76}, /* v */
+ {
+ HACK_NONE, 0x1a, 0x77}, /* w */
+ {
+ HACK_NONE, 0x1b, 0x78}, /* x */
+ {
+ HACK_NONE, 0x1c, 0x79}, /* y */
+ {
+ HACK_NONE, 0x1d, 0x7a}, /* z */
+ {
+ HACK_NONE, 0x1e, 0x31}, /* 1 */
+ {
+ HACK_NONE, 0x1f, 0x32}, /* 2 */
+ {
+ HACK_NONE, 0x20, 0x33}, /* 3 */
+ {
+ HACK_NONE, 0x21, 0x34}, /* 4 */
+ {
+ HACK_NONE, 0x22, 0x35}, /* 5 */
+ {
+ HACK_NONE, 0x23, 0x36}, /* 6 */
+ {
+ HACK_NONE, 0x24, 0x37}, /* 7 */
+ {
+ HACK_NONE, 0x25, 0x38}, /* 8 */
+ {
+ HACK_NONE, 0x26, 0x39}, /* 9 */
+ {
+ HACK_NONE, 0x27, 0x30}, /* 0 */
+ {
+ HACK_NONE, 0x28, 0xff0d}, /* Return */
+ {
+ HACK_NONE, 0x29, 0xff1b}, /* Escape */
+ {
+ HACK_NONE, 0x2a, 0xff08}, /* BackSpace */
+ {
+ HACK_NONE, 0x2b, 0xff09}, /* Tab */
+ {
+ HACK_NONE, 0x2c, 0x20}, /* space */
+ {
+ HACK_NONE, 0x2d, 0x2d}, /* minus */
+ {
+ HACK_NONE, 0x2e, 0x3d}, /* equal */
+ {
+ HACK_NONE, 0x2f, 0x5b}, /* bracketleft */
+ {
+ HACK_NONE, 0x30, 0x5d}, /* bracketright */
+ {
+ HACK_NONE, 0x31, 0x5c}, /* backslash */
+ {
+ HACK_NONE, 0x32, 0x5c}, /* backslash */
+ {
+ HACK_NONE, 0x33, 0x3b}, /* semicolon */
+ {
+ HACK_NONE, 0x34, 0x27}, /* apostrophe */
+ {
+ HACK_NONE, 0x35, 0x60}, /* grave */
+ {
+ HACK_NONE, 0x36, 0x2c}, /* comma */
+ {
+ HACK_NONE, 0x37, 0x2e}, /* period */
+ {
+ HACK_NONE, 0x38, 0x2f}, /* slash */
+ {
+ HACK_NONE, 0x39, 0xffe5}, /* Caps_Lock */
+ {
+ HACK_NONE, 0x3A, 0xffbe}, /* F1 */
+ {
+ HACK_NONE, 0x3B, 0xffbf}, /* F2 */
+ {
+ HACK_NONE, 0x3C, 0xffc0}, /* F3 */
+ {
+ HACK_NONE, 0x3D, 0xffc1}, /* F4 */
+ {
+ HACK_NONE, 0x3E, 0xffc2}, /* F5 */
+ {
+ HACK_NONE, 0x3F, 0xffc3}, /* F6 */
+ {
+ HACK_NONE, 0x40, 0xffc4}, /* F7 */
+ {
+ HACK_NONE, 0x41, 0xffc5}, /* F8 */
+ {
+ HACK_NONE, 0x42, 0xffc6}, /* F9 */
+ {
+ HACK_NONE, 0x43, 0xffc7}, /* F10 */
+ {
+ HACK_NONE, 0x44, 0xffc8}, /* F11 */
+ {
+ HACK_NONE, 0x45, 0xffc9}, /* F12 */
+ {
+ HACK_NONE, 0x46, 0xff61}, /* Print */
+ {
+ HACK_NONE, 0x47, 0xff14}, /* Scroll_Lock */
+ {
+ HACK_NONE, 0x48, 0xff13}, /* Pause */
+ {
+ HACK_NONE, 0x49, 0xff63}, /* Insert */
+ {
+ HACK_NONE, 0x4A, 0xff50}, /* Home */
+ {
+ HACK_NONE, 0x4B, 0xff55}, /* Prior */
+ {
+ HACK_NONE, 0x4C, 0xffff}, /* Delete */
+ {
+ HACK_NONE, 0x4D, 0xff57}, /* End */
+ {
+ HACK_NONE, 0x4E, 0xff56}, /* Next */
+ {
+ HACK_NONE, 0x4F, 0xff53}, /* Right */
+ {
+ HACK_NONE, 0x50, 0xff51}, /* Left */
+ {
+ HACK_NONE, 0x51, 0xff54}, /* Down */
+ {
+ HACK_NONE, 0x52, 0xff52}, /* Up */
+ {
+ HACK_NONE, 0x53, 0xff7f}, /* Num_Lock */
+ {
+ HACK_NONE, 0x54, 0xffaf}, /* KP_Divide */
+ {
+ HACK_NONE, 0x55, 0xffaa}, /* KP_Multiply */
+ {
+ HACK_NONE, 0x56, 0xffad}, /* KP_Subtract */
+ {
+ HACK_NONE, 0x57, 0xffab}, /* KP_Add */
+ {
+ HACK_NONE, 0x58, 0xff8d}, /* KP_Enter */
+ {
+ HACK_NONE, 0x59, 0xffb1}, /* KP_1 */
+ {
+ HACK_NONE, 0x5A, 0xffb2}, /* KP_2 */
+ {
+ HACK_NONE, 0x5B, 0xffb3}, /* KP_3 */
+ {
+ HACK_NONE, 0x5C, 0xffb4}, /* KP_4 */
+ {
+ HACK_NONE, 0x5D, 0xffb5}, /* KP_5 */
+ {
+ HACK_NONE, 0x5E, 0xffb6}, /* KP_6 */
+ {
+ HACK_NONE, 0x5F, 0xffb7}, /* KP_7 */
+ {
+ HACK_NONE, 0x60, 0xffb8}, /* KP_8 */
+ {
+ HACK_NONE, 0x61, 0xffb9}, /* KP_9 */
+ {
+ HACK_NONE, 0x62, 0xffb0}, /* KP_0 */
+ {
+ HACK_NONE, 0x63, 0xffae}, /* KP_Decimal */
+ {
+ HACK_NONE, 0x64, 0x3c}, /* less */
+ {
+ HACK_NONE, 0x65, 0xff67}, /* Menu */
+ {
+ HACK_NONE, 0x66, 0x1008ff2a}, /* XF86PowerOff */
+ {
+ HACK_NONE, 0x67, 0xffbd}, /* KP_Equal */
+ {
+ HACK_NONE, 0x68, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x69, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x6A, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x6B, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x6C, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x6D, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x6E, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x6F, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x70, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x71, 0x1008ffa9}, /* XF86TouchpadToggle */
+ {
+ HACK_NONE, 0x72, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x73, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x74, 0x1005ff73}, /* SunOpen */
+ {
+ HACK_NONE, 0x75, 0xff6a}, /* Help */
+ {
+ HACK_NONE, 0x76, 0x1005ff70}, /* SunProps */
+ {
+ HACK_NONE, 0x77, 0x1005ff71}, /* SunFront */
+ {
+ HACK_NONE, 0x78, 0xff69}, /* Cancel */
+ {
+ HACK_NONE, 0x79, 0xff66}, /* Redo */
+ {
+ HACK_NONE, 0x7A, 0xff65}, /* Undo */
+ {
+ HACK_NONE, 0x7B, 0x1008ff58}, /* XF86Cut */
+ {
+ HACK_NONE, 0x7C, 0x1008ff57}, /* XF86Copy */
+ {
+ HACK_NONE, 0x7D, 0x1008ff6d}, /* XF86Paste */
+ {
+ HACK_NONE, 0x7E, 0xff68}, /* Find */
+ {
+ HACK_NONE, 0x7F, 0x1008ff12}, /* XF86AudioMute */
+ {
+ HACK_NONE, 0x80, 0x1008ff13}, /* XF86AudioRaiseVolume */
+ {
+ HACK_NONE, 0x81, 0x1008ff11}, /* XF86AudioLowerVolume */
+ {
+ HACK_NONE, 0x82, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x83, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x84, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x85, 0xffae}, /* KP_Decimal */
+ {
+ HACK_NONE, 0x86, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x87, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x88, 0xff27}, /* Hiragana_Katakana */
+ {
+ HACK_NONE, 0x89, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x8A, 0xff23}, /* Henkan_Mode */
+ {
+ HACK_NONE, 0x8B, 0xff22}, /* Muhenkan */
+ {
+ HACK_NONE, 0x8C, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x8D, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x8E, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x8F, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x90, 0xff31}, /* Hangul */
+ {
+ HACK_NONE, 0x91, 0xff34}, /* Hangul_Hanja */
+ {
+ HACK_NONE, 0x92, 0xff26}, /* Katakana */
+ {
+ HACK_NONE, 0x93, 0xff25}, /* Hiragana */
+ {
+ HACK_NONE, 0x94, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x95, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x96, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x97, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x98, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x99, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x9A, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x9B, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x9C, 0xffff}, /* Delete */
+ {
+ HACK_NONE, 0x9D, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x9E, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0x9F, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xA0, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xA1, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xA2, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xA3, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xA4, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xA5, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xA6, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xA7, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xA8, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xA9, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xAA, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xAB, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xAC, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xAD, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xAE, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xAF, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xB0, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xB1, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xB2, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xB3, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xB4, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xB5, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xB6, 0x28}, /* parenleft */
+ {
+ HACK_NONE, 0xB7, 0x29}, /* parenright */
+ {
+ HACK_NONE, 0xB8, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xB9, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xBA, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xBB, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xBC, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xBD, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xBE, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xBF, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xC0, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xC1, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xC2, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xC3, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xC4, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xC5, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xC6, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xC7, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xC8, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xC9, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xCA, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xCB, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xCC, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xCD, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xCE, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xCF, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xD0, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xD1, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xD2, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xD3, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xD4, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xD5, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xD6, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xD7, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xD8, 0xffff}, /* Delete */
+ {
+ HACK_NONE, 0xD9, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xDA, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xDB, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xDC, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xDD, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xDE, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xDF, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xE0, 0xffe3}, /* Control_L */
+ {
+ HACK_NONE, 0xE1, 0xffe1}, /* Shift_L */
+ {
+ HACK_NONE, 0xE2, 0xffe9}, /* Alt_L */
+ {
+ HACK_NONE, 0xE3, 0xffeb}, /* Super_L */
+ {
+ HACK_NONE, 0xE4, 0xffe4}, /* Control_R */
+ {
+ HACK_NONE, 0xE5, 0xffe2}, /* Shift_R */
+ {
+ HACK_NONE, 0xE6, 0xffea}, /* Alt_R */
+ {
+ HACK_NONE, 0xE7, 0xffec}, /* Super_R */
+ {
+ HACK_NONE, 0xE8, 0x1008ff14}, /* XF86AudioPlay */
+ {
+ HACK_NONE, 0xE9, 0x1008ff15}, /* XF86AudioStop */
+ {
+ HACK_NONE, 0xEA, 0x1008ff16}, /* XF86AudioPrev */
+ {
+ HACK_NONE, 0xEB, 0x1008ff17}, /* XF86AudioNext */
+ {
+ HACK_NONE, 0xEC, 0x1008ff2c}, /* XF86Eject */
+ {
+ HACK_NONE, 0xED, 0x1008ff13}, /* XF86AudioRaiseVolume */
+ {
+ HACK_NONE, 0xEE, 0x1008ff11}, /* XF86AudioLowerVolume */
+ {
+ HACK_NONE, 0xEF, 0x1008ff12}, /* XF86AudioMute */
+ {
+ HACK_NONE, 0xF0, 0x1008ff2e}, /* XF86WWW */
+ {
+ HACK_NONE, 0xF1, 0x1008ff26}, /* XF86Back */
+ {
+ HACK_NONE, 0xF2, 0x1008ff27}, /* XF86Forward */
+ {
+ HACK_NONE, 0xF3, 0xff69}, /* Cancel */
+ {
+ HACK_NONE, 0xF4, 0xff68}, /* Find */
+ {
+ HACK_NONE, 0xF5, 0x1008ff78}, /* XF86ScrollUp */
+ {
+ HACK_NONE, 0xF6, 0x1008ff79}, /* XF86ScrollDown */
+ {
+ HACK_NONE, 0xF7, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xF8, 0x1008ff2f}, /* XF86Sleep */
+ {
+ HACK_NONE, 0xF9, 0x1008ff2d}, /* XF86ScreenSaver */
+ {
+ HACK_NONE, 0xFA, 0x1008ff73}, /* XF86Reload */
+ {
+ HACK_NONE, 0xFB, 0x1008ff1d}, /* XF86Calculator */
+ {
+ HACK_NONE, 0xFC, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xFD, 0x0}, /* NoSymbol */
+ {
+ HACK_NONE, 0xFE, 0x0}, /* NoSymbol */
+};
+
+#define MAP_LEN (sizeof(map)/sizeof(struct map_ent))
+
+
+#if 0
+#define MAP_LEN 256
+static int kc_map[MAP_LEN];
+static KeySym kc_map[MAP_LEN] = {
+ [0x04] = 0x61, /* a */
+ [0x05] = 0x62, /* b */
+ [0x06] = 0x63, /* c */
+ [0x07] = 0x64, /* d */
+ [0x08] = 0x65, /* e */
+ [0x09] = 0x66, /* f */
+ [0x0a] = 0x67, /* g */
+ [0x0b] = 0x68, /* h */
+ [0x0c] = 0x69, /* i */
+ [0x0d] = 0x6a, /* j */
+ [0x0e] = 0x6b, /* k */
+ [0x0f] = 0x6c, /* l */
+ [0x10] = 0x6d, /* m */
+ [0x11] = 0x6e, /* n */
+ [0x12] = 0x6f, /* o */
+ [0x13] = 0x70, /* p */
+ [0x14] = 0x71, /* q */
+ [0x15] = 0x72, /* r */
+ [0x16] = 0x73, /* s */
+ [0x17] = 0x74, /* t */
+ [0x18] = 0x75, /* u */
+ [0x19] = 0x76, /* v */
+ [0x1a] = 0x77, /* w */
+ [0x1b] = 0x78, /* x */
+ [0x1c] = 0x79, /* y */
+ [0x1d] = 0x7a, /* z */
+ [0x1e] = 0x31, /* 1 */
+ [0x1f] = 0x32, /* 2 */
+ [0x20] = 0x33, /* 3 */
+ [0x21] = 0x34, /* 4 */
+ [0x22] = 0x35, /* 5 */
+ [0x23] = 0x36, /* 6 */
+ [0x24] = 0x37, /* 7 */
+ [0x25] = 0x38, /* 8 */
+ [0x26] = 0x39, /* 9 */
+ [0x27] = 0x30, /* 0 */
+ [0x28] = 0xff0d, /* Return */
+ [0x29] = 0xff1b, /* Escape */
+ [0x2a] = 0xff08, /* BackSpace */
+ [0x2b] = 0xff09, /* Tab */
+ [0x2c] = 0x20, /* space */
+ [0x2d] = 0x2d, /* minus */
+ [0x2e] = 0x3d, /* equal */
+ [0x2f] = 0x5b, /* bracketleft */
+ [0x30] = 0x5d, /* bracketright */
+ [0x31] = 0x5c, /* backslash */
+ [0x32] = 0x5c, /* backslash */
+ [0x33] = 0x3b, /* semicolon */
+ [0x34] = 0x27, /* apostrophe */
+ [0x35] = 0x60, /* grave */
+ [0x36] = 0x2c, /* comma */
+ [0x37] = 0x2e, /* period */
+ [0x38] = 0x2f, /* slash */
+ [0x39] = 0xffe5, /* Caps_Lock */
+ [0x3A] = 0xffbe, /* F1 */
+ [0x3B] = 0xffbf, /* F2 */
+ [0x3C] = 0xffc0, /* F3 */
+ [0x3D] = 0xffc1, /* F4 */
+ [0x3E] = 0xffc2, /* F5 */
+ [0x3F] = 0xffc3, /* F6 */
+ [0x40] = 0xffc4, /* F7 */
+ [0x41] = 0xffc5, /* F8 */
+ [0x42] = 0xffc6, /* F9 */
+ [0x43] = 0xffc7, /* F10 */
+ [0x44] = 0xffc8, /* F11 */
+ [0x45] = 0xffc9, /* F12 */
+ [0x46] = 0xff61, /* Print */
+ [0x47] = 0xff14, /* Scroll_Lock */
+ [0x48] = 0xff13, /* Pause */
+ [0x49] = 0xff63, /* Insert */
+ [0x4A] = 0xff50, /* Home */
+ [0x4B] = 0xff55, /* Prior */
+ [0x4C] = 0xffff, /* Delete */
+ [0x4D] = 0xff57, /* End */
+ [0x4E] = 0xff56, /* Next */
+ [0x4F] = 0xff53, /* Right */
+ [0x50] = 0xff51, /* Left */
+ [0x51] = 0xff54, /* Down */
+ [0x52] = 0xff52, /* Up */
+ [0x53] = 0xff7f, /* Num_Lock */
+ [0x54] = 0xffaf, /* KP_Divide */
+ [0x55] = 0xffaa, /* KP_Multiply */
+ [0x56] = 0xffad, /* KP_Subtract */
+ [0x57] = 0xffab, /* KP_Add */
+ [0x58] = 0xff8d, /* KP_Enter */
+ [0x59] = 0xffb1, /* KP_1 */
+ [0x5A] = 0xffb2, /* KP_2 */
+ [0x5B] = 0xffb3, /* KP_3 */
+ [0x5C] = 0xffb4, /* KP_4 */
+ [0x5D] = 0xffb5, /* KP_5 */
+ [0x5E] = 0xffb6, /* KP_6 */
+ [0x5F] = 0xffb7, /* KP_7 */
+ [0x60] = 0xffb8, /* KP_8 */
+ [0x61] = 0xffb9, /* KP_9 */
+ [0x62] = 0xffb0, /* KP_0 */
+ [0x63] = 0xffae, /* KP_Decimal */
+ [0x64] = 0x3c, /* less */
+ [0x65] = 0xff67, /* Menu */
+ [0x66] = 0x1008ff2a, /* XF86PowerOff */
+ [0x67] = 0xffbd, /* KP_Equal */
+ [0x68] = 0x0, /* NoSymbol */
+ [0x69] = 0x0, /* NoSymbol */
+ [0x6A] = 0x0, /* NoSymbol */
+ [0x6B] = 0x0, /* NoSymbol */
+ [0x6C] = 0x0, /* NoSymbol */
+ [0x6D] = 0x0, /* NoSymbol */
+ [0x6E] = 0x0, /* NoSymbol */
+ [0x6F] = 0x0, /* NoSymbol */
+ [0x70] = 0x0, /* NoSymbol */
+ [0x71] = 0x1008ffa9, /* XF86TouchpadToggle */
+ [0x72] = 0x0, /* NoSymbol */
+ [0x73] = 0x0, /* NoSymbol */
+ [0x74] = 0x1005ff73, /* SunOpen */
+ [0x75] = 0xff6a, /* Help */
+ [0x76] = 0x1005ff70, /* SunProps */
+ [0x77] = 0x1005ff71, /* SunFront */
+ [0x78] = 0xff69, /* Cancel */
+ [0x79] = 0xff66, /* Redo */
+ [0x7A] = 0xff65, /* Undo */
+ [0x7B] = 0x1008ff58, /* XF86Cut */
+ [0x7C] = 0x1008ff57, /* XF86Copy */
+ [0x7D] = 0x1008ff6d, /* XF86Paste */
+ [0x7E] = 0xff68, /* Find */
+ [0x7F] = 0x1008ff12, /* XF86AudioMute */
+ [0x80] = 0x1008ff13, /* XF86AudioRaiseVolume */
+ [0x81] = 0x1008ff11, /* XF86AudioLowerVolume */
+ [0x82] = 0x0, /* NoSymbol */
+ [0x83] = 0x0, /* NoSymbol */
+ [0x84] = 0x0, /* NoSymbol */
+ [0x85] = 0xffae, /* KP_Decimal */
+ [0x86] = 0x0, /* NoSymbol */
+ [0x87] = 0x0, /* NoSymbol */
+ [0x88] = 0xff27, /* Hiragana_Katakana */
+ [0x89] = 0x0, /* NoSymbol */
+ [0x8A] = 0xff23, /* Henkan_Mode */
+ [0x8B] = 0xff22, /* Muhenkan */
+ [0x8C] = 0x0, /* NoSymbol */
+ [0x8D] = 0x0, /* NoSymbol */
+ [0x8E] = 0x0, /* NoSymbol */
+ [0x8F] = 0x0, /* NoSymbol */
+ [0x90] = 0xff31, /* Hangul */
+ [0x91] = 0xff34, /* Hangul_Hanja */
+ [0x92] = 0xff26, /* Katakana */
+ [0x93] = 0xff25, /* Hiragana */
+ [0x94] = 0x0, /* NoSymbol */
+ [0x95] = 0x0, /* NoSymbol */
+ [0x96] = 0x0, /* NoSymbol */
+ [0x97] = 0x0, /* NoSymbol */
+ [0x98] = 0x0, /* NoSymbol */
+ [0x99] = 0x0, /* NoSymbol */
+ [0x9A] = 0x0, /* NoSymbol */
+ [0x9B] = 0x0, /* NoSymbol */
+ [0x9C] = 0xffff, /* Delete */
+ [0x9D] = 0x0, /* NoSymbol */
+ [0x9E] = 0x0, /* NoSymbol */
+ [0x9F] = 0x0, /* NoSymbol */
+ [0xA0] = 0x0, /* NoSymbol */
+ [0xA1] = 0x0, /* NoSymbol */
+ [0xA2] = 0x0, /* NoSymbol */
+ [0xA3] = 0x0, /* NoSymbol */
+ [0xA4] = 0x0, /* NoSymbol */
+ [0xA5] = 0x0, /* NoSymbol */
+ [0xA6] = 0x0, /* NoSymbol */
+ [0xA7] = 0x0, /* NoSymbol */
+ [0xA8] = 0x0, /* NoSymbol */
+ [0xA9] = 0x0, /* NoSymbol */
+ [0xAA] = 0x0, /* NoSymbol */
+ [0xAB] = 0x0, /* NoSymbol */
+ [0xAC] = 0x0, /* NoSymbol */
+ [0xAD] = 0x0, /* NoSymbol */
+ [0xAE] = 0x0, /* NoSymbol */
+ [0xAF] = 0x0, /* NoSymbol */
+ [0xB0] = 0x0, /* NoSymbol */
+ [0xB1] = 0x0, /* NoSymbol */
+ [0xB2] = 0x0, /* NoSymbol */
+ [0xB3] = 0x0, /* NoSymbol */
+ [0xB4] = 0x0, /* NoSymbol */
+ [0xB5] = 0x0, /* NoSymbol */
+ [0xB6] = 0x28, /* parenleft */
+ [0xB7] = 0x29, /* parenright */
+ [0xB8] = 0x0, /* NoSymbol */
+ [0xB9] = 0x0, /* NoSymbol */
+ [0xBA] = 0x0, /* NoSymbol */
+ [0xBB] = 0x0, /* NoSymbol */
+ [0xBC] = 0x0, /* NoSymbol */
+ [0xBD] = 0x0, /* NoSymbol */
+ [0xBE] = 0x0, /* NoSymbol */
+ [0xBF] = 0x0, /* NoSymbol */
+ [0xC0] = 0x0, /* NoSymbol */
+ [0xC1] = 0x0, /* NoSymbol */
+ [0xC2] = 0x0, /* NoSymbol */
+ [0xC3] = 0x0, /* NoSymbol */
+ [0xC4] = 0x0, /* NoSymbol */
+ [0xC5] = 0x0, /* NoSymbol */
+ [0xC6] = 0x0, /* NoSymbol */
+ [0xC7] = 0x0, /* NoSymbol */
+ [0xC8] = 0x0, /* NoSymbol */
+ [0xC9] = 0x0, /* NoSymbol */
+ [0xCA] = 0x0, /* NoSymbol */
+ [0xCB] = 0x0, /* NoSymbol */
+ [0xCC] = 0x0, /* NoSymbol */
+ [0xCD] = 0x0, /* NoSymbol */
+ [0xCE] = 0x0, /* NoSymbol */
+ [0xCF] = 0x0, /* NoSymbol */
+ [0xD0] = 0x0, /* NoSymbol */
+ [0xD1] = 0x0, /* NoSymbol */
+ [0xD2] = 0x0, /* NoSymbol */
+ [0xD3] = 0x0, /* NoSymbol */
+ [0xD4] = 0x0, /* NoSymbol */
+ [0xD5] = 0x0, /* NoSymbol */
+ [0xD6] = 0x0, /* NoSymbol */
+ [0xD7] = 0x0, /* NoSymbol */
+ [0xD8] = 0xffff, /* Delete */
+ [0xD9] = 0x0, /* NoSymbol */
+ [0xDA] = 0x0, /* NoSymbol */
+ [0xDB] = 0x0, /* NoSymbol */
+ [0xDC] = 0x0, /* NoSymbol */
+ [0xDD] = 0x0, /* NoSymbol */
+ [0xDE] = 0x0, /* NoSymbol */
+ [0xDF] = 0x0, /* NoSymbol */
+ [0xE0] = 0xffe3, /* Control_L */
+ [0xE1] = 0xffe1, /* Shift_L */
+ [0xE2] = 0xffe9, /* Alt_L */
+ [0xE3] = 0xffeb, /* Super_L */
+ [0xE4] = 0xffe4, /* Control_R */
+ [0xE5] = 0xffe2, /* Shift_R */
+ [0xE6] = 0xffea, /* Alt_R */
+ [0xE7] = 0xffec, /* Super_R */
+ [0xE8] = 0x1008ff14, /* XF86AudioPlay */
+ [0xE9] = 0x1008ff15, /* XF86AudioStop */
+ [0xEA] = 0x1008ff16, /* XF86AudioPrev */
+ [0xEB] = 0x1008ff17, /* XF86AudioNext */
+ [0xEC] = 0x1008ff2c, /* XF86Eject */
+ [0xED] = 0x1008ff13, /* XF86AudioRaiseVolume */
+ [0xEE] = 0x1008ff11, /* XF86AudioLowerVolume */
+ [0xEF] = 0x1008ff12, /* XF86AudioMute */
+ [0xF0] = 0x1008ff2e, /* XF86WWW */
+ [0xF1] = 0x1008ff26, /* XF86Back */
+ [0xF2] = 0x1008ff27, /* XF86Forward */
+ [0xF3] = 0xff69, /* Cancel */
+ [0xF4] = 0xff68, /* Find */
+ [0xF5] = 0x1008ff78, /* XF86ScrollUp */
+ [0xF6] = 0x1008ff79, /* XF86ScrollDown */
+ [0xF7] = 0x0, /* NoSymbol */
+ [0xF8] = 0x1008ff2f, /* XF86Sleep */
+ [0xF9] = 0x1008ff2d, /* XF86ScreenSaver */
+ [0xFA] = 0x1008ff73, /* XF86Reload */
+ [0xFB] = 0x1008ff1d, /* XF86Calculator */
+ [0xFC] = 0x0, /* NoSymbol */
+ [0xFD] = 0x0, /* NoSymbol */
+ [0xFE] = 0x0, /* NoSymbol */
+};
+
+
+static uint8_t
+keycode_to_usb (int k)
+{
+ int i;
+ for (i = 0; i < MAP_LEN; ++i)
+ {
+ if (kc_map[i] == k)
+ return i;
+ }
+ return 0;
+}
+#endif
+
+static uint32_t seq = 1;
+
+
+static int
+flush (struct usb_dev_handle *devh)
+{
+ int ret;
+ uint8_t rbuf[36];
+ uint8_t xbuf[31] = {
+ 0x55, 0x53, 0x42, 0x43,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00,
+ 0x00, 0x00
+ };
+ memcpy (&xbuf[4], &seq, 4);
+ seq++;
+
+/*Sends SCSI test unit ready*/
+
+ if (usb_bulk_write (devh, 0x2, xbuf, 31, 0) != 31)
+ exit (1);
+ ret = usb_bulk_read (devh, 0x81, rbuf, 36, 0);
+ if (ret <= 0)
+ exit (1);
+
+
+ return 0;
+}
+
+static int
+send_msg (struct usb_dev_handle *devh, uint8_t * msg)
+{
+ int ret;
+ uint8_t xbuf[31] = {
+ 0x55, 0x53, 0x42, 0x43,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0xd9,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00,
+ 0x4f, 0x54
+ };
+ uint8_t rbuf[36];
+
+ memcpy (&xbuf[16], msg, 13);
+ memcpy (&xbuf[4], &seq, 4);
+ seq++;
+
+/* READ CD-DA MSF !*/
+
+ if (usb_bulk_write (devh, 0x2, xbuf, 31, 0) != 31)
+ exit (1);
+ ret = usb_bulk_read (devh, 0x81, rbuf, 36, 0);
+ if (ret <= 0)
+ exit (1);
+
+
+ return 0;
+}
+
+static int
+mouse (struct usb_dev_handle *devh, uint16_t x, uint16_t y, uint8_t s, int l,
+ int m, int r)
+{
+ uint8_t bmask = (l ? 1 : 0) | (m ? 4 : 0) | (r ? 2 : 0);
+ uint8_t msg[13] = { 0x33, bmask, s, x & 0xff,
+ x >> 8, y & 0xff, y >> 8, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00
+ };
+
+ printf ("Mouse x=%4d y=%4d scroll=%2x bmask=%x\n", x, y, s, bmask);
+
+ return send_msg (devh, msg);
+}
+
+static int
+key_down_list (struct usb_dev_handle *devh, uint8_t modifiers,
+ uint8_t * keylist)
+{
+ uint8_t msg[13] = { 0x34, modifiers, 0x00 };
+ memcpy (&msg[3], keylist, KEY_LIST_LEN);
+ int i;
+
+ printf ("Keybd modifiers mask=%x key list=", modifiers);
+
+ for (i = 0; i < KEY_LIST_LEN; ++i)
+ {
+ if (keylist[i])
+ printf ("%02x ", keylist[i]);
+ }
+ printf ("\n");
+ return send_msg (devh, msg);
+}
+
+static uint8_t keys[KEY_LIST_LEN];
+
+
+static int
+key_down (struct usb_dev_handle *devh, uint8_t key, uint8_t modifiers)
+{
+ int i;
+
+//printf("Key %d down modifiers %x\n",key,modifiers);
+
+ if (key)
+ {
+ do
+ {
+ for (i = 0; i < sizeof (keys); ++i)
+ {
+ if (keys[i] == key)
+ break;
+ }
+
+ for (i = 0; i < sizeof (keys); ++i)
+ {
+ if (!keys[i])
+ {
+ keys[i] = key;
+ break;
+ }
+ }
+ }
+ while (0);
+ }
+
+ return key_down_list (devh, modifiers, keys);
+}
+
+
+static int
+key_up (struct usb_dev_handle *devh, uint8_t key, uint8_t modifiers)
+{
+ int i;
+
+//printf("Key %d up modifiers %x\n",key,modifiers);
+
+ if (key)
+ {
+ for (i = 0; i < sizeof (keys); ++i)
+ {
+ if (keys[i] == key)
+ keys[i] = 0;
+ }
+ }
+
+ return key_down_list (devh, modifiers, keys);
+}
+
+
+
+static int
+init (void)
+{
+
+ int i;
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+
+ usb_init ();
+
+ usb_set_debug (15);
+
+ usb_find_busses ();
+ usb_find_devices ();
+
+
+ for (bus = usb_get_busses (); bus; bus = bus->next)
+ {
+ for (dev = bus->devices; dev; dev = dev->next)
+ {
+ if ((dev->descriptor.idVendor == 0x0ea0) &&
+ (dev->descriptor.idProduct == 0x2211))
+ break;
+ }
+
+ if (dev && (dev->descriptor.idVendor == 0x0ea0) &&
+ (dev->descriptor.idProduct == 0x2211))
+ break;
+ }
+
+
+ if (!dev)
+ exit (1);
+
+ devh = usb_open (dev);
+
+ if (!devh)
+ {
+ printf ("can't open widget: %s\n", usb_strerror ());
+ exit (1);
+
+ }
+
+
+
+
+ usb_detach_kernel_driver_np (devh, 0);
+ usb_detach_kernel_driver_np (devh, 1);
+ usb_detach_kernel_driver_np (devh, 2);
+ usb_claim_interface (devh, 0);
+
+
+ usb_clear_halt (devh, 0x81);
+ usb_clear_halt (devh, 0x2);
+
+
+#if 0
+ key_down (devh, 0xe);
+ flush (devh);
+ key_up (devh, 0xe);
+ flush (devh);
+ key_down (devh, 0xf);
+ flush (devh);
+ key_up (devh, 0xf);
+ flush (devh);
+#endif
+
+
+
+//mouse(devh,i,i,0,0,1);
+//mouse(devh,i,i,0,0,0);
+//mouse(devh,200,200,1,0,0);
+//mouse(devh,200,200,0,0,0);
+
+ return 0;
+}
+
+#include <stdio.h>
+
+static int cx, cy;
+static int bs[3];
+
+void
+fake_motion (int x, int y)
+{
+ cx = x;
+ cy = y;
+
+ mouse (devh, cx, cy, 0, bs[0], bs[1], bs[2]);
+}
+
+
+void
+fake_scroll_event (int d)
+{
+ uint8_t s;
+
+
+ if (d >= 0)
+ {
+ s = d;
+ }
+ else
+ {
+ s = 256 + d;
+ }
+
+
+ mouse (devh, cx, cy, s, bs[0], bs[1], bs[2]);
+ flush (devh);
+
+}
+
+void
+fake_button_event (int b, int ud)
+{
+
+ switch (b)
+ {
+ case 1:
+ case 2:
+ case 3:
+ bs[b - 1] = ! !ud;
+ mouse (devh, cx, cy, 0, bs[0], bs[1], bs[2]);
+ break;
+ case 4:
+ if (ud)
+ fake_scroll_event (1);
+ break;
+ case 5:
+ if (ud)
+ fake_scroll_event (-1);
+ break;
+ }
+
+}
+
+struct map_ent *
+lookup_map_ent (int keycode, uint8_t modifiers)
+{
+ int i;
+
+ for (i = 0; i < MAP_LEN; ++i)
+ {
+ if (map[i].keycode == keycode)
+ {
+ if (map[i].hacks & (HACK_RCS | HACK_HS))
+ { /*Do we require a shift key to match ? */
+ if (modifiers & HACK_SHIFT_MASK)
+ return &map[i];
+ }
+ else
+ {
+ return &map[i];
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+
+
+void
+fake_key_event (int k, int ud)
+{
+ static uint8_t modifiers;
+ uint8_t mods;
+
+ struct map_ent *e = lookup_map_ent (k, modifiers);
+
+ if (!e)
+ return;
+
+ if (e->hacks & HACK_MODIFIER_MASK)
+ {
+ if (ud)
+ {
+ modifiers |= e->hacks & HACK_MODIFIER_MASK;
+ }
+ else
+ {
+ modifiers &= ~(e->hacks & HACK_MODIFIER_MASK);
+ }
+ }
+
+ if (e->hacks & HACK_HS)
+ {
+ mods = modifiers & ~HACK_SHIFT_MASK;
+
+ if (ud)
+ {
+ if (modifiers & HACK_SHIFT_L)
+ key_up (devh, 0xe1, mods);
+ if (modifiers & HACK_SHIFT_R)
+ key_up (devh, 0xe5, mods);
+ }
+
+
+ }
+ else
+ {
+ mods = modifiers;
+ }
+
+#if 0
+ printf
+ ("Hacks %8x, modifiers=%4x, mods=%4x, e->keysym=%4x, e->keycode=%4x, e->code=%2x\n",
+ e->hacks, modifiers, mods, e->keysym, e->keycode, e->code);
+#endif
+
+ if (ud)
+ key_down (devh, e->code, mods);
+ else
+ key_up (devh, e->code, mods);
+
+ if (e->hacks & HACK_HS)
+ {
+ if (!ud)
+ {
+ if (modifiers & HACK_SHIFT_L)
+ key_down (devh, 0xe1, modifiers);
+ if (modifiers & HACK_SHIFT_R)
+ key_down (devh, 0xe5, modifiers);
+ }
+ }
+
+
+ flush (devh);
+}
+
+void
+init_map (Display * d)
+{
+ int i;
+ for (i = 0; i < MAP_LEN; ++i)
+ {
+ map[i].keycode = XKeysymToKeycode (d, map[i].keysym);
+ }
+}
+
+void
+fake_init (Display * d)
+{
+ init_map (d);
+ init ();
+}
diff --git a/x2usb.man b/x2usb.man
new file mode 100644
index 0000000..1f31cd7
--- /dev/null
+++ b/x2usb.man
@@ -0,0 +1,270 @@
+.nh
+.TH x2x 1
+.SH NAME
+x2x \- X to X connection
+.SH SYNTAX
+\f x2x\fR <[-to <DISPLAY>] | [-fromwin | -from <DISPLAY>]> [options...]
+.SH DESCRIPTION
+x2x allows the keyboard and mouse on one ("from") X display to be used to
+control another ("to") X display. Since x2x uses the XTEST extension,
+the "to" X display must support XTEST.
+
+If x2x is built under Cygwin (on Windows XP or Windows 2000) then the
+-fromwin option may be specified to allow the "from" display to be the
+Windows desktop. (The Cygwin build also supports use of an X display
+for the "from" screen). Use of -fromwin sets the default behaviour as
+if the -big -west -capslockhack options had also been given.
+
+In the default interface, x2x puts a window on the "from" display.
+This window is labeled with the name of the "to" display. Keystrokes
+typed into this window go to the window on the "to" display that has
+the input focus. Clicking on the x2x window causes the mouse on the
+"from" display to control the cursor on the "to" display. Performing
+a subsequent multiple button click on the "to" display returns control
+to the "from" display.
+
+If the -fromwin or -east or -west options are specified on the command
+line, x2x starts up with a different interface. When the mouse moves
+to the (east or west) side of the default screen on the "from"
+display, the cursor slides over to the "to" display. When the mouse
+returns to to side of the "to" display that it entered, it slides back
+onto the "from" display.
+
+Unless the -nosel option is specified, x2x relays X selections from
+one display to the other. (If -fromwin is specified then the X
+selection is relayed to and from the Windows clipboard as text strings).
+
+Here are a few hints for eXcursion users (based on Intel version
+2.1.309). First, use the -big option. Second, in the control panel,
+under mouse, check the box that enables "Automatically Capture Text on
+Button Up." X selections will then automatically move into the
+Windows clipboard. As is the case with all X applications running on
+2.1.309 (including x2x), you will need to do an extra mouse click
+after performing the X selection for this operation to work. x2x is
+known to work poorly with eXcursion running on Windows 95, probably
+due to the Windows 95 task scheduler. x2x does work well with eXcursion
+running on Windows NT.
+
+The hints for eXcursion are also valid for Exceed, with the exception
+that X selections work better, as long as you are using x2x version
+1.25 or later.
+
+.SH OPTIONS
+Either the -to option or the -from option (or both) must be specified.
+.TP
+.B \-to \fIdisplay\fP
+.IP
+Indicates the ("to") display that is remotely controlled by the "from" display.
+Default is equivalent to the default display.
+.TP
+.B \-from \fIdisplay\fP
+.IP
+Indicates the ("from") display that remotely controls the "to" display.
+Default is equivalent to the default display.
+.TP
+.B \-fromwin
+.IP
+Available when x2x is built in the Cygwin environment. This option
+indicates the ("from") display should be the Windows desktop. In this
+case the "to" display must be specified with the \-to option. Setting
+this option forces \-big and sets the default to \-west \-capslockhack
+
+The -fromwin option works best when Windows is configured for
+focus-follows-mouse also known as X Mouse. This can be set using
+TweakUI for Windows XP (on the Mouse/X-Mouse panel) or the XMouse2000
+program for Windows 2000. If Windows is set for its default behaviour
+x2x will attempt to get the keyboard and mouse focus but may not
+succeed. (The Windows XP TweakUI has a General/Focus option that can be
+unchecked to allow applications to steal the focus.) If it fails the
+first try, x2x tries quite hard to get the focus!
+
+If the "to" display supports mouse buttons 4 and 5 then mouse wheel
+events on the Windows side are translated to clicks of buttons 4 and 5
+on the X display. This matches with XFree86 servers using
+Option "ZAxisMapping" "4 5".
+
+A link may be created on the Windows desktop to conveniently launch
+x2x. Assuming cygwin is installed to C:\\cygwin and x2x.exe is in
+/usr/X11R6/bin then the link properties should be set to:
+
+Target:
+.br
+C:\\cygwin\\usr\\X11R6\\bin\\run.exe\ /usr/X11R6/bin/x2x\ \-fromwin\ \-to\ somewhere:0.0\ \-east
+
+Start In: C:\\cygwin\\usr\\X11R6\\bin
+
+The "Start In" option is important to allow DLLs to be loaded and
+C:\\cygwin\\bin must be on the Windows PATH to allow other DLLs to be
+loaded. (If either of these are incorrect, launching the application
+tends to silently fail.)
+
+There are two magic key combinations activated by -fromwin:
+
+RightAlt-Home: Forces the focus back to Windows without needing the
+mouse to be moved. Useful when some popup window on the Windows side
+grabs the mouse!
+
+RightAlt-End: Exit x2x
+.TP
+.B \-east
+.IP
+Slide off the east side of the "to" display onto the "from" display.
+.TP
+.B \-west
+.IP
+Slide off the west side of the "to" display onto the "from" display.
+.TP
+.B \-font \fIfontname\fP
+.IP
+The font used in the x2x window. (Overridden by -east or -west.)
+.TP
+.B \-geometry \fIspecification\fP
+.IP
+The X geometry specification for the x2x window.
+(Overridden by -east or -west.)
+.TP
+.B \-wait
+.IP
+Tells x2x to poll the "to" and "from" displays at startup until they
+are ready. Useful for login scripts.
+.TP
+.B \-big
+.IP
+Workaround for a bug in the cursor grab implementations of at least one
+X server. Put a big window over the "to" display in order to force the
+X server to track the cursor. (This option is forced by the -fromwin option).
+.TP
+.B \-buttonblock
+.IP
+If this option is enabled with -east or -west, the cursor will not
+slide back onto the "from" display when one or more mouse buttons
+are pressed.
+.TP
+.B \-nomouse
+.IP
+Don't capture the mouse.
+(Overridden by -east or -west.)
+.TP
+.B \-nopointermap
+.IP
+Since x2x uses XTEST, which sends input at a lower level than the
+pointer button mapping, x2x needs to understand the "to" display's
+button mapping and do appropriate conversion. Use this option
+to turn off the pointer button conversion.
+.TP
+.B \-nosel
+.IP
+Don't relay the X selection between displays.
+.TP
+.B \-noautoup
+.IP
+Normally, the autoup feature in x2x automatically lifts up all keys and
+mouse buttons when it removes the cursor from the "from" display.
+.B
+Note: the autoup feature changes the state of lock functions like
+.B
+Caps Lock. The state of the lock function may not correspond to
+.B
+the state of the keyboard LEDs!
+To disable this feature, use the \-noautoup command line option.
+.TP
+.B \-resurface
+.IP
+Ugly hack to work-around window manager ugliness. The -east and -west
+modes actually put a small window on the side of the "from" display.
+This option causes this window to resurface itself if another window
+ever obscures it. This option can cause really nasty behavior if another
+application tries to do the same thing. Useful for login scripts.
+.TP
+.B \-capslockhack
+.IP
+Ugly hack to work-around the situation in which the "to" Xserver doesn't
+seem to honor the state of the CapsLock on the "from" Xserver. This is
+the default when the -fromwin option is given (although the hack used
+is slightly less ugly).
+.TP
+.B \-nocapslockhack
+.IP
+Disable the -capslockhack behaviour. Used to change the default
+behaviour after the -fromwin option is specified.
+.TP
+.B \-clipcheck
+.IP
+Check that clipboard entries are regular strings (XA_STRING) before
+forwarding to Windows. Enabling this is safer but may prevent copying
+with certain setups (eg from emacs under KDE/XFree).
+.TP
+.B \-shadow \fIdisplay\fP
+.IP
+Also sends mouse movements and keystrokes to this display. Useful
+for demos. Amaze your friends: specify multiple shadows.
+.TP
+.B \-sticky \fIsticky-key\fP
+.IP
+This option is primarily for "lock" keys like Caps_Lock. If a lock
+key only seems to work on every other press, try this option. The
+sticky option prevents autoup for the specified key. Look in
+/usr/include/X11/keysymdef.h for a list of valid names of keys
+(remove the leading XK_).
+.TP
+.B \-copyright
+.IP
+Prints the full copyright for the x2x code.
+.SH AUTHOR
+David Chaiken
+.br
+(chaiken@pa.dec.com)
+.br
+Mark Hayter (-fromwin code, thanks to the WinVNC sources)
+.SH BUGS
+This software is experimental! Heaven help you if your network
+connection should go down. Caveat hacker. TANSTAAFL.
+
+When using the -fromwin option if the Ctrl-Alt-Del keysequence is used
+while the mouse is forwarded to the X display then the Ctrl and Alt
+key press events are reported to x2x and forwarded but no other key
+events are generated. Thus if the Ctrl-Alt-Del sequence is used to
+manually lock the Windows display when the display is unlocked the
+mouse will still be forwarded to the X screen and the X server will
+believe Ctrl and Alt are still pressed. Pressing and releasing Ctrl
+and Alt should restore correct operation, as should returning the
+mouse to the Windows display (or using the RightAlt-Home magic key
+sequence).
+
+.SH LAWYERESE
+Copyright (c) 1997
+Digital Equipment Corporation. All rights reserved.
+
+By downloading, installing, using, modifying or distributing this
+software, you agree to the following:
+
+1. CONDITIONS. Subject to the following conditions, you may download,
+install, use, modify and distribute this software in source and binary forms:
+
+a) Any source code, binary code and associated documentation
+(including the online manual) used, modified or distributed must
+reproduce and retain the above copyright notice, this list of
+conditions and the following disclaimer.
+
+b) No right is granted to use any trade name, trademark or logo of
+Digital Equipment Corporation. Neither the "Digital Equipment
+Corporation" name nor any trademark or logo of Digital Equipment
+Corporation may be used to endorse or promote products derived from
+this software without the prior written permission of Digital
+Equipment Corporation.
+
+2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Windows 95 and Windows NT are trademarks of Microsoft Corporation.
+.br
+Exceed is a trademark of Hummingbird Communications Ltd.
diff --git a/x2x.c b/x2x.c
new file mode 100644
index 0000000..2dae613
--- /dev/null
+++ b/x2x.c
@@ -0,0 +1,1440 @@
+/*
+ * x2x: Uses the XTEST extension to forward keystrokes from a window on
+ * one display to another display. Useful for desks
+ * with multiple keyboards.
+ *
+ * Copyright (c) 1997
+ * Digital Equipment Corporation. All rights reserved.
+ *
+ * By downloading, installing, using, modifying or distributing this
+ * software, you agree to the following:
+ *
+ * 1. CONDITIONS. Subject to the following conditions, you may download,
+ * install, use, modify and distribute this software in source and binary
+ * forms:
+ *
+ * a) Any source code, binary code and associated documentation
+ * (including the online manual) used, modified or distributed must
+ * reproduce and retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * b) No right is granted to use any trade name, trademark or logo of
+ * Digital Equipment Corporation. Neither the "Digital Equipment
+ * Corporation" name nor any trademark or logo of Digital Equipment
+ * Corporation may be used to endorse or promote products derived from
+ * this software without the prior written permission of Digital
+ * Equipment Corporation.
+ *
+ * 2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Cygwin version with -fromwin to allow source to be a Windows
+ * machine that is not running a X server.
+ * Adapted by Mark Hayter 2003 using win2vnc ClientConnect.cpp code
+ *
+ * Original win2vnc copyright follows:
+ */
+// win2vnc, adapted from vncviewer by Fredrik Hubinette 2001
+//
+// Original copyright follows:
+//
+// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
+//
+// This file is part of the VNC system.
+//
+// The VNC system 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 program 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 program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+//
+// If the source code for the VNC system is not available from the place
+// whence you received this file, check http://www.uk.research.att.com/vnc or contact
+// the authors on vnc@uk.research.att.com for information on obtaining it.
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/Xatom.h> /* for selection */
+#include <X11/Xos.h>
+#include <X11/extensions/XTest.h>
+#include <X11/keysym.h>
+#include "format.h"
+
+
+extern void fake_motion(int x,int y);
+extern void fake_button_event(int b,int ud);
+extern void fake_key_event(int k,int ud);
+extern void fake_init(Display *d);
+
+/*#define DEBUG*/
+
+/**********
+ * definitions for edge
+ **********/
+#define EDGE_NONE 0 /* don't transfer between edges of screens */
+#define EDGE_EAST 1 /* from display is on the east side of to display */
+#define EDGE_WEST 2 /* from display is on the west side of to display */
+
+/**********
+ * functions
+ **********/
+static void ParseCommandLine();
+static Display *OpenAndCheckDisplay();
+static Bool CheckTestExtension();
+static void DoX2X();
+static void InitDpyInfo();
+static void DoConnect();
+static void DoDisconnect();
+static void RegisterEventHandlers();
+static Bool ProcessEvent();
+static Bool ProcessMotionNotify();
+static Bool ProcessExpose();
+static Bool ProcessEnterNotify();
+static Bool ProcessButtonPress();
+static Bool ProcessButtonRelease();
+static Bool ProcessKeyEvent();
+static Bool ProcessConfigureNotify();
+static Bool ProcessClientMessage();
+static Bool ProcessPropertyNotify();
+static Bool ProcessVisibility();
+static Bool ProcessMapping();
+static void FakeThingsUp();
+static void FakeAction();
+static void RefreshPointerMapping();
+static void Usage();
+
+
+
+/**********
+ * text formatting instructions
+ **********/
+#define toDpyFormatLength (sizeof(toDpyFormat) / sizeof(Format))
+static Format toDpyFormat[] = {
+ FormatMeasureText,
+ FormatSetLeft, 0,
+ FormatSetTop, 0,
+ FormatAddHalfTextX, 1,
+ FormatAddHalfTextY, 3,
+ FormatString, (Format)"unknown",
+ FormatAddHalfTextX, 1,
+ FormatAddHalfTextY, 1
+ };
+/* indexes of values to be filled in at runtime */
+#define toDpyLeftIndex 2
+#define toDpyTopIndex 4
+#define toDpyStringIndex 10
+
+/**********
+ * stuff for selection forwarding
+ **********/
+typedef struct _dpyxtra {
+ Display *otherDpy;
+ int sState;
+ Atom pingAtom;
+ Bool pingInProg;
+ Window propWin;
+} DPYXTRA, *PDPYXTRA;
+
+/**********
+ * structures for recording state of buttons and keys
+ **********/
+typedef struct _fakestr {
+ struct _fakestr *pNext;
+ int type;
+ unsigned int thing;
+} FAKE, *PFAKE;
+
+#define FAKE_KEY 0
+#define FAKE_BUTTON 1
+
+#define N_BUTTONS 5
+
+#define GETDPYXTRA(DPY,PDPYINFO)\
+ (((DPY) == (PDPYINFO)->fromDpy) ?\
+ &((PDPYINFO)->fromDpyXtra) : &((PDPYINFO)->toDpyXtra))
+
+/* values for sState */
+#define SELSTATE_ON 0
+#define SELSTATE_OFF 1
+#define SELSTATE_WAIT 2
+
+/* special values for translated coordinates */
+#define COORD_INCR -1
+#define COORD_DECR -2
+#define SPECIAL_COORD(COORD) (((COORD) < 0) ? (COORD) : 0)
+
+/* max unreasonable coordinates before accepting it */
+#define MAX_UNREASONABLES 10
+
+/**********
+ * display information
+ **********/
+typedef struct {
+ /* stuff on "from" display */
+ Display *fromDpy;
+ Window root;
+ Window trigger;
+ Window big;
+ GC textGC;
+ Atom wmpAtom, wmdwAtom;
+ Cursor grabCursor;
+ XFS *font;
+ int twidth, theight;
+ int lastFromX;
+ int unreasonableDelta;
+
+
+ /* stuff on "to" display */
+ Window selWin;
+ unsigned int inverseMap[N_BUTTONS + 1]; /* inverse of button mapping */
+
+ /* state of connection */
+ int mode; /* connection */
+ int eventMask; /* trigger */
+
+ /* coordinate conversion stuff */
+ int toScreen;
+ int nScreens;
+ short **xTables; /* precalculated conversion tables */
+ short **yTables;
+ int fromXConn, fromXDisc; /* location of cursor after conn/disc ops */
+ int fromXIncr, fromXDecr; /* location of cursor after incr/decr ops */
+
+ /* selection forwarding info */
+ DPYXTRA fromDpyXtra;
+ DPYXTRA toDpyXtra;
+ Display *sDpy;
+ Time sTime;
+
+ /* for recording state of buttons and keys */
+ PFAKE pFakeThings;
+
+} DPYINFO, *PDPYINFO;
+
+/* shadow displays */
+typedef struct _shadow {
+ struct _shadow *pNext;
+ char *name;
+} SHADOW, *PSHADOW;
+
+/* sticky keys */
+typedef struct _sticky {
+ struct _sticky *pNext;
+ KeySym keysym;
+} STICKY, *PSTICKY;
+
+typedef int (*HANDLER)(); /* event handler function */
+
+
+/**********
+ * top-level variables
+ **********/
+static char *programStr = "x2x";
+static char *fromDpyName = NULL;
+static char *toDpyName = NULL;
+static char *defaultFN = "-*-times-bold-r-*-*-*-180-*-*-*-*-*-*";
+static char *fontName = "-*-times-bold-r-*-*-*-180-*-*-*-*-*-*";
+static char *pingStr = "PING"; /* atom for ping request */
+static char *geomStr = NULL;
+static Bool waitDpy = False;
+static Bool doBig = False;
+static Bool doMouse = True;
+static int doEdge = EDGE_NONE;
+static Bool doAutoUp = True;
+static Bool doResurface = False;
+static PSHADOW shadows = NULL;
+static int triggerw = 2;
+static Bool doPointerMap = True;
+static PSTICKY stickies = NULL;
+static Bool doBtnBlock = False;
+static Bool doCapsLkHack = False;
+static Bool doClipCheck = False;
+
+/**********
+ * main
+ **********/
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ Display *fromDpy;
+ PSHADOW pShadow;
+
+
+ XrmInitialize();
+ ParseCommandLine(argc, argv);
+
+ fromDpyName = XDisplayName(fromDpyName);
+
+#if 0
+ toDpyName = XDisplayName(toDpyName);
+ if (!strcasecmp(toDpyName, fromDpyName)) {
+ fprintf(stderr, "%s: display names are both %s\n", programStr, toDpyName);
+ exit(1);
+ }
+#endif
+
+ /* no OS independent wat to stop Xlib from complaining via stderr,
+ but can always pipe stdout/stderr to /dev/null */
+ /* convert to real name: */
+ while ((fromDpy = XOpenDisplay(fromDpyName)) == NULL) {
+ if (!waitDpy) {
+ fprintf(stderr, "%s - error: can not open display %s\n",
+ programStr, fromDpyName);
+ exit(2);
+ } /* END if */
+ sleep(10);
+ } /* END while fromDpy */
+
+ /* toDpy is always the first shadow */
+ pShadow = (PSHADOW)malloc(sizeof(SHADOW));
+ pShadow->name = toDpyName;
+ /* link into the global list */
+ pShadow->pNext = shadows;
+ shadows = pShadow;
+#if 0
+
+ /* initialize all of the shadows, including the toDpy */
+ for (pShadow = shadows; pShadow; pShadow = pShadow->pNext)
+ if (!(pShadow->dpy = OpenAndCheckDisplay(pShadow->name)))
+ exit(3);
+#endif
+
+ fake_init(fromDpy);
+
+ /* run the x2x loop */
+ DoX2X(fromDpy );
+
+ /* shut down gracefully */
+
+ XCloseDisplay(fromDpy);
+
+#if 0
+ for (pShadow = shadows; pShadow; pShadow = pShadow->pNext)
+ XCloseDisplay(pShadow->dpy);
+#endif
+ exit(0);
+
+} /* END main */
+
+#if 0
+static Display *OpenAndCheckDisplay(name)
+char *name;
+{
+ Display *openDpy;
+
+ /* convert to real name: */
+ name = XDisplayName(name);
+ while ((openDpy = XOpenDisplay(name)) == NULL) {
+ if (!waitDpy) {
+ fprintf(stderr, "%s - error: can not open display %s\n",
+ programStr, name);
+ return NULL;
+ } /* END if */
+ sleep(10);
+ } /* END while openDpy */
+
+ if (!CheckTestExtension(openDpy)) {
+ fprintf(stderr,
+ "%s - error: display %s does not support the test extension\n",
+ programStr, name);
+ return NULL;
+ }
+ return (openDpy);
+
+} /* END OpenAndCheckDisplay */
+#endif
+
+/**********
+ * use standard X functions to parse the command line
+ **********/
+static void ParseCommandLine(argc, argv)
+int argc;
+char **argv;
+{
+ int arg;
+ PSHADOW pShadow;
+ extern char *lawyerese;
+ PSTICKY pNewSticky;
+ KeySym keysym;
+
+#ifdef DEBUG
+ printf ("programStr = %s\n", programStr);
+#endif
+
+ for (arg = 1; arg < argc; ++arg) {
+ if (!strcasecmp(argv[arg], "-from")) {
+ if (++arg >= argc) Usage();
+ fromDpyName = argv[arg];
+
+#ifdef DEBUG
+ printf ("fromDpyName = %s\n", fromDpyName);
+#endif
+ } else if (!strcasecmp(argv[arg], "-to")) {
+ if (++arg >= argc) Usage();
+ toDpyName = argv[arg];
+
+#ifdef DEBUG
+ printf ("toDpyName = %s\n", toDpyName);
+#endif
+ } else if (!strcasecmp(argv[arg], "-font")) {
+ if (++arg >= argc) Usage();
+ fontName = argv[arg];
+
+#ifdef DEBUG
+ printf ("fontName = %s\n", fontName);
+#endif
+ } else if (!strcasecmp(argv[arg], "-geometry")) {
+ if (++arg >= argc) Usage();
+ geomStr = argv[arg];
+
+#ifdef DEBUG
+ printf ("geometry = %s\n", geomStr);
+#endif
+ } else if (!strcasecmp(argv[arg], "-wait")) {
+ waitDpy = True;
+
+#ifdef DEBUG
+ printf("will wait for displays\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-big")) {
+ doBig = True;
+
+#ifdef DEBUG
+ printf("will create big window on from display\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-nomouse")) {
+ doMouse = False;
+
+#ifdef DEBUG
+ printf("will not capture mouse (eek!)\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-nopointermap")) {
+ doPointerMap = False;
+
+#ifdef DEBUG
+ printf("will not do pointer mapping\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-east")) {
+ doEdge = EDGE_EAST;
+#ifdef DEBUG
+ printf("\"from\" is on the east side of \"to\"\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-west")) {
+ doEdge = EDGE_WEST;
+#ifdef DEBUG
+ printf("\"from\" is on the west side of \"to\"\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-noautoup")) {
+ doAutoUp = False;
+#ifdef DEBUG
+ printf("will not automatically lift keys and buttons\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-buttonblock")) {
+ doBtnBlock = True;
+#ifdef DEBUG
+ printf("mouse buttons down will block disconnects\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-capslockhack")) {
+ doCapsLkHack = True;
+#ifdef DEBUG
+ printf("behavior of CapsLock will be hacked\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-clipcheck")) {
+ doClipCheck = True;
+#ifdef DEBUG
+ printf("Clipboard type will be checked for XA_STRING\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-nocapslockhack")) {
+ doCapsLkHack = False;
+#ifdef DEBUG
+ printf("behavior of CapsLock will not be hacked\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-sticky")) {
+ if (++arg >= argc) Usage();
+ if ((keysym = XStringToKeysym(argv[arg])) != NoSymbol) {
+ pNewSticky = (PSTICKY)malloc(sizeof(STICKY));
+ pNewSticky->pNext = stickies;
+ pNewSticky->keysym = keysym;
+ stickies = pNewSticky;
+#ifdef DEBUG
+ printf("will press/release sticky key: %s\n", argv[arg]);
+#endif
+ } else {
+ printf("x2x: warning: can't translate %s\n", argv[arg]);
+ }
+ } else if (!strcasecmp(argv[arg], "-resurface")) {
+ doResurface = True;
+#ifdef DEBUG
+ printf("will resurface the trigger window when obscured\n");
+#endif
+ } else if (!strcasecmp(argv[arg], "-shadow")) {
+ if (++arg >= argc) Usage();
+ pShadow = (PSHADOW)malloc(sizeof(SHADOW));
+ pShadow->name = argv[arg];
+
+ /* into the global list of shadows */
+ pShadow->pNext = shadows;
+ shadows = pShadow;
+
+ } else if (!strcasecmp(argv[arg], "-triggerw")) {
+ if (++arg >= argc) Usage();
+ triggerw = atoi(argv[arg]);
+ } else if (!strcasecmp(argv[arg], "-copyright")) {
+ printf(lawyerese);
+ } else {
+ Usage();
+ } /* END if... */
+ } /* END for */
+
+} /* END ParseCommandLine */
+
+static void Usage()
+{
+ printf("Usage: x2x [-to <DISPLAY> | -from <DISPLAY>] options...\n");
+ printf(" -copyright\n");
+ printf(" -font <FONTNAME>\n");
+ printf(" -geometry <GEOMETRY>\n");
+ printf(" -wait\n");
+ printf(" -big\n");
+ printf(" -buttonblock\n");
+ printf(" -nomouse\n");
+ printf(" -east\n");
+ printf(" -west\n");
+ printf(" -nosel\n");
+ printf(" -noautoup\n");
+ printf(" -resurface\n");
+ printf(" -capslockhack\n");
+ printf(" -nocapslockhack\n");
+ printf(" -clipcheck\n");
+ printf(" -shadow <DISPLAY>\n");
+ printf(" -sticky <sticky key>\n");
+ exit(4);
+
+} /* END Usage */
+
+/**********
+ * call the library to check for the test extension
+ **********/
+#if 0
+static Bool CheckTestExtension(dpy)
+Display *dpy;
+{
+ int eventb, errorb;
+ int vmajor, vminor;
+
+ return (XTestQueryExtension(dpy, &eventb, &errorb, &vmajor, &vminor));
+
+} /* END CheckTestExtension */
+#endif
+
+#define X2X_DISCONNECTED 0
+#define X2X_AWAIT_RELEASE 1
+#define X2X_CONNECTED 2
+#define X2X_CONN_RELEASE 3
+
+static void DoX2X(fromDpy )
+Display *fromDpy;
+{
+ DPYINFO dpyInfo;
+ int nfds;
+ fd_set fdset;
+ Bool fromPending;
+ int fromConn, toConn;
+
+ /* set up displays */
+ dpyInfo.fromDpy = fromDpy;
+ InitDpyInfo(&dpyInfo);
+ RegisterEventHandlers(&dpyInfo);
+
+ /* set up for select */
+ fromConn = XConnectionNumber(fromDpy);
+
+#if 0
+ toConn = XConnectionNumber(toDpy);
+ nfds = (fromConn > toConn ? fromConn : toConn) + 1;
+#else
+ nfds=fromConn+1;
+#endif
+
+ while (True) { /* FOREVER */
+ if ((fromPending = XPending(fromDpy)))
+ if (ProcessEvent(fromDpy, &dpyInfo)) /* done! */
+ break;
+ FD_ZERO(&fdset);
+ FD_SET(fromConn, &fdset);
+#if 0
+ FD_SET(toConn, &fdset);
+#endif
+ if (!XPending(fromDpy))
+ select(nfds, &fdset, NULL, NULL, NULL);
+
+ } /* END FOREVER */
+
+} /* END DoX2X() */
+
+static void InitDpyInfo(pDpyInfo)
+PDPYINFO pDpyInfo;
+{
+ Display *fromDpy, *toDpy;
+ Screen *fromScreen;
+ long black, white;
+ int fromHeight, fromWidth, toHeight, toWidth;
+ Pixmap nullPixmap;
+ XColor dummyColor;
+ Window root, trigger, big, rret, toRoot, propWin;
+ short *xTable, *yTable; /* short: what about dimensions > 2^15? */
+ int *heights, *widths;
+ int counter;
+ int nScreens, screenNum;
+ int twidth, theight; /* text dimensions */
+ int xoff, yoff; /* window offsets */
+ unsigned int width, height; /* window width, height */
+ int geomMask; /* mask returned by parse */
+ int gravMask;
+ int gravity;
+ int xret, yret, wret, hret, bret, dret;
+ XSetWindowAttributes xswa;
+ XSizeHints *xsh;
+ int eventMask;
+ GC textGC;
+ char *windowName;
+ XFS *font;
+ PSHADOW pShadow;
+ int triggerLoc;
+
+ /* cache commonly used variables */
+ fromDpy = pDpyInfo->fromDpy;
+
+ fromScreen = XDefaultScreenOfDisplay(fromDpy);
+ black = XBlackPixelOfScreen(fromScreen);
+ white = XWhitePixelOfScreen(fromScreen);
+ fromHeight = XHeightOfScreen(fromScreen);
+ fromWidth = XWidthOfScreen(fromScreen);
+
+ /* values also in dpyinfo */
+ root = pDpyInfo->root = XDefaultRootWindow(fromDpy);
+ nScreens = pDpyInfo->nScreens = 1;
+
+ /* other dpyinfo values */
+ pDpyInfo->mode = X2X_DISCONNECTED;
+ pDpyInfo->unreasonableDelta = fromWidth / 2;
+ pDpyInfo->pFakeThings = NULL;
+
+ /* window init structures */
+ xswa.override_redirect = True;
+ xsh = XAllocSizeHints();
+ eventMask = KeyPressMask | KeyReleaseMask;
+
+ /* cursor locations for moving between screens */
+ pDpyInfo->fromXIncr = triggerw;
+ pDpyInfo->fromXDecr = fromWidth - triggerw - 1;
+ if (doEdge) { /* edge triggers x2x */
+ nullPixmap = XCreatePixmap(fromDpy, root, 1, 1, 1);
+ eventMask |= EnterWindowMask;
+ pDpyInfo->grabCursor =
+ XCreatePixmapCursor(fromDpy, nullPixmap, nullPixmap,
+ &dummyColor, &dummyColor, 0, 0);
+
+ if (doEdge == EDGE_EAST) {
+ /* trigger window location */
+ triggerLoc = fromWidth - triggerw;
+ toHeight = 2048;
+ pDpyInfo->fromXConn = 1;
+ pDpyInfo->fromXDisc = fromWidth - triggerw - 1;
+ } else {
+ /* trigger window location */
+ triggerLoc = 0;
+ toHeight = 2048;
+ toWidth = 2048;
+ pDpyInfo->fromXConn = fromWidth - triggerw - 1;
+ pDpyInfo->fromXDisc = triggerw;
+ } /* END if doEdge == ... */
+
+ xswa.background_pixel = black;
+
+ fprintf(stderr,"x=%d y=%d w=%d h=%d\n",triggerLoc,0,triggerw,fromHeight);
+ /* fromWidth - 1 doesn't seem to work for some reason */
+ trigger = pDpyInfo->trigger =
+ XCreateWindow(fromDpy, root, triggerLoc, 0, triggerw, fromHeight,
+ 0, 0, InputOutput, 0,
+ CWBackPixel | CWOverrideRedirect, &xswa);
+ font = NULL;
+
+ } else { /* normal window for text: do size grovelling */
+ pDpyInfo->grabCursor = XCreateFontCursor(fromDpy, XC_exchange);
+ eventMask |= StructureNotifyMask | ExposureMask;
+ if (doMouse) eventMask |= ButtonPressMask | ButtonReleaseMask;
+
+ /* determine size of text */
+ if (((font = XLoadQueryFont(fromDpy, fontName)) != NULL) ||
+ ((font = XLoadQueryFont(fromDpy, defaultFN)) != NULL) ||
+ ((font = XLoadQueryFont(fromDpy, "fixed")) != NULL)) {
+ /* have a font */
+ toDpyFormat[toDpyStringIndex] = (Format)toDpyName;
+ formatText(NULL, NULL, NULL, font,
+ toDpyFormatLength, toDpyFormat, &twidth, &theight);
+
+ textGC = pDpyInfo->textGC = XCreateGC(fromDpy, root, 0, NULL);
+ XSetState(fromDpy, textGC, black, white, GXcopy, AllPlanes);
+ XSetFont(fromDpy, textGC, font->fid);
+
+ } else { /* should not have to execute this clause: */
+ twidth = theight = 100; /* default window size */
+ } /* END if have a font ... else ... */
+
+ /* determine size of window */
+ xoff = yoff = 0;
+ width = twidth;
+ height = theight;
+ geomMask = XParseGeometry(geomStr, &xoff, &yoff, &width, &height);
+ switch (gravMask = (geomMask & (XNegative | YNegative))) {
+ case (XNegative | YNegative): gravity = SouthEastGravity; break;
+ case XNegative: gravity = NorthEastGravity; break;
+ case YNegative: gravity = SouthWestGravity; break;
+ default: gravity = NorthWestGravity; break;
+ }
+ if (gravMask) {
+ XGetGeometry(fromDpy, root,
+ &rret, &xret, &yret, &wret, &hret, &bret, &dret);
+ if ((geomMask & (XValue | XNegative)) == (XValue | XNegative)){
+ xoff = wret - width + xoff;
+ }
+ if ((geomMask & (YValue | YNegative)) == (YValue | YNegative)) {
+ yoff = hret - height + yoff;
+ }
+ } /* END if geomMask */
+
+ trigger = pDpyInfo->trigger =
+ XCreateSimpleWindow(fromDpy, root, xoff, yoff, width, height,
+ 0, black, white);
+ } /* END if doEdge ... else ...*/
+
+ /* size hints stuff: */
+ xsh->x = xoff;
+ xsh->y = yoff;
+ xsh->base_width = width;
+ xsh->base_height = height;
+ xsh->win_gravity = gravity;
+ xsh->flags = (PPosition|PBaseSize|PWinGravity);
+ XSetWMNormalHints(fromDpy, trigger, xsh);
+
+ windowName = (char *)malloc(strlen(programStr) + strlen(toDpyName) + 2);
+ strcpy(windowName, programStr);
+ strcat(windowName, " ");
+ strcat(windowName, toDpyName);
+ XStoreName(fromDpy, trigger, windowName);
+ XSetIconName(fromDpy, trigger, windowName);
+
+ /* register for WM_DELETE_WINDOW protocol */
+ pDpyInfo->wmpAtom = XInternAtom(fromDpy, "WM_PROTOCOLS", True);
+ pDpyInfo->wmdwAtom = XInternAtom(fromDpy, "WM_DELETE_WINDOW", True);
+ XSetWMProtocols(fromDpy, trigger, &(pDpyInfo->wmdwAtom), 1);
+
+ /* mdh - Put in Chaiken's change to make this InputOnly */
+ if (doBig) {
+ big = pDpyInfo->big =
+ XCreateWindow(fromDpy, root, 0, 0, fromWidth, fromHeight, 0,
+ 0, InputOnly, 0, CWOverrideRedirect, &xswa);
+ /* size hints stuff: */
+ xsh->x = 0;
+ xsh->y = 0;
+ xsh->base_width = fromWidth;
+ xsh->base_height = fromHeight;
+ xsh->min_width = fromWidth;
+ xsh->min_height = fromHeight;
+ xsh->flags = (PMinSize|PPosition|PBaseSize);
+
+ XSetWMNormalHints(fromDpy, big, xsh);
+ XStoreName(fromDpy, big, windowName);
+ XSetIconName(fromDpy, big, windowName);
+ } else {
+ pDpyInfo->big = None;
+ }
+
+ XFree((char *) xsh);
+ free(windowName);
+
+ /* conversion stuff */
+ pDpyInfo->toScreen = (doEdge == EDGE_WEST) ? (nScreens - 1) : 0;
+
+ /* construct table lookup for screen coordinate conversion */
+ pDpyInfo->xTables = (short **)malloc(sizeof(short *) * nScreens);
+ pDpyInfo->yTables = (short **)malloc(sizeof(short *) * nScreens);
+ heights = (int *)malloc(sizeof(int *) * nScreens);
+ widths = (int *)malloc(sizeof(int *) * nScreens);
+
+ for (screenNum = 0; screenNum < nScreens; ++screenNum) {
+ widths[screenNum] = toWidth = 2048;
+ heights[screenNum] = toHeight = 2048;
+
+ pDpyInfo->xTables[screenNum] = xTable =
+ (short *)malloc(sizeof(short) * fromWidth);
+ pDpyInfo->yTables[screenNum] = yTable =
+ (short *)malloc(sizeof(short) * fromHeight);
+
+ /* vertical conversion table */
+ for (counter = 0; counter < fromHeight; ++counter)
+ yTable[counter] = (counter * toHeight) / fromHeight;
+
+ /* horizontal conversion table entries */
+ for (counter = 0; counter < fromWidth; ++counter)
+ xTable[counter] = (counter * toWidth) / fromWidth;
+
+ /* adjustment for boundaries */
+ if ((screenNum != 0) || (doEdge == EDGE_EAST))
+ xTable[0] = COORD_DECR;
+ if (((screenNum + 1) < nScreens) || (doEdge == EDGE_WEST)) {
+ xTable[fromWidth - 1] = COORD_INCR;
+ /* work-around for bug: on at least one tested screen, cursor
+ never moved past fromWidth - 2 */
+ xTable[fromWidth - 2] = COORD_INCR;
+ }
+
+ } /* END for screenNum */
+
+ free(heights);
+ free(widths);
+
+ if (doResurface) /* get visibility events */
+ eventMask |= VisibilityChangeMask;
+
+ XSelectInput(fromDpy, trigger, eventMask);
+ pDpyInfo->eventMask = eventMask; /* save for future munging */
+ XMapRaised(fromDpy, trigger);
+ if ((pDpyInfo->font = font)) { /* paint text */
+ /* position text */
+ pDpyInfo->twidth = twidth;
+ pDpyInfo->theight = theight;
+ toDpyFormat[toDpyLeftIndex] = MAX(0,((width - twidth) / 2));
+ toDpyFormat[toDpyTopIndex] = MAX(0,((height - theight) / 2));
+
+ formatText(fromDpy, trigger, &(textGC), font,
+ toDpyFormatLength, toDpyFormat, NULL, NULL);
+ } /* END if font */
+
+} /* END InitDpyInfo */
+
+static void DoConnect(pDpyInfo)
+PDPYINFO pDpyInfo;
+{
+ Display *fromDpy = pDpyInfo->fromDpy;
+ Window trigger = pDpyInfo->trigger;
+
+#ifdef DEBUG
+ printf("connecting\n");
+#endif
+ pDpyInfo->mode = X2X_CONNECTED;
+
+ if (pDpyInfo->big != None) XMapRaised(fromDpy, pDpyInfo->big);
+ XGrabPointer(fromDpy, trigger, True,
+ PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync,
+ None, pDpyInfo->grabCursor, CurrentTime);
+ XGrabKeyboard(fromDpy, trigger, True,
+ GrabModeAsync, GrabModeAsync,
+ CurrentTime);
+ XSelectInput(fromDpy, trigger, pDpyInfo->eventMask | PointerMotionMask);
+ XFlush(fromDpy);
+} /* END DoConnect */
+
+static void DoDisconnect(pDpyInfo)
+PDPYINFO pDpyInfo;
+{
+ Display *fromDpy = pDpyInfo->fromDpy;
+ PDPYXTRA pDpyXtra;
+
+#ifdef DEBUG
+ printf("disconnecting\n");
+#endif
+ pDpyInfo->mode = X2X_DISCONNECTED;
+ if (pDpyInfo->big != None) XUnmapWindow(fromDpy, pDpyInfo->big);
+ XUngrabKeyboard(fromDpy, CurrentTime);
+ XUngrabPointer(fromDpy, CurrentTime);
+ XSelectInput(fromDpy, pDpyInfo->trigger, pDpyInfo->eventMask);
+
+ XFlush(fromDpy);
+
+ /* force normal state on to display: */
+ if (doAutoUp)
+ FakeThingsUp(pDpyInfo);
+} /* END DoDisconnect */
+
+static void RegisterEventHandlers(pDpyInfo)
+PDPYINFO pDpyInfo;
+{
+ Display *fromDpy = pDpyInfo->fromDpy;
+ Window trigger = pDpyInfo->trigger;
+ Window propWin;
+
+#define XSAVECONTEXT(A, B, C, D) XSaveContext(A, B, C, (XPointer)(D))
+
+ XSAVECONTEXT(fromDpy, trigger, MotionNotify, ProcessMotionNotify);
+ XSAVECONTEXT(fromDpy, trigger, Expose, ProcessExpose);
+ XSAVECONTEXT(fromDpy, trigger, EnterNotify, ProcessEnterNotify);
+ XSAVECONTEXT(fromDpy, trigger, ButtonPress, ProcessButtonPress);
+ XSAVECONTEXT(fromDpy, trigger, ButtonRelease, ProcessButtonRelease);
+ XSAVECONTEXT(fromDpy, trigger, KeyPress, ProcessKeyEvent);
+ XSAVECONTEXT(fromDpy, trigger, KeyRelease, ProcessKeyEvent);
+ XSAVECONTEXT(fromDpy, trigger, ConfigureNotify, ProcessConfigureNotify);
+ XSAVECONTEXT(fromDpy, trigger, ClientMessage, ProcessClientMessage);
+ XSAVECONTEXT(fromDpy, trigger, ClientMessage, ProcessClientMessage);
+ XSAVECONTEXT(fromDpy, trigger, ClientMessage, ProcessClientMessage);
+ XSAVECONTEXT(fromDpy, None, MappingNotify, ProcessMapping);
+
+
+ if (doResurface)
+ XSAVECONTEXT(fromDpy, trigger, VisibilityNotify, ProcessVisibility);
+
+
+} /* END RegisterEventHandlers */
+
+static Bool ProcessEvent(dpy, pDpyInfo)
+Display *dpy;
+PDPYINFO pDpyInfo;
+{
+ XEvent ev;
+ XAnyEvent *pEv = (XAnyEvent *)&ev;
+ HANDLER handler;
+
+#define XFINDCONTEXT(A, B, C, D) XFindContext(A, B, C, (XPointer *)(D))
+
+ XNextEvent(dpy, &ev);
+ handler = 0;
+ if ((!XFINDCONTEXT(dpy, pEv->window, pEv->type, &handler)) ||
+ (!XFINDCONTEXT(dpy, None, pEv->type, &handler))) {
+ /* have handler */
+ return ((*handler)(dpy, pDpyInfo, &ev));
+ } else {
+#ifdef DEBUG
+ printf("no handler for window 0x%x, event type %d\n",
+ (unsigned int)pEv->window, pEv->type);
+#endif
+ } /* END if/else */
+
+ return False;
+
+} /* END ProcessEvent */
+
+static Bool ProcessMotionNotify(unused, pDpyInfo, pEv)
+Display *unused;
+PDPYINFO pDpyInfo;
+XMotionEvent *pEv; /* caution: might be pseudo-event!!! */
+{
+ /* Note: ProcessMotionNotify is sometimes called from inside x2x to
+ * simulate a motion event. Any new references to pEv fields
+ * must be checked carefully!
+ */
+
+ int toScreenNum;
+ PSHADOW pShadow;
+ int toX, fromX, delta;
+ Display *fromDpy;
+ Bool bAbortedDisconnect;
+
+ /* find the screen */
+ toScreenNum = pDpyInfo->toScreen;
+ fromX = pEv->x_root;
+
+ /* check to make sure the cursor is still on the from screen */
+ if (!(pEv->same_screen)) {
+ toX = (pDpyInfo->lastFromX < fromX) ? COORD_DECR : COORD_INCR;
+ } else {
+ toX = pDpyInfo->xTables[toScreenNum][fromX];
+
+ /* sanity check motion: necessary for nondeterminism surrounding warps */
+ delta = pDpyInfo->lastFromX - fromX;
+ if (delta < 0) delta = -delta;
+ if (delta > pDpyInfo->unreasonableDelta) return False;
+ }
+
+ if (SPECIAL_COORD(toX) != 0) { /* special coordinate */
+ bAbortedDisconnect = False;
+ if (toX == COORD_INCR) {
+ if (toScreenNum != (pDpyInfo->nScreens - 1)) { /* next screen */
+ toScreenNum = ++(pDpyInfo->toScreen);
+ fromX = pDpyInfo->fromXIncr;
+ toX = pDpyInfo->xTables[toScreenNum][fromX];
+ } else { /* disconnect! */
+ if (doBtnBlock &&
+ (pEv->state & (Button1Mask | Button2Mask | Button3Mask |
+ Button4Mask | Button5Mask)))
+ bAbortedDisconnect = True;
+ else {
+ DoDisconnect(pDpyInfo);
+ fromX = pDpyInfo->fromXDisc;
+ }
+ toX = pDpyInfo->xTables[toScreenNum][pDpyInfo->fromXConn];
+ }
+ } else { /* DECR */
+ if (toScreenNum != 0) { /* previous screen */
+ toScreenNum = --(pDpyInfo->toScreen);
+ fromX = pDpyInfo->fromXDecr;
+ toX = pDpyInfo->xTables[toScreenNum][fromX];
+ } else { /* disconnect! */
+ if (doBtnBlock &&
+ (pEv->state & (Button1Mask | Button2Mask | Button3Mask |
+ Button4Mask | Button5Mask)))
+ bAbortedDisconnect = True;
+ else {
+ DoDisconnect(pDpyInfo);
+ fromX = pDpyInfo->fromXDisc;
+ }
+ toX = pDpyInfo->xTables[toScreenNum][pDpyInfo->fromXConn];
+ }
+ } /* END if toX */
+ if (!bAbortedDisconnect) {
+ fromDpy = pDpyInfo->fromDpy;
+ XWarpPointer(fromDpy, None, pDpyInfo->root, 0, 0, 0, 0,
+ fromX, pEv->y_root);
+ XFlush(fromDpy);
+ }
+ } /* END if SPECIAL_COORD */
+ pDpyInfo->lastFromX = fromX;
+
+ for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
+ fake_motion(toX,pDpyInfo->yTables[toScreenNum][pEv->y_root]);
+ } /* END for */
+
+ return False;
+
+} /* END ProcessMotionNotify */
+
+static Bool ProcessExpose(dpy, pDpyInfo, pEv)
+Display *dpy;
+PDPYINFO pDpyInfo;
+XExposeEvent *pEv;
+{
+ XClearWindow(pDpyInfo->fromDpy, pDpyInfo->trigger);
+ if (pDpyInfo->font)
+ formatText(pDpyInfo->fromDpy, pDpyInfo->trigger,
+ &(pDpyInfo->textGC), pDpyInfo->font,
+ toDpyFormatLength, toDpyFormat, NULL, NULL);
+ return False;
+
+} /* END ProcessExpose */
+
+static Bool ProcessEnterNotify(dpy, pDpyInfo, pEv)
+Display *dpy;
+PDPYINFO pDpyInfo;
+XCrossingEvent *pEv;
+{
+ Display *fromDpy = pDpyInfo->fromDpy;
+ XMotionEvent xmev;
+
+ if ((pEv->mode == NotifyNormal) &&
+ (pDpyInfo->mode == X2X_DISCONNECTED) && (dpy == pDpyInfo->fromDpy)) {
+ DoConnect(pDpyInfo);
+ XWarpPointer(fromDpy, None, pDpyInfo->root, 0, 0, 0, 0,
+ pDpyInfo->fromXConn, pEv->y_root);
+ xmev.x_root = pDpyInfo->lastFromX = pDpyInfo->fromXConn;
+ xmev.y_root = pEv->y_root;
+ xmev.same_screen = True;
+ ProcessMotionNotify(NULL, pDpyInfo, &xmev);
+ } /* END if NotifyNormal... */
+ return False;
+
+} /* END ProcessEnterNotify */
+
+static Bool ProcessButtonPress(dpy, pDpyInfo, pEv)
+Display *dpy;
+PDPYINFO pDpyInfo;
+XButtonEvent *pEv;
+{
+ int state;
+ PSHADOW pShadow;
+ unsigned int toButton;
+
+ switch (pDpyInfo->mode) {
+ case X2X_DISCONNECTED:
+ pDpyInfo->mode = X2X_AWAIT_RELEASE;
+#ifdef DEBUG
+ printf("awaiting button release before connecting\n");
+#endif
+ break;
+ case X2X_CONNECTED:
+ if (pEv->button <= N_BUTTONS) {
+// toButton = pDpyInfo->inverseMap[pEv->button];
+ toButton = pEv->button;
+ for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
+ fake_button_event(toButton,True);
+#ifdef DEBUG
+ printf("from button %d down, to button %d down\n", pEv->button,toButton);
+#endif
+ } /* END for */
+ if (doAutoUp)
+ FakeAction(pDpyInfo, FAKE_BUTTON, toButton, True);
+ if (doEdge) break;
+ }
+
+ /* check if more than one button pressed */
+ state = pEv->state;
+ switch (pEv->button) {
+ case Button1: state &= ~Button1Mask; break;
+ case Button2: state &= ~Button2Mask; break;
+ case Button3: state &= ~Button3Mask; break;
+ case Button4: state &= ~Button4Mask; break;
+ case Button5: state &= ~Button5Mask; break;
+ default:
+#ifdef DEBUG
+ printf("unknown button %d\n", pEv->button);
+#endif
+ break;
+ } /* END switch button */
+ if (state) { /* then more than one button pressed */
+#ifdef DEBUG
+ printf("awaiting button release before disconnecting\n");
+#endif
+ pDpyInfo->mode = X2X_CONN_RELEASE;
+ }
+ break;
+ } /* END switch mode */
+ return False;
+} /* END ProcessButtonPress */
+
+static Bool ProcessButtonRelease(dpy, pDpyInfo, pEv)
+Display *dpy;
+PDPYINFO pDpyInfo;
+XButtonEvent *pEv;
+{
+ int state;
+ PSHADOW pShadow;
+ XMotionEvent xmev;
+ unsigned int toButton;
+
+ if ((pDpyInfo->mode == X2X_CONNECTED) ||
+ (pDpyInfo->mode == X2X_CONN_RELEASE)) {
+ if (pEv->button <= N_BUTTONS) {
+ toButton = pEv->button;
+// toButton = pDpyInfo->inverseMap[pEv->button];
+ for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
+ fake_button_event(toButton,False);
+#ifdef DEBUG
+ printf("from button %d up, to button %d up\n", pEv->button, toButton);
+#endif
+ } /* END for */
+ if (doAutoUp)
+ FakeAction(pDpyInfo, FAKE_BUTTON, toButton, False);
+ }
+ } /* END if */
+
+ if (doEdge) return False;
+ if ((pDpyInfo->mode == X2X_AWAIT_RELEASE) ||
+ (pDpyInfo->mode == X2X_CONN_RELEASE)) {
+ /* make sure that all buttons are released */
+ state = pEv->state;
+ switch (pEv->button) {
+ case Button1: state &= ~Button1Mask; break;
+ case Button2: state &= ~Button2Mask; break;
+ case Button3: state &= ~Button3Mask; break;
+ case Button4: state &= ~Button4Mask; break;
+ case Button5: state &= ~Button5Mask; break;
+ default:
+#ifdef DEBUG
+ printf("unknown button %d\n", pEv->button);
+#endif
+ break;
+ } /* END switch button */
+ if (!state) { /* all buttons up: time to (dis)connect */
+ if (pDpyInfo->mode == X2X_AWAIT_RELEASE) { /* connect */
+ DoConnect(pDpyInfo);
+ xmev.x_root = pDpyInfo->lastFromX = pEv->x_root;
+ xmev.y_root = pEv->y_root;
+ xmev.same_screen = True;
+ ProcessMotionNotify(NULL, pDpyInfo, &xmev);
+ } else { /* disconnect */
+ DoDisconnect(pDpyInfo);
+ } /* END if mode */
+ } /* END if !state */
+ } /* END if mode */
+ return False;
+
+} /* END ProcessButtonRelease */
+
+static Bool ProcessKeyEvent(dpy, pDpyInfo, pEv)
+Display *dpy;
+PDPYINFO pDpyInfo;
+XKeyEvent *pEv;
+{
+// KeyCode keycode;
+ KeySym keysym;
+ PSHADOW pShadow;
+ Bool bPress;
+ PSTICKY pSticky;
+ Bool DoFakeShift = False;
+ KeyCode toShiftCode;
+ KeyCode keycode;
+
+ XLookupString(pEv, NULL, 0, &keysym, NULL);
+ bPress = (pEv->type == KeyPress);
+
+ /* If CapsLock is on, we need to do some funny business to make sure the */
+ /* "to" display does the right thing */
+ if(doCapsLkHack && (pEv->state & 0x2))
+ {
+ /* Throw away any explicit shift events (they're faked as neccessary) */
+ if((keysym == XK_Shift_L) || (keysym == XK_Shift_R)) return False;
+
+ /* If the shift key is pressed, do the shift, unless the keysym */
+ /* is an alpha key, in which case we invert the shift logic */
+ DoFakeShift = (pEv->state & 0x1);
+ if(((keysym >= XK_A) && (keysym <= XK_Z)) ||
+ ((keysym >= XK_a) && (keysym <= XK_z)))
+ DoFakeShift = !DoFakeShift;
+ }
+
+ for (pSticky = stickies; pSticky; pSticky = pSticky->pNext)
+ if (keysym == pSticky->keysym)
+ break;
+
+ if (pSticky) {
+ for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
+#if 1
+ toShiftCode = XKeysymToKeycode(dpy, XK_Shift_L);
+ if ((keycode = XKeysymToKeycode(dpy, keysym))) {
+ if(DoFakeShift) fake_key_event(toShiftCode, True);
+ fake_key_event(keycode,True);
+ fake_key_event(keycode,False);
+ if(DoFakeShift) fake_key_event(toShiftCode, False);
+ } /* END if */
+#else
+ if(DoFakeShift) fake_key_event(XK_Shift_L, True);
+ fake_key_event(keysym,True);
+ fake_key_event(keysym,False);
+ if(DoFakeShift) fake_key_event(XK_Shift_L, False);
+
+#endif
+ } /* END for */
+ } else {
+ for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
+#if 1
+ toShiftCode = XKeysymToKeycode(dpy, XK_Shift_L);
+ if ((keycode = XKeysymToKeycode(dpy, keysym))) {
+ if(DoFakeShift) fake_key_event(toShiftCode, True);
+ fake_key_event(keycode,bPress);
+ if(DoFakeShift) fake_key_event(toShiftCode, False);
+ } /* END if */
+#else
+ if(DoFakeShift) fake_key_event(XK_Shift_L, True);
+ fake_key_event(keysym,bPress);
+ if(DoFakeShift) fake_key_event(XK_Shift_L, False);
+#endif
+ } /* END for */
+ if (doAutoUp)
+ FakeAction(pDpyInfo, FAKE_KEY, keysym, bPress);
+ }
+
+ return False;
+
+} /* END ProcessKeyEvent */
+
+static Bool ProcessConfigureNotify(dpy, pDpyInfo, pEv)
+Display *dpy;
+PDPYINFO pDpyInfo;
+XConfigureEvent *pEv;
+{
+ if (pDpyInfo->font) {
+ /* reposition text */
+ toDpyFormat[toDpyLeftIndex] =
+ MAX(0,((pEv->width - pDpyInfo->twidth) / 2));
+ toDpyFormat[toDpyTopIndex] =
+ MAX(0,((pEv->height - pDpyInfo->theight) / 2));
+ } /* END if font */
+ return False;
+
+} /* END ProcessConfigureNotify */
+
+static Bool ProcessClientMessage(dpy, pDpyInfo, pEv)
+Display *dpy;
+PDPYINFO pDpyInfo;
+XClientMessageEvent *pEv;
+{
+ /* terminate if atoms match! */
+ return ((pEv->message_type == pDpyInfo->wmpAtom) &&
+ (pEv->data.l[0] == pDpyInfo->wmdwAtom));
+
+} /* END ProcessClientMessage */
+
+
+
+/**********
+ * process a visibility event
+ **********/
+static Bool ProcessVisibility(dpy, pDpyInfo, pEv)
+Display *dpy;
+PDPYINFO pDpyInfo;
+XVisibilityEvent *pEv;
+{
+ /* might want to qualify, based on other messages. otherwise,
+ this code might cause a loop if two windows decide to fight
+ it out for the top of the stack */
+ if (pEv->state != VisibilityUnobscured)
+ XRaiseWindow(dpy, pEv->window);
+
+ return False;
+
+} /* END ProcessVisibility */
+
+/**********
+ * process a keyboard mapping event
+ **********/
+static Bool ProcessMapping(dpy, pDpyInfo, pEv)
+Display *dpy;
+PDPYINFO pDpyInfo;
+XMappingEvent *pEv;
+{
+#ifdef DEBUG
+ printf("mapping\n");
+#endif
+
+ switch (pEv->request) {
+ case MappingModifier:
+ case MappingKeyboard:
+ XRefreshKeyboardMapping(pEv);
+ break;
+ case MappingPointer:
+ RefreshPointerMapping(dpy, pDpyInfo);
+ break;
+ } /* END switch */
+
+ return False;
+
+} /* END ProcessMapping */
+
+static void FakeAction(pDpyInfo, type, thing, bDown)
+PDPYINFO pDpyInfo;
+unsigned int thing;
+Bool bDown;
+{
+ PFAKE *ppFake;
+ PFAKE pFake;
+
+ /* find the associated button, or the last record, whichever comes first */
+ for (ppFake = &(pDpyInfo->pFakeThings);
+ (*ppFake &&
+ (((*ppFake)->type != type) || ((*ppFake)->thing != thing)));
+ ppFake = &((*ppFake)->pNext));
+
+ if (bDown) { /* key down */
+ if (*ppFake == NULL) { /* need a new record */
+ pFake = (PFAKE)malloc(sizeof(FAKE));
+ pFake->pNext = NULL; /* always at the end of the list */
+ pFake->type = type;
+ pFake->thing = thing;
+ *ppFake = pFake;
+ } /* END if */
+ } else { /* key up */
+ if (*ppFake != NULL) { /* get rid of the record */
+ /* splice out of the list */
+ pFake = *ppFake;
+ *ppFake = pFake->pNext;
+ free(pFake); /* blam! */
+ } /* END if */
+ } /* END if */
+
+} /* END FakeAction */
+
+static void FakeThingsUp(pDpyInfo)
+PDPYINFO pDpyInfo;
+{
+ PFAKE pFake, pNext;
+ PSHADOW pShadow;
+ unsigned int type;
+ KeyCode keycode;
+
+ if (pDpyInfo->pFakeThings) { /* everything goes up! */
+ for (pFake = pDpyInfo->pFakeThings; pFake; pFake = pNext) {
+ type = pFake->type;
+ /* send up to all shadows */
+ for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) {
+ if (type == FAKE_KEY) { /* key goes up */
+#if 1
+ if ((keycode = XKeysymToKeycode(pDpyInfo->fromDpy, pFake->thing))) {
+ fake_key_event(keycode,False);
+#ifdef DEBUG
+ printf("key 0x%x up\n", pFake->thing);
+#endif
+ } /* END if */
+#else
+ fake_key_event(pFake->thing,False);
+#endif
+ } else { /* button goes up */
+ fake_button_event(pFake->thing,False);
+#ifdef DEBUG
+ printf("button %d up\n", pFake->thing);
+#endif
+ } /* END if/else */
+ } /* END for */
+
+ /* flush everything at once */
+
+ /* get next and free current */
+ pNext = pFake->pNext;
+ free(pFake);
+ } /* END for */
+
+ pDpyInfo->pFakeThings = NULL;
+ } /* END if */
+
+} /* END FakeThingsUp */
+
+static void RefreshPointerMapping(dpy, pDpyInfo)
+Display *dpy;
+PDPYINFO pDpyInfo;
+{
+ unsigned int buttCtr;
+ unsigned char buttonMap[N_BUTTONS];
+ int nButtons;
+
+ for (buttCtr = 1; buttCtr <= N_BUTTONS; ++buttCtr) {
+ pDpyInfo->inverseMap[buttCtr] = buttCtr;
+ } /* END for */
+
+
+#if 0
+ if (dpy == pDpyInfo->toDpy) { /* only care about toDpy */
+ /* straightforward mapping */
+ for (buttCtr = 1; buttCtr <= N_BUTTONS; ++buttCtr) {
+ pDpyInfo->inverseMap[buttCtr] = buttCtr;
+ } /* END for */
+
+ nButtons = MIN(N_BUTTONS, XGetPointerMapping(dpy, buttonMap, N_BUTTONS));
+ if (doPointerMap) {
+ for (buttCtr = 0; buttCtr < nButtons; ++buttCtr) {
+#ifdef DEBUG
+ printf("button %d -> %d\n", buttCtr + 1, buttonMap[buttCtr]);
+#endif
+ if (buttonMap[buttCtr] <= N_BUTTONS)
+ pDpyInfo->inverseMap[buttonMap[buttCtr]] = buttCtr + 1;
+ } /* END for */
+ } /* END if */
+ } /* END if toDpy */
+#endif
+
+} /* END RefreshPointerMapping */