diff options
-rw-r--r-- | Changes | 113 | ||||
-rw-r--r-- | Imakefile | 20 | ||||
-rw-r--r-- | format.c | 239 | ||||
-rw-r--r-- | format.h | 74 | ||||
-rw-r--r-- | keymap.c | 261 | ||||
-rw-r--r-- | keymap.h | 56 | ||||
-rw-r--r-- | lawyerese.c | 74 | ||||
-rw-r--r-- | nocursor.cur | bin | 0 -> 326 bytes | |||
-rw-r--r-- | resource.h | 2 | ||||
-rw-r--r-- | usb.c | 1282 | ||||
-rw-r--r-- | x2usb.man | 270 | ||||
-rw-r--r-- | x2x.c | 1440 |
12 files changed, 3831 insertions, 0 deletions
@@ -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 Binary files differnew file mode 100644 index 0000000..6bb01a5 --- /dev/null +++ b/nocursor.cur 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 @@ -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. @@ -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 */ |