From 8907955471eb1e6507b3e1a7a2ca2ce0849b7766 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 25 May 2015 17:59:50 +0100 Subject: fish --- Changes | 113 +++++ Imakefile | 20 + format.c | 239 ++++++++++ format.h | 74 +++ keymap.c | 261 +++++++++++ keymap.h | 56 +++ lawyerese.c | 74 +++ nocursor.cur | Bin 0 -> 326 bytes resource.h | 2 + usb.c | 1282 +++++++++++++++++++++++++++++++++++++++++++++++++++ x2usb.man | 270 +++++++++++ x2x.c | 1440 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 3831 insertions(+) create mode 100644 Changes create mode 100644 Imakefile create mode 100644 format.c create mode 100644 format.h create mode 100644 keymap.c create mode 100644 keymap.h create mode 100644 lawyerese.c create mode 100644 nocursor.cur create mode 100644 resource.h create mode 100644 usb.c create mode 100644 x2usb.man create mode 100644 x2x.c diff --git a/Changes b/Changes new file mode 100644 index 0000000..65dbe1f --- /dev/null +++ b/Changes @@ -0,0 +1,113 @@ +RCS 1.1 -nAlpha1 : First release for Puneet and David to play with +Files: +Imakefile +format.c +format.h +keymap.c +keymap.h +lawyerese.c +x2x.1 +x2x.c + + +22 Sept 03 released Alpha2 +-------------------------- +- Modify Imakefile to recognize cygwin or not +- Adapt to load null cursor +- Add Windows resources (for cursor, but alos has version info) +- Initializae some variables (unused in -fromwin) to keep compiler happy +- Add casts in printfs to remover warnings +- Don't grab clipboard from X if its what we added to Windows +- Force redraw when big window goes away (may not be strictly needed) +- Intersept windows screenblank and forward to X if connected +- Intersept ERASEBKGND and prevent Windows drawing black in big window +- Don't register for property notify (on -to) in fromWin case +- Bump version to 1.30 per Chaiken +Add files: +resource.h +nocursor.cur (copy from win2vnc) +x2xwin.rc (resource description) + +02 Oct 03 released Alpha3 + +- After MAX_UNREASONABLES "unreasonable" coordinates they become reasonable + (helps recovery from errors that would otherwise loose the mouse) + +- Add 1 second tick to cause X events to be polled, sets max bound + when doing a paste to the X side [bug from pkumar] + +- Check number of buttons on -to side and don't send mousewheel events + if buttons 4/5 are not ok. [bug from chaiken] + +- Check for not becomming foreground, and try to recover, become aggresive + if events are turning up on the wrong window [Bug from Thomas] + +- Fix cursor warp (west) so it goes one left of return coordinate + [Bug from Thomas] + +- Extra message printing if -DDEBUGCHATTY [mdh] + +- Version of -capslockhack code in Windows KeyEvent processing + [Bug from Thomas and mdh] + +- Add magic key sequences for -fromwin: + RightAlt-Home to force cursor back to Windows + RightAlt-End to exit x2x + +- Known issue: Both left and right shift keys on Windows cause left shift on X. + +- make -fromwin imply -capslockhack, and add -nocapslockhack option + +- Fix to allow -east work before -fromwin on command line [Bug from Thomas] + +- Add comment in usage with Thomas' tip on making a shortcut to launch x2x + +- Fix Imakefile LOCAL_LIBRARIES to only include windows libs on cygwin +- Add comments on -D to Imakefile + +Changed files: +Imakefile +keymap.c +x2x.c +x2xwin.rc (bump version) + +Added files: +winmsg.c - This is a quick hack to turn Windows message numbers into + a string so I can print them. Only when -DDEBUGCHATTY + + +27 Oct 2003 Beta 1 +------------------ + +- Added code from Thomas Chadwick to save Windows focus when going to X + and restore on the way back (good for click-to-focus) + +- Added code from Thomas Chadwick to send a fake mouse click to Windows + when x2x is havig problems getting the focus (good for click-to-focus) + +- Support the -buttonblock flag in the -fromwin code + +- Add description of -fromwin to the manpage + +- Make man file x2x.man so that the makefile will build x2x.1.html + and the install will install x2x.1 + +- Add to BUGS section of the man page that Ctrl-Alt-Del on the Windows +side will leave the Ctrl and Alt keys stuck down on the X server and that +pressing and releasing Ctrl and Alt should fix this. + +- Default to no -DDEBUG + +- Bump version to Beta + +- Add -clipcheck option and relax clipboard copy checking to windows +if it is not given (allows other than plain XA_STRING copies, eg emacs +keeps giving me a COMPOUND_TEXT type) + +Changed files: +x2x.c +x2x.man +x2xwin.rc +Imakefile + + diff --git a/Imakefile b/Imakefile new file mode 100644 index 0000000..6730ba8 --- /dev/null +++ b/Imakefile @@ -0,0 +1,20 @@ +XCOMM $XConsortium: Imakefile,v 1.5 91/07/17 16:07:10 gildea Exp $ + DEPLIBS = $(DEPXTESTLIB) $(DEPEXTENSIONLIB) $(DEPXLIB) + +LOCAL_LIBRARIES = $(XTESTLIB) $(EXTENSIONLIB) $(XLIB) + SRCS = lawyerese.c x2x.c format.c usb.c + OBJS = lawyerese.o x2x.o format.o usb.o + PROTO_DEFINES = + + CC = gcc + +XCOMM Add +XCOMM -DDEBUG for debugging printfs +XCOMM -DDEBUGCHATTY for printfs of every Windows message +XCOMM -DDEBUGMOUSE for printfs of every Windows mouse coordinates + + CDEBUGFLAGS = -O + + LOCAL_LIBRARIES = -lX11 -lusb + +ComplexProgramTarget(x2usb) diff --git a/format.c b/format.c new file mode 100644 index 0000000..edcbf3a --- /dev/null +++ b/format.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 1997 + * Digital Equipment Corporation. All rights reserved. + * + * By downloading, installing, using, modifying or distributing this + * software, you agree to the following: + * + * 1. CONDITIONS. Subject to the following conditions, you may download, + * install, use, modify and distribute this software in source and binary + * forms: + * + * a) Any source code, binary code and associated documentation + * (including the online manual) used, modified or distributed must + * reproduce and retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * b) No right is granted to use any trade name, trademark or logo of + * Digital Equipment Corporation. Neither the "Digital Equipment + * Corporation" name nor any trademark or logo of Digital Equipment + * Corporation may be used to endorse or promote products derived from + * this software without the prior written permission of Digital + * Equipment Corporation. + * + * 2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#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 for assistance with the +// international keyboard mapping stuff. + +// KeyMap.cpp + +#ifdef WIN_2_X +#include +#include +#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 +#include + +// A single key press on the client may result in more than one +// going to the server. + +#define MaxKeysPerKey 4 +#define VoidKeyCode XK_VoidSymbol + +// keycodes contains the keysyms terminated by an VoidKeyCode. +// The releaseModifiers is a set of ORed flags indicating whether +// particular modifier-up messages should be sent before the keys +// and modifier-down after. + +#define KEYMAP_LCONTROL 0x0001 +#define KEYMAP_RCONTROL 0x0002 +#define KEYMAP_LALT 0x0004 +#define KEYMAP_RALT 0x0008 + typedef struct +{ + KeySym keycodes[MaxKeysPerKey]; + int releaseModifiers; + } KeyActionSpec; + KeyActionSpec PCtoX (unsigned int virtkey, DWORD keyData); + diff --git a/lawyerese.c b/lawyerese.c new file mode 100644 index 0000000..57cdca5 --- /dev/null +++ b/lawyerese.c @@ -0,0 +1,74 @@ +char *lawyerese = +#ifdef WIN_2_X +" Cygwin version with -fromwin to allow source to be a Windows\n" +" machine that is not running a X server.\n" +" Adapted by Mark Hayter 2003 using win2vnc ClientConnect.cpp code\n" +"\n" +"The x2x code is coverd by the following:\n\n" +#endif +"Copyright (c) 1997\n\ +Digital Equipment Corporation. All rights reserved.\n\ +\n\ +By downloading, installing, using, modifying or distributing this\n\ +software, you agree to the following:\n\ +\n\ +1. CONDITIONS. Subject to the following conditions, you may download,\n\ +install, use, modify and distribute this software in source and binary\n\ +forms:\n\ +\n\ +a) Any source code, binary code and associated documentation\n\ +(including the online manual) used, modified or distributed must\n\ +reproduce and retain the above copyright notice, this list of\n\ +conditions and the following disclaimer.\n\ +\n\ +b) No right is granted to use any trade name, trademark or logo of\n\ +Digital Equipment Corporation. Neither the \"Digital Equipment\n\ +Corporation\" name nor any trademark or logo of Digital Equipment\n\ +Corporation may be used to endorse or promote products derived from\n\ +this software without the prior written permission of Digital\n\ +Equipment Corporation.\n\ +\n\ +2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL \"AS IS\" AND ANY\n\ +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n\ +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n\ +PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY\n\ +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n\ +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n\ +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n\ +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\n\ +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n\ +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n\ +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\ +" +#ifdef WIN_2_X +"\n" +"The win2vnc code was itself adapted from vncviewer for windows\n" +"\n" +" win2vnc, adapted from vncviewer by Fredrik Hubinette 2001\n" +"\n" +" Original copyright follows:\n" +"\n" +" Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.\n" +"\n" +" This file is part of the VNC system.\n" +"\n" +" The VNC system is free software; you can redistribute it and/or modify\n" +" it under the terms of the GNU General Public License as published by\n" +" the Free Software Foundation; either version 2 of the License, or\n" +" (at your option) any later version.\n" +"\n" +" This program is distributed in the hope that it will be useful,\n" +" but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +" GNU General Public License for more details.\n" +"\n" +" You should have received a copy of the GNU General Public License\n" +" along with this program; if not, write to the Free Software\n" +" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,\n" +" USA.\n" +"\n" +" If the source code for the VNC system is not available from the place \n" +" whence you received this file, check http://www.uk.research.att.com/vnc or contact\n" +" the authors on vnc@uk.research.att.com for information on obtaining it.\n" +#endif +; diff --git a/nocursor.cur b/nocursor.cur new file mode 100644 index 0000000..6bb01a5 Binary files /dev/null and b/nocursor.cur differ diff --git a/resource.h b/resource.h new file mode 100644 index 0000000..996a83b --- /dev/null +++ b/resource.h @@ -0,0 +1,2 @@ +// Communication between the .rc file and code +#define IDC_NOCURSOR 100 diff --git a/usb.c b/usb.c new file mode 100644 index 0000000..1212486 --- /dev/null +++ b/usb.c @@ -0,0 +1,1282 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#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 + +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 ] | [-fromwin | -from ]> [options...] +.SH DESCRIPTION +x2x allows the keyboard and mouse on one ("from") X display to be used to +control another ("to") X display. Since x2x uses the XTEST extension, +the "to" X display must support XTEST. + +If x2x is built under Cygwin (on Windows XP or Windows 2000) then the +-fromwin option may be specified to allow the "from" display to be the +Windows desktop. (The Cygwin build also supports use of an X display +for the "from" screen). Use of -fromwin sets the default behaviour as +if the -big -west -capslockhack options had also been given. + +In the default interface, x2x puts a window on the "from" display. +This window is labeled with the name of the "to" display. Keystrokes +typed into this window go to the window on the "to" display that has +the input focus. Clicking on the x2x window causes the mouse on the +"from" display to control the cursor on the "to" display. Performing +a subsequent multiple button click on the "to" display returns control +to the "from" display. + +If the -fromwin or -east or -west options are specified on the command +line, x2x starts up with a different interface. When the mouse moves +to the (east or west) side of the default screen on the "from" +display, the cursor slides over to the "to" display. When the mouse +returns to to side of the "to" display that it entered, it slides back +onto the "from" display. + +Unless the -nosel option is specified, x2x relays X selections from +one display to the other. (If -fromwin is specified then the X +selection is relayed to and from the Windows clipboard as text strings). + +Here are a few hints for eXcursion users (based on Intel version +2.1.309). First, use the -big option. Second, in the control panel, +under mouse, check the box that enables "Automatically Capture Text on +Button Up." X selections will then automatically move into the +Windows clipboard. As is the case with all X applications running on +2.1.309 (including x2x), you will need to do an extra mouse click +after performing the X selection for this operation to work. x2x is +known to work poorly with eXcursion running on Windows 95, probably +due to the Windows 95 task scheduler. x2x does work well with eXcursion +running on Windows NT. + +The hints for eXcursion are also valid for Exceed, with the exception +that X selections work better, as long as you are using x2x version +1.25 or later. + +.SH OPTIONS +Either the -to option or the -from option (or both) must be specified. +.TP +.B \-to \fIdisplay\fP +.IP +Indicates the ("to") display that is remotely controlled by the "from" display. +Default is equivalent to the default display. +.TP +.B \-from \fIdisplay\fP +.IP +Indicates the ("from") display that remotely controls the "to" display. +Default is equivalent to the default display. +.TP +.B \-fromwin +.IP +Available when x2x is built in the Cygwin environment. This option +indicates the ("from") display should be the Windows desktop. In this +case the "to" display must be specified with the \-to option. Setting +this option forces \-big and sets the default to \-west \-capslockhack + +The -fromwin option works best when Windows is configured for +focus-follows-mouse also known as X Mouse. This can be set using +TweakUI for Windows XP (on the Mouse/X-Mouse panel) or the XMouse2000 +program for Windows 2000. If Windows is set for its default behaviour +x2x will attempt to get the keyboard and mouse focus but may not +succeed. (The Windows XP TweakUI has a General/Focus option that can be +unchecked to allow applications to steal the focus.) If it fails the +first try, x2x tries quite hard to get the focus! + +If the "to" display supports mouse buttons 4 and 5 then mouse wheel +events on the Windows side are translated to clicks of buttons 4 and 5 +on the X display. This matches with XFree86 servers using +Option "ZAxisMapping" "4 5". + +A link may be created on the Windows desktop to conveniently launch +x2x. Assuming cygwin is installed to C:\\cygwin and x2x.exe is in +/usr/X11R6/bin then the link properties should be set to: + +Target: +.br +C:\\cygwin\\usr\\X11R6\\bin\\run.exe\ /usr/X11R6/bin/x2x\ \-fromwin\ \-to\ somewhere:0.0\ \-east + +Start In: C:\\cygwin\\usr\\X11R6\\bin + +The "Start In" option is important to allow DLLs to be loaded and +C:\\cygwin\\bin must be on the Windows PATH to allow other DLLs to be +loaded. (If either of these are incorrect, launching the application +tends to silently fail.) + +There are two magic key combinations activated by -fromwin: + +RightAlt-Home: Forces the focus back to Windows without needing the +mouse to be moved. Useful when some popup window on the Windows side +grabs the mouse! + +RightAlt-End: Exit x2x +.TP +.B \-east +.IP +Slide off the east side of the "to" display onto the "from" display. +.TP +.B \-west +.IP +Slide off the west side of the "to" display onto the "from" display. +.TP +.B \-font \fIfontname\fP +.IP +The font used in the x2x window. (Overridden by -east or -west.) +.TP +.B \-geometry \fIspecification\fP +.IP +The X geometry specification for the x2x window. +(Overridden by -east or -west.) +.TP +.B \-wait +.IP +Tells x2x to poll the "to" and "from" displays at startup until they +are ready. Useful for login scripts. +.TP +.B \-big +.IP +Workaround for a bug in the cursor grab implementations of at least one +X server. Put a big window over the "to" display in order to force the +X server to track the cursor. (This option is forced by the -fromwin option). +.TP +.B \-buttonblock +.IP +If this option is enabled with -east or -west, the cursor will not +slide back onto the "from" display when one or more mouse buttons +are pressed. +.TP +.B \-nomouse +.IP +Don't capture the mouse. +(Overridden by -east or -west.) +.TP +.B \-nopointermap +.IP +Since x2x uses XTEST, which sends input at a lower level than the +pointer button mapping, x2x needs to understand the "to" display's +button mapping and do appropriate conversion. Use this option +to turn off the pointer button conversion. +.TP +.B \-nosel +.IP +Don't relay the X selection between displays. +.TP +.B \-noautoup +.IP +Normally, the autoup feature in x2x automatically lifts up all keys and +mouse buttons when it removes the cursor from the "from" display. +.B +Note: the autoup feature changes the state of lock functions like +.B +Caps Lock. The state of the lock function may not correspond to +.B +the state of the keyboard LEDs! +To disable this feature, use the \-noautoup command line option. +.TP +.B \-resurface +.IP +Ugly hack to work-around window manager ugliness. The -east and -west +modes actually put a small window on the side of the "from" display. +This option causes this window to resurface itself if another window +ever obscures it. This option can cause really nasty behavior if another +application tries to do the same thing. Useful for login scripts. +.TP +.B \-capslockhack +.IP +Ugly hack to work-around the situation in which the "to" Xserver doesn't +seem to honor the state of the CapsLock on the "from" Xserver. This is +the default when the -fromwin option is given (although the hack used +is slightly less ugly). +.TP +.B \-nocapslockhack +.IP +Disable the -capslockhack behaviour. Used to change the default +behaviour after the -fromwin option is specified. +.TP +.B \-clipcheck +.IP +Check that clipboard entries are regular strings (XA_STRING) before +forwarding to Windows. Enabling this is safer but may prevent copying +with certain setups (eg from emacs under KDE/XFree). +.TP +.B \-shadow \fIdisplay\fP +.IP +Also sends mouse movements and keystrokes to this display. Useful +for demos. Amaze your friends: specify multiple shadows. +.TP +.B \-sticky \fIsticky-key\fP +.IP +This option is primarily for "lock" keys like Caps_Lock. If a lock +key only seems to work on every other press, try this option. The +sticky option prevents autoup for the specified key. Look in +/usr/include/X11/keysymdef.h for a list of valid names of keys +(remove the leading XK_). +.TP +.B \-copyright +.IP +Prints the full copyright for the x2x code. +.SH AUTHOR +David Chaiken +.br +(chaiken@pa.dec.com) +.br +Mark Hayter (-fromwin code, thanks to the WinVNC sources) +.SH BUGS +This software is experimental! Heaven help you if your network +connection should go down. Caveat hacker. TANSTAAFL. + +When using the -fromwin option if the Ctrl-Alt-Del keysequence is used +while the mouse is forwarded to the X display then the Ctrl and Alt +key press events are reported to x2x and forwarded but no other key +events are generated. Thus if the Ctrl-Alt-Del sequence is used to +manually lock the Windows display when the display is unlocked the +mouse will still be forwarded to the X screen and the X server will +believe Ctrl and Alt are still pressed. Pressing and releasing Ctrl +and Alt should restore correct operation, as should returning the +mouse to the Windows display (or using the RightAlt-Home magic key +sequence). + +.SH LAWYERESE +Copyright (c) 1997 +Digital Equipment Corporation. All rights reserved. + +By downloading, installing, using, modifying or distributing this +software, you agree to the following: + +1. CONDITIONS. Subject to the following conditions, you may download, +install, use, modify and distribute this software in source and binary forms: + +a) Any source code, binary code and associated documentation +(including the online manual) used, modified or distributed must +reproduce and retain the above copyright notice, this list of +conditions and the following disclaimer. + +b) No right is granted to use any trade name, trademark or logo of +Digital Equipment Corporation. Neither the "Digital Equipment +Corporation" name nor any trademark or logo of Digital Equipment +Corporation may be used to endorse or promote products derived from +this software without the prior written permission of Digital +Equipment Corporation. + +2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Windows 95 and Windows NT are trademarks of Microsoft Corporation. +.br +Exceed is a trademark of Hummingbird Communications Ltd. diff --git a/x2x.c b/x2x.c new file mode 100644 index 0000000..2dae613 --- /dev/null +++ b/x2x.c @@ -0,0 +1,1440 @@ +/* + * x2x: Uses the XTEST extension to forward keystrokes from a window on + * one display to another display. Useful for desks + * with multiple keyboards. + * + * Copyright (c) 1997 + * Digital Equipment Corporation. All rights reserved. + * + * By downloading, installing, using, modifying or distributing this + * software, you agree to the following: + * + * 1. CONDITIONS. Subject to the following conditions, you may download, + * install, use, modify and distribute this software in source and binary + * forms: + * + * a) Any source code, binary code and associated documentation + * (including the online manual) used, modified or distributed must + * reproduce and retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * b) No right is granted to use any trade name, trademark or logo of + * Digital Equipment Corporation. Neither the "Digital Equipment + * Corporation" name nor any trademark or logo of Digital Equipment + * Corporation may be used to endorse or promote products derived from + * this software without the prior written permission of Digital + * Equipment Corporation. + * + * 2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Cygwin version with -fromwin to allow source to be a Windows + * machine that is not running a X server. + * Adapted by Mark Hayter 2003 using win2vnc ClientConnect.cpp code + * + * Original win2vnc copyright follows: + */ +// win2vnc, adapted from vncviewer by Fredrik Hubinette 2001 +// +// Original copyright follows: +// +// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. +// +// This file is part of the VNC system. +// +// The VNC system is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +// USA. +// +// If the source code for the VNC system is not available from the place +// whence you received this file, check http://www.uk.research.att.com/vnc or contact +// the authors on vnc@uk.research.att.com for information on obtaining it. + + + +#include +#include +#include +#include +#include +#include +#include +#include /* for selection */ +#include +#include +#include +#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 | -from ] options...\n"); + printf(" -copyright\n"); + printf(" -font \n"); + printf(" -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 \n"); + printf(" -sticky \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 */ -- cgit v1.2.3