├── bootstrap.sh ├── nocursor.cur ├── resource.h ├── ChangeLog ├── INSTALL ├── .gitignore ├── AUTHORS ├── docs ├── X2xUsage.txt ├── HostBasedAuthentication.txt ├── MIT-MAGIC-COOKIE-1.txt └── SshTunneling.txt ├── Makefile.am ├── configure.ac ├── x2xwin.rc ├── COPYING.win32 ├── COPYING ├── README.md ├── keymap.h ├── ChangeLog.old ├── winmsg.c ├── keymap.c ├── x2x.1 └── x2x.c /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | autoreconf -isv 4 | -------------------------------------------------------------------------------- /nocursor.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dottedmag/x2x/HEAD/nocursor.cur -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- 1 | // Communication between the .rc file and code 2 | #define IDC_NOCURSOR 100 3 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2008-03-18 2 | 3 | - autotools-based build instead of Imake-based 4 | - lawyerese.c is now generated from COPYING.* 5 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Just build/install x2x as any other autotools-based program. 2 | See README.md for details installing on Fedora and Ubuntu. 3 | 4 | Configuration options: 5 | 6 | --with-win32 - enables win32 support 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | .deps/ 3 | /INSTALL 4 | /aclocal.m4 5 | /autom4te.cache/ 6 | /compile 7 | /config.guess 8 | /config.h 9 | /config.h.in 10 | /config.log 11 | /config.status 12 | /config.sub 13 | /configure 14 | /depcomp 15 | /install-sh 16 | /lawyerese.c 17 | /missing 18 | /stamp-h1 19 | /x2x 20 | Makefile 21 | Makefile.in 22 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | * David Chaiken 2 | Original version author 3 | * Charles Briscoe-Smith 4 | -north, -south options. Various patches. 5 | * Mark Hayter 6 | Cygwin version, -fromwin to allow using Windows as source display. 7 | * Snow 8 | Windows version patches 9 | * Mikhail Gusarov 10 | Maintainer 11 | -------------------------------------------------------------------------------- /docs/X2xUsage.txt: -------------------------------------------------------------------------------- 1 | x2x links two X displays together so you can use single mouse and 2 | keyboard to control them. Your keyboard and mouse works as 3 | usual on the display they attached to, until you switch display (by clicking x2x window, or moving mouse to the edge of screen, depending of the options passed to x2x), and then all your input goes to the second display. X selection data also 4 | propagates as expected. 5 | 6 | ''Right now there are glitches with transferring non-ASCII X selection data: 7 | GTK and QT applications expose strange behavior, while Tk and Xaw 8 | applications work properly (see the ticket #7).'' 9 | 10 | Surely, accessing remote displays is a subject of 11 | authentication. x2x uses regular X11 authorization methods, so this 12 | should not be so much trouble, but we are providing quick howto for 13 | the uninitiated :) 14 | 15 | X11 use HostBasedAuthentication and [wiki:MIT-MAGIC-COOKIE-1] protocols. Also SshTunneling may be used for the access to the remote displays. 16 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2008 Mikhail Gusarov 3 | # 4 | # BSD-3 5 | # 6 | 7 | bin_PROGRAMS = x2x 8 | 9 | x2x_SOURCES = x2x.c 10 | nodist_x2x_SOURCES = lawyerese.c 11 | 12 | dist_man1_MANS = x2x.1 13 | 14 | # -- win32 support -- 15 | 16 | if WIN32 17 | 18 | AM_CFLAGS = -DWIN_2_X 19 | LIBS += -luser32 -lgdi32 # Ugly hack 20 | x2x_SOURCES += keymap.c winmsg.c x2xwin.rc 21 | 22 | .o:.rc 23 | windres $^ -o $@ 24 | 25 | x2xwin.o: resource.h nocursor.cur 26 | 27 | endif 28 | 29 | # -- creating lawyerese.c -- 30 | 31 | if WIN32 32 | COPYING_FILES = COPYING.win32 33 | else 34 | COPYING_FILES = 35 | endif 36 | COPYING_FILES += COPYING 37 | 38 | lawyerese.c: $(COPYING_FILES) 39 | echo 'char *lawyerese =' > $@.tmp && \ 40 | sed -e 's|.*|"\0\\n"|g' $^ >> $@.tmp && \ 41 | echo ";" >> $@.tmp && \ 42 | mv $@.tmp $@ || rm -f $@.tmp 43 | 44 | CLEANFILES = lawyerese.c 45 | 46 | # -- Various -- 47 | 48 | dist_doc_DATA = AUTHORS ChangeLog ChangeLog.old COPYING COPYING.win32 \ 49 | README.md docs/HostBasedAuthentication.txt \ 50 | docs/MIT-MAGIC-COOKIE-1.txt docs/SshTunneling.txt \ 51 | docs/X2xUsage.txt 52 | 53 | 54 | EXTRA_DIST = keymap.h nocursor.cur resource.h 55 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl 2 | dnl Copyright (c) 2008 Mikhail Gusarov 3 | dnl 4 | dnl BSD-3 5 | dnl 6 | 7 | AC_PREREQ([2.69]) 8 | AC_INIT([x2x],[1.30-rc1],[http://x2x.dottedmag.net/newticket],[x2x],[http://x2x.dottedmag.net]) 9 | AM_INIT_AUTOMAKE([-Wall foreign dist-bzip2]) 10 | AC_CONFIG_SRCDIR([x2x.c]) 11 | 12 | # config.h is unused but generating it avoids compiler invocation clutter. 13 | AC_CONFIG_HEADERS([config.h]) 14 | 15 | AC_PROG_CC 16 | AC_PROG_INSTALL 17 | 18 | AX_CFLAGS_WARN_ALL 19 | 20 | ## This PKG_CHECK_MODULES can be replaced by the following three 21 | ## AC_SEARCH_LIBSs and the non-Cygwin setting of AM_LDFLAGS and 22 | ## AM_CFLAGS in Makefile.am removed. 23 | PKG_CHECK_MODULES(X11, xext xtst x11) 24 | # AC_SEARCH_LIBS([XOpenDisplay], [X11 x11]) 25 | # AC_SEARCH_LIBS([XextFindDisplay], [Xext xext]) 26 | # AC_SEARCH_LIBS([XTestFakeKeyEvent], [Xtst xtst]) 27 | 28 | CFLAGS="${X11_CFLAGS} ${CFLAGS}" 29 | LIBS="${X11_LIBS} ${LIBS}" 30 | 31 | AC_ARG_ENABLE([win32], 32 | AS_HELP_STRING( 33 | [--enable-win32], 34 | [enable Win32 support (-fromwin option). Disabled by default])) 35 | 36 | AM_CONDITIONAL(WIN32, [test x$enable_win32 = xyes]) 37 | 38 | AC_CONFIG_FILES([Makefile]) 39 | AC_OUTPUT 40 | -------------------------------------------------------------------------------- /x2xwin.rc: -------------------------------------------------------------------------------- 1 | // Windows resources for x2x -fromwin 2 | #include "resource.h" 3 | #include 4 | // Version is always resource 1 5 | VS_VERSION_INFO VERSIONINFO 6 | // Based on cygwin 1.27-2. mdh-Alpha1 is 100 7 | // dc has allocated 1.30 for the initial release 8 | // 1.30.0.2=alpha.2 9 | // 1.30.0.3=alpha.3 10 | // 1.30.0.4=beta 1 11 | FILEVERSION 1,30,0,4 12 | PRODUCTVERSION 1,30,0,4 13 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 14 | FILEFLAGS 0x0L 15 | FILEOS VOS_NT_WINDOWS32 16 | FILETYPE VFT_APP 17 | FILESUBTYPE 0x0L 18 | BEGIN 19 | BLOCK "StringFileInfo" 20 | BEGIN 21 | // US-English 22 | BLOCK "040904b0" 23 | BEGIN 24 | VALUE "Comments", "Windows version by Mark Hayter, from x2x and win2vnc\0" 25 | VALUE "CompanyName", "(See x2x -copyright for full details)\0" 26 | VALUE "FileDescription", "x2x -fromwin\0" 27 | VALUE "FileVersion", "1.30 Beta\0" 28 | VALUE "InternalName", "x2x\0" 29 | VALUE "LegalCopyright", "(see x2x -copyright for full details)\0" 30 | VALUE "LegalTrademarks", "\0" 31 | VALUE "OriginalFilename", "x2x.exe\0" 32 | VALUE "PrivateBuild", "\0" 33 | VALUE "ProductName", "x2x\0" 34 | VALUE "ProductVersion", "1.30 Beta\0" 35 | VALUE "SpecialBuild", "\0" 36 | END 37 | END 38 | END 39 | IDC_NOCURSOR CURSOR DISCARDABLE "nocursor.cur" 40 | -------------------------------------------------------------------------------- /COPYING.win32: -------------------------------------------------------------------------------- 1 | Cygwin version with -fromwin to allow source to be a Windows machine that is not 2 | running a X server. 3 | 4 | Adapted by Mark Hayter 2003 using win2vnc ClientConnect.cpp code. 5 | 6 | The win2vnc code was itself adapted from vncviewer for windows win2vnc, adapted 7 | from vncviewer by Fredrik Hubinette 2001. 8 | 9 | Original vncviewer copyright follows: 10 | 11 | Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 12 | 13 | This file is part of the VNC system. 14 | 15 | The VNC system is free software; you can redistribute it and/or modify it under 16 | the terms of the GNU General Public License as published by he Free Software 17 | Foundation; either version 2 of the License, or (at your option) any later 18 | version. 19 | 20 | This program is distributed in the hope that it will be useful, but WITHOUT ANY 21 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 22 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 23 | 24 | You should have received a copy of the GNU General Public License along with 25 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple 26 | Place - Suite 330, Boston, MA 02111-1307, USA. 27 | 28 | If the source code for the VNC system is not available from the place whence you 29 | received this file, check http://www.uk.research.att.com/vnc or contact the 30 | authors on vnc@uk.research.att.com for information on obtaining it. 31 | 32 | Original x2x copyright follows: 33 | -------------------------------------------------------------------------------- /docs/HostBasedAuthentication.txt: -------------------------------------------------------------------------------- 1 | X server may be configured to allow """any""" connection from 2 | specified host. `xhost` is the utility allowing to control what hosts 3 | are allowed to connect. 4 | 5 | Basic synopsis is 6 | 7 | ||`xhost -`||enables host authentication protocol: only authenticated hosts may connect.|| 8 | ||`xhost +`||disables any security protocols: any host may connect|| 9 | ||`xhost +host`||adds specified host to the allowed hosts list|| 10 | ||`xhost -host`||removes host from the allowed hosts list|| 11 | 12 | `host` may contain `inet:hostname` to allow clients from `hostname` to connect, `local` to allow connection from local clients and other, less used now, forms. 13 | 14 | For the full information about xhost read `xhost(1x)` manual page and `Xsecurity(7x)` manual pages. 15 | 16 | It is highly insecure to use host-based authentication protocols 17 | in the non-controlled networks, so you 18 | should probably consider using other authentication protocol, such as 19 | [wiki:MIT-MAGIC-COOKIE-1], or even SshTunneling. But in 20 | some cases, such as virtual machines inside one hardware machine, 21 | host-based authentication is ok. 22 | 23 | Example configuration using host-based authentication is the following: 24 | `host1` runs `x2x` and wants to control display on `host2`. 25 | 26 | On the host2: 27 | {{{ 28 | host2% echo $DISPLAY 29 | :0.0 30 | host2% xhost +inet:host1 (or just 'xhost +host1') 31 | host2% 32 | }}} 33 | 34 | On the host1: 35 | {{{ 36 | host1% x2x -to host2:0 37 | }}} 38 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 1997 Digital Equipment Corporation. All rights reserved. 2 | 3 | By downloading, installing, using, modifying or distributing this software, you 4 | agree to the following: 5 | 6 | 1. CONDITIONS. Subject to the following conditions, you may download, install, 7 | use, modify and distribute this software in source and binary forms: 8 | 9 | a) Any source code, binary code and associated documentation (including the 10 | online manual) used, modified or distributed must reproduce and retain the above 11 | copyright notice, this list of conditions and the following disclaimer. 12 | 13 | b) No right is granted to use any trade name, trademark or logo of Digital 14 | Equipment Corporation. Neither the ''Digital Equipment Corporation'' name nor 15 | any trademark or logo of Digital Equipment Corporation may be used to endorse or 16 | promote products derived from this software without the prior written permission 17 | of Digital Equipment Corporation. 18 | 19 | 2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL ''AS IS'' AND ANY EXPRESS 20 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT 22 | SHALL DIGITAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 24 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 28 | OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # x2x 2 | 3 | ## Project status 4 | 5 | Dormant. This project needs a new maintainer. 6 | 7 | x2x has a long history. It was born in the times when life was hard, window 8 | managers were simple and displays were rectangular. Now it needs an overhaul. 9 | 10 | ## Overview 11 | 12 | x2x allows the keyboard, mouse on one X display to be used to control another X 13 | display. It also shares X clipboards between the displays. 14 | 15 | When built/run on Cygwin it may be run on Windows desktop to control X display. 16 | 17 | ## License 18 | 19 | x2x is under MIT/BSD license. 20 | 21 | Windows support includes code under GPLv2+. 22 | 23 | ## Authors 24 | 25 | x2x was initially developed in DEC by David Chaiken. 26 | Current maintainer is Mikhail Gusarov. 27 | 28 | ## Building on Various Systems 29 | 30 | ### Building on Arch 31 | 32 | 1. `git clone https://github.com/dottedmag/x2x && cd x2x` 33 | 2. `./bootstrap.sh` 34 | 3. `sudo pacman -S libxext libxtst` 35 | 4. `./configure` 36 | 5. `make && sudo make install` 37 | 38 | If you want the simple solution, there is also a package in the [AUR](https://aur.archlinux.org/packages/x2x-git) for x2x. 39 | 40 | ### Building on Fedora 41 | 42 | 1. `git clone https://github.com/dottedmag/x2x && cd x2x` 43 | 2. `./bootstrap.sh` 44 | 3. `sudo dnf -y install libXext-devel libXtst-devel` 45 | 4. `./configure` 46 | 5. `make && sudo make install` 47 | 48 | ### Building on Debian or Debian-Derivative like Ubuntu 49 | 50 | 1. `git clone https://github.com/dottedmag/x2x && cd x2x` 51 | 2. `git checkout debian` 52 | 3. `dpkg-checkbuilddeps` (and `sudo apt install` anything missing) 53 | 4. `env DEB_RULES_REQUIRES_ROOT=no debian/rules binary` 54 | 5. `sudo dpkg --install ../x2x_VERSION.deb` 55 | -------------------------------------------------------------------------------- /docs/MIT-MAGIC-COOKIE-1.txt: -------------------------------------------------------------------------------- 1 | [wiki:MIT-MAGIC-COOKIE-1] is much more secure authentication protocol than HostBasedAuthentication: it uses private tokens to authenicate clients trying to access X server: token is bound to the X server and vaild only during one session. 2 | 3 | Authentication tokens are generated at server startup and stored at 4 | `.Xauthority` file in user home directory. Any X application trying to 5 | access the display reads authentication token corresponding to 6 | the display from this file (or from the file variable XAUTHORITY 7 | points to if this variable exists) and passes this token to the 8 | server. 9 | 10 | `xauth` program is designed to manipulate authentication tokens. Two 11 | most interesting for us commands of xauth are 12 | 13 | ||`xauth nextract`||extracts the authentication token from `.Xauthority` file.|| 14 | ||`xauth nmerge`||adds the authentication token, extracted by `nextract`, to the `.Xauthority` file|| 15 | 16 | ('n' here means 'numeric format' as opposed to the 'binary': numeric format contains only printable symbols). 17 | 18 | You also can list installed to the `.Xauthority` authentication tokens by using `xauth nlist`. 19 | 20 | Example configuration is the same as in HostBasedAuthentication: `host1` runs `x2x` and wants to control display on `host2`. 21 | 22 | On the host2: 23 | {{{ 24 | host2% echo $DISPLAY 25 | :0.0 26 | host2% xauth nextract - :0.0 27 | 28 | host2% 29 | }}} 30 | 31 | On the host1: 32 | {{{ 33 | host1% xauth nmerge - 34 | 35 | host1% x2x -to host2:0 36 | }}} 37 | 38 | This authentication method is a bit more complicated than host-based, 39 | but much more secure, and you should prefer it unless you know exactly 40 | what are you doing. 41 | -------------------------------------------------------------------------------- /docs/SshTunneling.txt: -------------------------------------------------------------------------------- 1 | You can use SSH to easily make `x2x` link two displays together. SSH 2 | provides the options to tunnel the X traffic from the host you are 3 | connecting to the host you are connected from. 4 | 5 | SSH propagates authentication token from the local host to the remote 6 | host, and creates tunnel. For example, if you have access token to the 7 | `$DISPLAY` on the local host, it will propagate 8 | authentication token to the remote host, and forward local X connection to the display like `localhost:10` on the remote host. 9 | 10 | SSH server and client have number of options to control the behavior 11 | of the forwarding. The most frequently used options are listed in the 12 | table below: 13 | 14 | ssh server options (`/etc/ssh/sshd_config`) 15 | ||`X11Forwarding`||Specifies whether forwarding is allowed. May be 'yes' or 'no'.|| 16 | ||`X11DisplayOffset`||Specifies first display number to be used. By default it is '10', which means tunnel will be established from the `localhost:10` display. || 17 | ||`X11UseLocalhost`||Specifies whether listening socket will be bound to the localhost only or to the all available network interfaces.|| 18 | 19 | ssh client options (`~/.ssh/config`, `/etc/ssh/ssh_config`) 20 | ||`ForwardX11` (command-line switches -X and -x)||Specifies whether to forward X connection to the remote host. Option -X enables forwarding, -x disables it.|| 21 | 22 | Full list of options is contained in man pages ssh(1), ssh_config(5) 23 | and sshd_config(5). 24 | 25 | Example configuration. host1 runs x2x and wants to control display on host2. 26 | 27 | On the host1: 28 | {{{ 29 | host1% echo $DISPLAY 30 | :0.0 31 | host1% 32 | }}} 33 | 34 | On the host2: 35 | {{{ 36 | host2% ssh host1 37 | Password: 38 | host1% echo $DISPLAY 39 | localhost:10 40 | host1% x2x -from :0 41 | }}} 42 | -------------------------------------------------------------------------------- /keymap.h: -------------------------------------------------------------------------------- 1 | 2 | // This file comes from the vncviewer source 3 | // Converted to C from C++ and used in -fromwin version of x2x 4 | // 2003 By Mark Hayter 5 | 6 | // Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 7 | // 8 | // This file is part of the VNC system. 9 | // 10 | // The VNC system is free software; you can redistribute it and/or modify 11 | // it under the terms of the GNU General Public License as published by 12 | // the Free Software Foundation; either version 2 of the License, or 13 | // (at your option) any later version. 14 | // 15 | // This program is distributed in the hope that it will be useful, 16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | // GNU General Public License for more details. 19 | // 20 | // You should have received a copy of the GNU General Public License 21 | // along with this program; if not, write to the Free Software 22 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 23 | // USA. 24 | // 25 | // If the source code for the VNC system is not available from the place 26 | // whence you received this file, check http://www.uk.research.att.com/vnc or contact 27 | // the authors on vnc@uk.research.att.com for information on obtaining it. 28 | 29 | 30 | // KeyMap.h 31 | // mapping of windows virtual key codes to X keysyms. 32 | 33 | #include 34 | #include 35 | 36 | // A single key press on the client may result in more than one 37 | // going to the server. 38 | 39 | #define MaxKeysPerKey 4 40 | #define VoidKeyCode XK_VoidSymbol 41 | 42 | // keycodes contains the keysyms terminated by an VoidKeyCode. 43 | // The releaseModifiers is a set of ORed flags indicating whether 44 | // particular modifier-up messages should be sent before the keys 45 | // and modifier-down after. 46 | 47 | #define KEYMAP_LCONTROL 0x0001 48 | #define KEYMAP_RCONTROL 0x0002 49 | #define KEYMAP_LALT 0x0004 50 | #define KEYMAP_RALT 0x0008 51 | 52 | typedef struct { 53 | KeySym keycodes[MaxKeysPerKey]; 54 | int releaseModifiers; 55 | } KeyActionSpec; 56 | 57 | KeyActionSpec PCtoX(unsigned int virtkey, DWORD keyData); 58 | 59 | -------------------------------------------------------------------------------- /ChangeLog.old: -------------------------------------------------------------------------------- 1 | RCS 1.1 -nAlpha1 : First release for Puneet and David to play with 2 | Files: 3 | Imakefile 4 | format.c 5 | format.h 6 | keymap.c 7 | keymap.h 8 | lawyerese.c 9 | x2x.1 10 | x2x.c 11 | 12 | 13 | 22 Sept 03 released Alpha2 14 | -------------------------- 15 | - Modify Imakefile to recognize cygwin or not 16 | - Adapt to load null cursor 17 | - Add Windows resources (for cursor, but alos has version info) 18 | - Initializae some variables (unused in -fromwin) to keep compiler happy 19 | - Add casts in printfs to remover warnings 20 | - Don't grab clipboard from X if its what we added to Windows 21 | - Force redraw when big window goes away (may not be strictly needed) 22 | - Intersept windows screenblank and forward to X if connected 23 | - Intersept ERASEBKGND and prevent Windows drawing black in big window 24 | - Don't register for property notify (on -to) in fromWin case 25 | - Bump version to 1.30 per Chaiken 26 | Add files: 27 | resource.h 28 | nocursor.cur (copy from win2vnc) 29 | x2xwin.rc (resource description) 30 | 31 | 02 Oct 03 released Alpha3 32 | 33 | - After MAX_UNREASONABLES "unreasonable" coordinates they become reasonable 34 | (helps recovery from errors that would otherwise loose the mouse) 35 | 36 | - Add 1 second tick to cause X events to be polled, sets max bound 37 | when doing a paste to the X side [bug from pkumar] 38 | 39 | - Check number of buttons on -to side and don't send mousewheel events 40 | if buttons 4/5 are not ok. [bug from chaiken] 41 | 42 | - Check for not becomming foreground, and try to recover, become aggresive 43 | if events are turning up on the wrong window [Bug from Thomas] 44 | 45 | - Fix cursor warp (west) so it goes one left of return coordinate 46 | [Bug from Thomas] 47 | 48 | - Extra message printing if -DDEBUGCHATTY [mdh] 49 | 50 | - Version of -capslockhack code in Windows KeyEvent processing 51 | [Bug from Thomas and mdh] 52 | 53 | - Add magic key sequences for -fromwin: 54 | RightAlt-Home to force cursor back to Windows 55 | RightAlt-End to exit x2x 56 | 57 | - Known issue: Both left and right shift keys on Windows cause left shift on X. 58 | 59 | - make -fromwin imply -capslockhack, and add -nocapslockhack option 60 | 61 | - Fix to allow -east work before -fromwin on command line [Bug from Thomas] 62 | 63 | - Add comment in usage with Thomas' tip on making a shortcut to launch x2x 64 | 65 | - Fix Imakefile LOCAL_LIBRARIES to only include windows libs on cygwin 66 | - Add comments on -D to Imakefile 67 | 68 | Changed files: 69 | Imakefile 70 | keymap.c 71 | x2x.c 72 | x2xwin.rc (bump version) 73 | 74 | Added files: 75 | winmsg.c - This is a quick hack to turn Windows message numbers into 76 | a string so I can print them. Only when -DDEBUGCHATTY 77 | 78 | 79 | 27 Oct 2003 Beta 1 80 | ------------------ 81 | 82 | - Added code from Thomas Chadwick to save Windows focus when going to X 83 | and restore on the way back (good for click-to-focus) 84 | 85 | - Added code from Thomas Chadwick to send a fake mouse click to Windows 86 | when x2x is havig problems getting the focus (good for click-to-focus) 87 | 88 | - Support the -buttonblock flag in the -fromwin code 89 | 90 | - Add description of -fromwin to the manpage 91 | 92 | - Make man file x2x.man so that the makefile will build x2x.1.html 93 | and the install will install x2x.1 94 | 95 | - Add to BUGS section of the man page that Ctrl-Alt-Del on the Windows 96 | side will leave the Ctrl and Alt keys stuck down on the X server and that 97 | pressing and releasing Ctrl and Alt should fix this. 98 | 99 | - Default to no -DDEBUG 100 | 101 | - Bump version to Beta 102 | 103 | - Add -clipcheck option and relax clipboard copy checking to windows 104 | if it is not given (allows other than plain XA_STRING copies, eg emacs 105 | keeps giving me a COMPOUND_TEXT type) 106 | 107 | Changed files: 108 | x2x.c 109 | x2x.man 110 | x2xwin.rc 111 | Imakefile 112 | 113 | 114 | -------------------------------------------------------------------------------- /winmsg.c: -------------------------------------------------------------------------------- 1 | /* Code to print windows messages */ 2 | /* mdh 9/30/03 */ 3 | 4 | #ifdef DEBUGCHATTY 5 | 6 | /* This table generated from cygwin /usr/include/w32api/winuser.h 7 | * with : 8 | * grep WM_ /usr/include/w32api/winuser.h | 9 | * sed 's/#define \([^ ]*\) \(.*\)/{\2,\"\1\"},/' > foo 10 | * then edited! 11 | */ 12 | #define WM_USER 1024 13 | 14 | struct wmsginfo { int num; char *msg }; 15 | 16 | struct wmsginfo msginfo[] = { 17 | {6,"WM_ACTIVATE"}, 18 | {28,"WM_ACTIVATEAPP"}, 19 | /* FIXME/CHECK: Are WM_AFX{FIRST,LAST} valid for WINVER < 0x400? */ 20 | {864,"WM_AFXFIRST"}, 21 | {895,"WM_AFXLAST"}, 22 | {780,"WM_ASKCBFORMATNAME"}, 23 | {75,"WM_CANCELJOURNAL"}, 24 | {31,"WM_CANCELMODE"}, 25 | {533,"WM_CAPTURECHANGED"}, 26 | {781,"WM_CHANGECBCHAIN"}, 27 | {258,"WM_CHAR"}, 28 | {47,"WM_CHARTOITEM"}, 29 | {34,"WM_CHILDACTIVATE"}, 30 | {771,"WM_CLEAR"}, 31 | {16,"WM_CLOSE"}, 32 | {273,"WM_COMMAND"}, 33 | {68 /* obsolete */,"WM_COMMNOTIFY"}, 34 | {65,"WM_COMPACTING"}, 35 | {57,"WM_COMPAREITEM"}, 36 | {123,"WM_CONTEXTMENU"}, 37 | {769,"WM_COPY"}, 38 | {74,"WM_COPYDATA"}, 39 | {1,"WM_CREATE"}, 40 | {309,"WM_CTLCOLORBTN"}, 41 | {310,"WM_CTLCOLORDLG"}, 42 | {307,"WM_CTLCOLOREDIT"}, 43 | {308,"WM_CTLCOLORLISTBOX"}, 44 | {306,"WM_CTLCOLORMSGBOX"}, 45 | {311,"WM_CTLCOLORSCROLLBAR"}, 46 | {312,"WM_CTLCOLORSTATIC"}, 47 | {768,"WM_CUT"}, 48 | {259,"WM_DEADCHAR"}, 49 | {45,"WM_DELETEITEM"}, 50 | {2,"WM_DESTROY"}, 51 | {775,"WM_DESTROYCLIPBOARD"}, 52 | {537,"WM_DEVICECHANGE"}, 53 | {27,"WM_DEVMODECHANGE"}, 54 | {126,"WM_DISPLAYCHANGE"}, 55 | {776,"WM_DRAWCLIPBOARD"}, 56 | {43,"WM_DRAWITEM"}, 57 | {563,"WM_DROPFILES"}, 58 | {10,"WM_ENABLE"}, 59 | {22,"WM_ENDSESSION"}, 60 | {289,"WM_ENTERIDLE"}, 61 | {529,"WM_ENTERMENULOOP"}, 62 | {561,"WM_ENTERSIZEMOVE"}, 63 | {20,"WM_ERASEBKGND"}, 64 | {530,"WM_EXITMENULOOP"}, 65 | {562,"WM_EXITSIZEMOVE"}, 66 | {29,"WM_FONTCHANGE"}, 67 | {135,"WM_GETDLGCODE"}, 68 | {49,"WM_GETFONT"}, 69 | {51,"WM_GETHOTKEY"}, 70 | {127,"WM_GETICON"}, 71 | {36,"WM_GETMINMAXINFO"}, 72 | {13,"WM_GETTEXT"}, 73 | {14,"WM_GETTEXTLENGTH"}, 74 | /* FIXME/CHECK: Are WM_HANDHEL{FIRST,LAST} valid for WINVER < 0x400? */ 75 | {856,"WM_HANDHELDFIRST"}, 76 | {863,"WM_HANDHELDLAST"}, 77 | {83,"WM_HELP"}, 78 | {786,"WM_HOTKEY"}, 79 | {276,"WM_HSCROLL"}, 80 | {782,"WM_HSCROLLCLIPBOARD"}, 81 | {39,"WM_ICONERASEBKGND"}, 82 | {272,"WM_INITDIALOG"}, 83 | {278,"WM_INITMENU"}, 84 | {279,"WM_INITMENUPOPUP"}, 85 | {81,"WM_INPUTLANGCHANGE"}, 86 | {80,"WM_INPUTLANGCHANGEREQUEST"}, 87 | {256,"WM_KEYDOWN"}, 88 | {257,"WM_KEYUP"}, 89 | {8,"WM_KILLFOCUS"}, 90 | {546,"WM_MDIACTIVATE"}, 91 | {551,"WM_MDICASCADE"}, 92 | {544,"WM_MDICREATE"}, 93 | {545,"WM_MDIDESTROY"}, 94 | {553,"WM_MDIGETACTIVE"}, 95 | {552,"WM_MDIICONARRANGE"}, 96 | {549,"WM_MDIMAXIMIZE"}, 97 | {548,"WM_MDINEXT"}, 98 | {564,"WM_MDIREFRESHMENU"}, 99 | {547,"WM_MDIRESTORE"}, 100 | {560,"WM_MDISETMENU"}, 101 | {550,"WM_MDITILE"}, 102 | {44,"WM_MEASUREITEM"}, 103 | {290,"WM_MENURBUTTONUP"}, 104 | {288,"WM_MENUCHAR"}, 105 | {287,"WM_MENUSELECT"}, 106 | {531,"WM_NEXTMENU"}, 107 | {3,"WM_MOVE"}, 108 | {534,"WM_MOVING"}, 109 | {134,"WM_NCACTIVATE"}, 110 | {131,"WM_NCCALCSIZE"}, 111 | {129,"WM_NCCREATE"}, 112 | {130,"WM_NCDESTROY"}, 113 | {132,"WM_NCHITTEST"}, 114 | {163,"WM_NCLBUTTONDBLCLK"}, 115 | {161,"WM_NCLBUTTONDOWN"}, 116 | {162,"WM_NCLBUTTONUP"}, 117 | {169,"WM_NCMBUTTONDBLCLK"}, 118 | {167,"WM_NCMBUTTONDOWN"}, 119 | {168,"WM_NCMBUTTONUP"}, 120 | {160,"WM_NCMOUSEMOVE"}, 121 | {133,"WM_NCPAINT"}, 122 | {166,"WM_NCRBUTTONDBLCLK"}, 123 | {164,"WM_NCRBUTTONDOWN"}, 124 | {165,"WM_NCRBUTTONUP"}, 125 | {40,"WM_NEXTDLGCTL"}, 126 | {531,"WM_NEXTMENU"}, 127 | {78,"WM_NOTIFY"}, 128 | {85,"WM_NOTIFYFORMAT"}, 129 | {0,"WM_NULL"}, 130 | {15,"WM_PAINT"}, 131 | {777,"WM_PAINTCLIPBOARD"}, 132 | {38,"WM_PAINTICON"}, 133 | {785,"WM_PALETTECHANGED"}, 134 | {784,"WM_PALETTEISCHANGING"}, 135 | {528,"WM_PARENTNOTIFY"}, 136 | {770,"WM_PASTE"}, 137 | {896,"WM_PENWINFIRST"}, 138 | {911,"WM_PENWINLAST"}, 139 | {72,"WM_POWER"}, 140 | {536,"WM_POWERBROADCAST"}, 141 | {791,"WM_PRINT"}, 142 | {792,"WM_PRINTCLIENT"}, 143 | {55,"WM_QUERYDRAGICON"}, 144 | {17,"WM_QUERYENDSESSION"}, 145 | {783,"WM_QUERYNEWPALETTE"}, 146 | {19,"WM_QUERYOPEN"}, 147 | {35,"WM_QUEUESYNC"}, 148 | {18,"WM_QUIT"}, 149 | {774,"WM_RENDERALLFORMATS"}, 150 | {773,"WM_RENDERFORMAT"}, 151 | {32,"WM_SETCURSOR"}, 152 | {7,"WM_SETFOCUS"}, 153 | {48,"WM_SETFONT"}, 154 | {50,"WM_SETHOTKEY"}, 155 | {128,"WM_SETICON"}, 156 | {11,"WM_SETREDRAW"}, 157 | {12,"WM_SETTEXT"}, 158 | {26,"WM_SETTINGCHANGE"}, 159 | {24,"WM_SHOWWINDOW"}, 160 | {5,"WM_SIZE"}, 161 | {779,"WM_SIZECLIPBOARD"}, 162 | {532,"WM_SIZING"}, 163 | {42,"WM_SPOOLERSTATUS"}, 164 | {125,"WM_STYLECHANGED"}, 165 | {124,"WM_STYLECHANGING"}, 166 | {262,"WM_SYSCHAR"}, 167 | {21,"WM_SYSCOLORCHANGE"}, 168 | {274,"WM_SYSCOMMAND"}, 169 | {263,"WM_SYSDEADCHAR"}, 170 | {260,"WM_SYSKEYDOWN"}, 171 | {261,"WM_SYSKEYUP"}, 172 | {82,"WM_TCARD"}, 173 | {30,"WM_TIMECHANGE"}, 174 | {275,"WM_TIMER"}, 175 | {772,"WM_UNDO"}, 176 | {1024,"WM_USER"}, 177 | {84,"WM_USERCHANGED"}, 178 | {46,"WM_VKEYTOITEM"}, 179 | {277,"WM_VSCROLL"}, 180 | {778,"WM_VSCROLLCLIPBOARD"}, 181 | {71,"WM_WINDOWPOSCHANGED"}, 182 | {70,"WM_WINDOWPOSCHANGING"}, 183 | {26,"WM_WININICHANGE"}, 184 | {256,"WM_KEYFIRST"}, 185 | {264,"WM_KEYLAST"}, 186 | { 136,"WM_SYNCPAINT"}, 187 | {33,"WM_MOUSEACTIVATE"}, 188 | {512,"WM_MOUSEMOVE"}, 189 | {513,"WM_LBUTTONDOWN"}, 190 | {514,"WM_LBUTTONUP"}, 191 | {515,"WM_LBUTTONDBLCLK"}, 192 | {516,"WM_RBUTTONDOWN"}, 193 | {517,"WM_RBUTTONUP"}, 194 | {518,"WM_RBUTTONDBLCLK"}, 195 | {519,"WM_MBUTTONDOWN"}, 196 | {520,"WM_MBUTTONUP"}, 197 | {521,"WM_MBUTTONDBLCLK"}, 198 | {522,"WM_MOUSEWHEEL"}, 199 | {512,"WM_MOUSEFIRST"}, 200 | {522,"WM_MOUSELAST"}, 201 | {0x2A1, "WM_MOUSEHOVER"}, 202 | {0x2A3, "WM_MOUSELEAVE"}, 203 | {WM_USER,"DM_GETDEFID"}, 204 | {(WM_USER+1),"DM_SETDEFID"}, 205 | {(WM_USER+2),"DM_REPOSITION"}, 206 | {(WM_USER+100),"PSM_PAGEINFO"}, 207 | {(WM_USER+101),"PSM_SHEETINFO"}, 208 | {0xc,"HELP_WM_HELP"}, 209 | {32768,"WM_APP"} 210 | }; 211 | 212 | #define MAX_TEXT 2048 213 | 214 | static char *msgstr[MAX_TEXT]; 215 | static char *unknown = "(unknown)"; 216 | 217 | static int need_init = 1; 218 | 219 | char *msgtotext(int msg) 220 | { 221 | int i; 222 | if (need_init) { 223 | printf("Init messages\n"); 224 | for (i=0; i < MAX_TEXT; i++) msgstr[i] = unknown; 225 | for (i=0; msginfo[i].num < 32767; i++) { 226 | if (msginfo[i].num >= MAX_TEXT) 227 | printf("Warning: ignore %d, %s\n", msginfo[i].num, 228 | msginfo[i].msg); 229 | else { 230 | if (msgstr[msginfo[i].num] != unknown) 231 | printf("Warning: duplicate %d %s and %s\n", msginfo[i].num, 232 | msgstr[msginfo[i].num], msginfo[i].msg); 233 | else 234 | msgstr[msginfo[i].num] = msginfo[i].msg; 235 | } 236 | } 237 | need_init = 0; 238 | } 239 | if (msg >= MAX_TEXT) 240 | return unknown; 241 | else 242 | return msgstr[msg]; 243 | } 244 | 245 | #else /* not DEBUGCHATTY */ 246 | char *msgtotext(int msg) 247 | { 248 | return "(msgtotext)"; 249 | } 250 | #endif /* DEBUGCHATTY */ 251 | -------------------------------------------------------------------------------- /keymap.c: -------------------------------------------------------------------------------- 1 | // This file comes from the vncviewer source 2 | // Converted to C from C++ and used in -fromwin version of x2x 3 | // 2003 By Mark Hayter 4 | 5 | // Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 6 | // 7 | // This file is part of the VNC system. 8 | // 9 | // The VNC system is free software; you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation; either version 2 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, write to the Free Software 21 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 22 | // USA. 23 | // 24 | // If the source code for the VNC system is not available from the place 25 | // whence you received this file, check http://www.uk.research.att.com/vnc or contact 26 | // the authors on vnc@uk.research.att.com for information on obtaining it. 27 | 28 | // Thanks to Martin C. Mueller for assistance with the 29 | // international keyboard mapping stuff. 30 | 31 | // KeyMap.cpp 32 | 33 | #ifdef WIN_2_X 34 | #include 35 | #include 36 | #define XK_MISCELLANY 37 | #define XK_LATIN1 38 | #define XK_XKB_KEYS 39 | #include "keymap.h" 40 | 41 | // Define the keymap structure 42 | typedef struct vncKeymapping_struct { 43 | unsigned int wincode; 44 | KeySym Xcode; 45 | } vncKeymapping; 46 | 47 | static const vncKeymapping keymap[] = { 48 | {VK_BACK, XK_BackSpace}, 49 | {VK_TAB, XK_Tab}, 50 | {VK_CLEAR, XK_Clear}, 51 | {VK_RETURN, XK_Return}, 52 | {VK_LSHIFT, XK_Shift_L}, 53 | {VK_RSHIFT, XK_Shift_L}, /* XXX mdh - never gen SHIFT_R */ 54 | {VK_SHIFT, XK_Shift_L}, 55 | {VK_LCONTROL, XK_Control_L}, 56 | {VK_RCONTROL, XK_Control_R}, 57 | {VK_CONTROL, XK_Control_L}, 58 | {VK_LMENU, XK_Alt_L}, 59 | {VK_RMENU, XK_Alt_R}, 60 | {VK_MENU, XK_Alt_L}, 61 | {VK_PAUSE, XK_Pause}, 62 | {VK_CAPITAL, XK_Caps_Lock}, 63 | {VK_ESCAPE, XK_Escape}, 64 | {VK_SPACE, XK_space}, 65 | {VK_PRIOR, XK_Page_Up}, 66 | {VK_NEXT, XK_Page_Down}, 67 | {VK_END, XK_End}, 68 | {VK_HOME, XK_Home}, 69 | {VK_LEFT, XK_Left}, 70 | {VK_UP, XK_Up}, 71 | {VK_RIGHT, XK_Right}, 72 | {VK_DOWN, XK_Down}, 73 | {VK_SELECT, XK_Select}, 74 | {VK_EXECUTE, XK_Execute}, 75 | {VK_SNAPSHOT, XK_Print}, 76 | {VK_INSERT, XK_Insert}, 77 | {VK_DELETE, XK_Delete}, 78 | {VK_HELP, XK_Help}, 79 | {VK_NUMPAD0, XK_KP_0}, 80 | {VK_NUMPAD1, XK_KP_1}, 81 | {VK_NUMPAD2, XK_KP_2}, 82 | {VK_NUMPAD3, XK_KP_3}, 83 | {VK_NUMPAD4, XK_KP_4}, 84 | {VK_NUMPAD5, XK_KP_5}, 85 | {VK_NUMPAD6, XK_KP_6}, 86 | {VK_NUMPAD7, XK_KP_7}, 87 | {VK_NUMPAD8, XK_KP_8}, 88 | {VK_NUMPAD9, XK_KP_9}, 89 | {VK_MULTIPLY, XK_KP_Multiply}, 90 | {VK_ADD, XK_KP_Add}, 91 | {VK_SEPARATOR, XK_KP_Separator}, // often comma 92 | {VK_SUBTRACT, XK_KP_Subtract}, 93 | {VK_DECIMAL, XK_KP_Decimal}, 94 | {VK_DIVIDE, XK_KP_Divide}, 95 | {VK_F1, XK_F1}, 96 | {VK_F2, XK_F2}, 97 | {VK_F3, XK_F3}, 98 | {VK_F4, XK_F4}, 99 | {VK_F5, XK_F5}, 100 | {VK_F6, XK_F6}, 101 | {VK_F7, XK_F7}, 102 | {VK_F8, XK_F8}, 103 | {VK_F9, XK_F9}, 104 | {VK_F10, XK_F10}, 105 | {VK_F11, XK_F11}, 106 | {VK_F12, XK_F12}, 107 | {VK_F13, XK_F13}, 108 | {VK_F14, XK_F14}, 109 | {VK_F15, XK_F15}, 110 | {VK_F16, XK_F16}, 111 | {VK_F17, XK_F17}, 112 | {VK_F18, XK_F18}, 113 | {VK_F19, XK_F19}, 114 | {VK_F20, XK_F20}, 115 | {VK_F21, XK_F21}, 116 | {VK_F22, XK_F22}, 117 | {VK_F23, XK_F23}, 118 | {VK_F24, XK_F24}, 119 | {VK_NUMLOCK, XK_Num_Lock}, 120 | {VK_SCROLL, XK_Scroll_Lock} 121 | }; 122 | 123 | static unsigned char buf[4]; 124 | static unsigned char keystate[256]; 125 | 126 | KeyActionSpec PCtoX(UINT virtkey, DWORD keyData) { 127 | int numkeys = 0; 128 | int mapsize, i; 129 | int extended; 130 | int ret; 131 | 132 | KeyActionSpec kas; 133 | kas.releaseModifiers = 0; 134 | 135 | extended = ((keyData & 0x1000000) != 0); 136 | #ifdef DEBUG 137 | printf(" keyData %04x ", (unsigned int) keyData); 138 | #endif 139 | 140 | if (extended) { 141 | #ifdef DEBUG 142 | printf(" (extended) "); 143 | #endif 144 | switch (virtkey) { 145 | case VK_MENU : 146 | virtkey = VK_RMENU; 147 | break; 148 | case VK_CONTROL: 149 | virtkey = VK_RCONTROL; 150 | break; 151 | } 152 | } 153 | 154 | // We try looking it up in our table 155 | mapsize = sizeof(keymap) / sizeof(vncKeymapping); 156 | 157 | // Look up the desired code in the table 158 | for (i = 0; i < mapsize; i++) { 159 | if (keymap[i].wincode == virtkey) { 160 | kas.keycodes[numkeys++] = keymap[i].Xcode; 161 | break; 162 | } 163 | } 164 | 165 | if (numkeys != 0) { 166 | #ifdef DEBUG 167 | UINT key = kas.keycodes[numkeys-1]; 168 | printf("keymap gives %u (%x) ", key, key); 169 | #endif 170 | } else { 171 | // not found in table 172 | #ifdef DEBUG 173 | printf("not in special keymap, "); 174 | #endif 175 | // we try a simple conversion to Ascii, using the current keyboard mapping 176 | GetKeyboardState(keystate); 177 | 178 | ret = ToAscii(virtkey, 0, keystate, (WORD *) buf, 0); 179 | 180 | // If Left Ctrl & Alt both pressed and ToAscii gives a valid keysym 181 | // This is for AltGr on international keyboards (= LCtrl-Alt). 182 | // e.g. Ctrl-Alt-Q gives @ on German keyboards 183 | if ( ((keystate[VK_MENU] & 0x80) != 0) && 184 | ((keystate[VK_CONTROL] & 0x80) != 0) ) { 185 | 186 | // If the key means anything in this keyboard layout 187 | if ( (ret >= 1) && 188 | ( ( (*buf >= 32) && (*buf <= 126) ) || 189 | ( (*buf >= 160) && (*buf <= 255) ) ) 190 | ) { 191 | 192 | // Send the modifiers up, then the keystroke, then mods down 193 | // We don't release the right control; this allows German users 194 | // to use it for doing Ctl-@ etc. (though not under Win95 -- 195 | // see below) 196 | 197 | if (GetKeyState(VK_LCONTROL) & 0x8000) 198 | kas.releaseModifiers |= KEYMAP_LCONTROL; 199 | 200 | if (GetKeyState(VK_LMENU) & 0x8000) 201 | kas.releaseModifiers |= KEYMAP_LALT; 202 | 203 | if (GetKeyState(VK_RMENU) & 0x8000) 204 | kas.releaseModifiers |= KEYMAP_RALT; 205 | 206 | // This is for windows 95, and possibly other systems. 207 | // The above GetKeyState calls don't work in 95 - they always return 0. 208 | // But if we're here at all we know that control and alt are pressed, so let's 209 | // raise all Control and Alt keys if we haven't registered any yet. 210 | if (kas.releaseModifiers == 0) 211 | kas.releaseModifiers = KEYMAP_LCONTROL | KEYMAP_LALT | KEYMAP_RALT; 212 | 213 | #ifdef DEBUG 214 | printf("Ctrl-Alt pressed ToAscii(without modifiers)returns %d bytes: ", 215 | ret); 216 | #endif 217 | for (i = 0; i < ret; i++) { 218 | kas.keycodes[numkeys++] = *(buf+i); 219 | #ifdef DEBUG 220 | printf("%02x (%c) ", *(buf+i) , *(buf+i)); 221 | #endif 222 | } 223 | #ifdef DEBUG 224 | printf("\n"); 225 | #endif 226 | } 227 | 228 | } 229 | 230 | // If not a ctrl-alt key 231 | if (numkeys == 0) { 232 | 233 | // There are no keysyms corresponding to control characters 234 | // Eg Ctrl F. The server already knows whether the control 235 | // key is pressed. So we are interested in the key that would be 236 | // there if the Ctrl were not pressed. 237 | keystate[VK_CONTROL] = keystate[VK_LCONTROL] = keystate[VK_RCONTROL] = 0; 238 | 239 | ret = ToAscii(virtkey, 0, keystate, (WORD *) buf, 0); 240 | if (ret < 0) { 241 | switch (*buf) { 242 | case '`' : 243 | kas.keycodes[numkeys++] = XK_dead_grave; 244 | break; 245 | case '\'' : 246 | kas.keycodes[numkeys++] = XK_dead_acute; 247 | break; 248 | case '~' : 249 | kas.keycodes[numkeys++] = XK_dead_tilde; 250 | break; 251 | case '^': 252 | kas.keycodes[numkeys++] = XK_dead_circumflex; 253 | break; 254 | } 255 | } 256 | // if this works, and it's a regular printable character, just send that 257 | if (ret >= 1) { 258 | #ifdef DEBUG 259 | printf("ToAscii (without ctrl) returns %d byte(s): ", ret); 260 | #endif 261 | for (i = 0; i < ret; i++) { 262 | kas.keycodes[numkeys++] = *(buf+i); 263 | #ifdef DEBUG 264 | printf("%02x (%c) ", *(buf+i) , *(buf+i)); 265 | #endif 266 | } 267 | } 268 | } 269 | } 270 | 271 | kas.keycodes[numkeys] = VoidKeyCode; 272 | return kas; 273 | } 274 | 275 | #endif 276 | -------------------------------------------------------------------------------- /x2x.1: -------------------------------------------------------------------------------- 1 | .nh 2 | .de URL 3 | \\$2 \(laURL: \\$1 \(ra\\$3 4 | .. 5 | .if \n[.g] .mso www.tmac 6 | \" .mso www.tmac 7 | .TH x2x 1 8 | .SH NAME 9 | x2x \- X to X connection 10 | .SH SYNTAX 11 | \fB x2x\fR <[\-to ] | [\-fromwin | \-from ]> [options...] 12 | .SH DESCRIPTION 13 | x2x allows the keyboard and mouse on one ("from") X display to be used to 14 | control another ("to") X display. Since x2x uses the XTEST extension, 15 | the "to" X display must support XTEST. 16 | 17 | If x2x is built under Cygwin (on Windows XP or Windows 2000) then the 18 | \-fromwin option may be specified to allow the "from" display to be the 19 | Windows desktop. (The Cygwin build also supports use of an X display 20 | for the "from" screen). Use of \-fromwin sets the default behaviour as 21 | if the \-big \-west \-capslockhack options had also been given. 22 | 23 | In the default interface, x2x puts a window on the "from" display. 24 | This window is labeled with the name of the "to" display. Keystrokes 25 | typed into this window go to the window on the "to" display that has 26 | the input focus. Clicking on the x2x window causes the mouse on the 27 | "from" display to control the cursor on the "to" display. Performing 28 | a subsequent multiple button click on the "to" display returns control 29 | to the "from" display. 30 | 31 | If the \-fromwin, \-north, \-south, \-east or \-west options are specified 32 | on the command line, x2x starts up with a different interface. When 33 | the mouse moves to the top, bottom, east side or west side of the 34 | default screen on the "from" display, the cursor slides over to the 35 | "to" display. When the mouse returns to to side of the "to" display 36 | that it entered, it slides back onto the "from" display. 37 | 38 | Unless the \-nosel option is specified, x2x relays X selections from 39 | one display to the other. (If \-fromwin is specified then the X 40 | selection is relayed to and from the Windows clipboard as text strings). 41 | 42 | Here are a few hints for eXcursion users (based on Intel version 43 | 2.1.309). First, use the \-big option. Second, in the control panel, 44 | under mouse, check the box that enables "Automatically Capture Text on 45 | Button Up." X selections will then automatically move into the 46 | Windows clipboard. As is the case with all X applications running on 47 | 2.1.309 (including x2x), you will need to do an extra mouse click 48 | after performing the X selection for this operation to work. x2x is 49 | known to work poorly with eXcursion running on Windows 95, probably 50 | due to the Windows 95 task scheduler. x2x does work well with eXcursion 51 | running on Windows NT. 52 | 53 | The hints for eXcursion are also valid for Exceed, with the exception 54 | that X selections work better, as long as you are using x2x version 55 | 1.25 or later. 56 | 57 | .SH OPTIONS 58 | Either the \-to option or the \-from option (or both) must be specified. 59 | .TP 60 | .B \-to \fIdisplay\fP 61 | .IP 62 | Indicates the ("to") display that is remotely controlled by the "from" display. 63 | Default is equivalent to the default display. 64 | .TP 65 | .B \-from \fIdisplay\fP 66 | .IP 67 | Indicates the ("from") display that remotely controls the "to" display. 68 | Default is equivalent to the default display. 69 | .TP 70 | .B \-fromwin 71 | .IP 72 | Available when x2x is built in the Cygwin environment. This option 73 | indicates the ("from") display should be the Windows desktop. In this 74 | case the "to" display must be specified with the \-to option. Setting 75 | this option forces \-big and sets the default to \-west \-capslockhack 76 | 77 | The \-fromwin option works best when Windows is configured for 78 | focus-follows-mouse also known as X Mouse. This can be set using 79 | TweakUI for Windows XP (on the Mouse/X-Mouse panel) or the XMouse2000 80 | program for Windows 2000. If Windows is set for its default behaviour 81 | x2x will attempt to get the keyboard and mouse focus but may not 82 | succeed. (The Windows XP TweakUI has a General/Focus option that can be 83 | unchecked to allow applications to steal the focus.) If it fails the 84 | first try, x2x tries quite hard to get the focus! 85 | 86 | If the "to" display supports mouse buttons 4 and 5 then mouse wheel 87 | events on the Windows side are translated to clicks of buttons 4 and 5 88 | on the X display. This matches with XFree86 servers using 89 | Option "ZAxisMapping" "4 5". 90 | 91 | A link may be created on the Windows desktop to conveniently launch 92 | x2x. Assuming cygwin is installed to C:\\cygwin and x2x.exe is in 93 | /usr/X11R6/bin then the link properties should be set to: 94 | 95 | Target: 96 | .br 97 | C:\\cygwin\\usr\\X11R6\\bin\\run.exe\ /usr/X11R6/bin/x2x\ \-fromwin\ \-to\ somewhere:0.0\ \-east 98 | 99 | Start In: C:\\cygwin\\usr\\X11R6\\bin 100 | 101 | The "Start In" option is important to allow DLLs to be loaded and 102 | C:\\cygwin\\bin must be on the Windows PATH to allow other DLLs to be 103 | loaded. (If either of these are incorrect, launching the application 104 | tends to silently fail.) 105 | 106 | There are two magic key combinations activated by \-fromwin: 107 | 108 | RightAlt-Home: Forces the focus back to Windows without needing the 109 | mouse to be moved. Useful when some popup window on the Windows side 110 | grabs the mouse! 111 | 112 | RightAlt-End: Exit x2x 113 | .TP 114 | .B \-north 115 | .IP 116 | Slide off the north side of the "to" display onto the "from" display. 117 | .TP 118 | .B \-south 119 | .IP 120 | Slide off the south side of the "to" display onto the "from" display. 121 | .TP 122 | .B \-east 123 | .IP 124 | Slide off the east side of the "to" display onto the "from" display. 125 | .TP 126 | .B \-west 127 | .IP 128 | Slide off the west side of the "to" display onto the "from" display. 129 | .TP 130 | .B \-font \fIfontname\fP 131 | .IP 132 | The font used in the x2x window. (Overridden by \-east or \-west.) 133 | .TP 134 | .B \-geometry \fIspecification\fP 135 | .IP 136 | The X geometry specification for the x2x window. 137 | (Overridden by \-north, \-south, \-east or \-west.) 138 | .TP 139 | .B \-wait 140 | .IP 141 | Tells x2x to poll the "to" and "from" displays at startup until they 142 | are ready. Useful for login scripts. 143 | .TP 144 | .B \-big 145 | .IP 146 | Workaround for a bug in the cursor grab implementations of at least one 147 | X server. Put a big window over the "from" display in order to force the 148 | X server to track the cursor. (This option is forced by the \-fromwin option). 149 | .TP 150 | .B \-buttonblock 151 | .IP 152 | If this option is enabled with \-north, \-south, \-east or \-west, the 153 | cursor will not slide back onto the "from" display when one or more 154 | mouse buttons are pressed. 155 | .TP 156 | .B \-buttonmap \fIbutton#\fP \fR"\fP\fIKeySym ...\fP\fR"\fP 157 | .IP 158 | Map a mouse button to one or more keyboard events on the "to" display. 159 | This is useful if you have a mouse with more buttons than the remote X 160 | server can handle (e.g. a wheel mouse on a PC, merged with a Sun/Sparc 161 | OpenWindows display). 162 | .TP 163 | .B \-nomouse 164 | .IP 165 | Don't capture the mouse. 166 | (Overridden by \-north, \-south, \-east or \-west.) 167 | .TP 168 | .B \-nopointermap 169 | .IP 170 | Since x2x uses XTEST, which sends input at a lower level than the 171 | pointer button mapping, x2x needs to understand the "to" display's 172 | button mapping and do appropriate conversion. Use this option 173 | to turn off the pointer button conversion. 174 | .TP 175 | .B \-nosel 176 | .IP 177 | Don't relay the X selection between displays. 178 | .TP 179 | .B \-noautoup 180 | .IP 181 | Normally, the autoup feature in x2x automatically lifts up all keys and 182 | mouse buttons when it removes the cursor from the "from" display. 183 | .B 184 | Note: the autoup feature changes the state of lock functions like 185 | .B 186 | Caps Lock. The state of the lock function may not correspond to 187 | .B 188 | the state of the keyboard LEDs! 189 | To disable this feature, use the \-noautoup command line option. 190 | .TP 191 | .B \-resurface 192 | .IP 193 | Ugly hack to work-around window manager ugliness. The \-north, \-south, 194 | \-east and \-west modes actually put a small window on the side of the 195 | "from" display. This option causes this window to resurface itself if 196 | another window ever obscures it. This option can cause really nasty 197 | behavior if another application tries to do the same thing. Useful for 198 | login scripts. 199 | .TP 200 | .B \-win-output 201 | .IP 202 | Makes the small window ("trigger window") on the side of the "from" display 203 | an InputOutput window instead of an InputOnly window. Visibility notification 204 | events are never generated for InputOnly window, therefore -resurface would 205 | not work for InputOnly window. Use -win-output together with -resurface. 206 | .TP 207 | .B \-win-transparent 208 | .IP 209 | Makes the small window ("trigger window") transparent. Use with -win-output option. 210 | .TP 211 | .B \-struts 212 | .IP 213 | Advertise struts in _NET_WM_STRUT 214 | 215 | Once upon a time, the trigger window was a regular window and could be 216 | arbitrarily stacked. If obscured it would stop working. Later the 217 | trigger window became a dock, to be treated specially by the window 218 | manager. The EWMH spec 219 | .B suggests 220 | placing docks over all other 221 | windows... but some window managers place docks below before unmapping 222 | them. XMonad is one such window manager. In this case we would like to 223 | advertise struts - reserved space along screen edges that is not 224 | normally obscured. However this should not happen if the dock is already 225 | above all windows. And thus the new '\-struts' settings is born, which 226 | uses the '_NET_WM_STRUT' property. 227 | 228 | Note that this is a less hacky alternative to '\-resurface'. 229 | .TP 230 | .B \-capslockhack 231 | .IP 232 | Ugly hack to work-around the situation in which the "to" Xserver doesn't 233 | seem to honor the state of the CapsLock on the "from" Xserver. This is 234 | the default when the \-fromwin option is given (although the hack used 235 | is slightly less ugly). 236 | .TP 237 | .B \-nocapslockhack 238 | .IP 239 | Disable the \-capslockhack behaviour. Used to change the default 240 | behaviour after the \-fromwin option is specified. 241 | .TP 242 | .B \-clipcheck 243 | .IP 244 | Check that clipboard entries are regular strings (XA_STRING) before 245 | forwarding to Windows. Enabling this is safer but may prevent copying 246 | with certain setups (eg from emacs under KDE/XFree). 247 | .TP 248 | .B \-shadow \fIdisplay\fP 249 | .IP 250 | Also sends mouse movements and keystrokes to this display. Useful 251 | for demos. Amaze your friends: specify multiple shadows. 252 | .TP 253 | .B \-sticky \fIsticky-key\fP 254 | .IP 255 | This option is primarily for "lock" keys like Caps_Lock. If a lock 256 | key only seems to work on every other press, try this option. The 257 | sticky option prevents autoup for the specified key. Look in 258 | /usr/include/X11/keysymdef.h for a list of valid names of keys 259 | (remove the leading XK_). 260 | .TP 261 | .B \-singlesticky 262 | .IP 263 | Some X servers generate both a key down and a key up when a lock key 264 | is toggled. Some X servers generate a key down when a lock key is 265 | activated and a key up only when it is deactivated. This option will 266 | allow an X server with the former behavior to control one with the 267 | latter behavior. Use this if Caps_Lock lock is behaving like shift. 268 | .TP 269 | .B \-label \fIlabel\fP 270 | .IP 271 | Override the label of the control window (useful when running over ssh). 272 | The label is the text displayed within the control window. 273 | .TP 274 | .B \-title \fItitle\fP 275 | .IP 276 | Override the title of the control window (useful when running over ssh). 277 | .IP 278 | .TP 279 | .B \-copyright 280 | .IP 281 | Prints the full copyright for the x2x code. 282 | .TP 283 | .B \-noscale 284 | .IP 285 | This option turns off the mouse scaling. In some circumstances, the 286 | remote screen is so different in physical size or resolution that the 287 | normal mouse scaling applied by x2x distorts the mouse movement so much 288 | as to be practially unusable. Note: this is only useful if the remote 289 | screen is lower resolution than the local screen and also causes the 290 | remote mouse pointer to warp around when it hits the edges. 291 | .TP 292 | .B \-completeregionleft 293 | .IP 294 | Describes leftmost coordinate of complete rectangle region in from-display. If 295 | from-display is configured with multiple monitors and they have different 296 | resolution, few regions that does not belongs to any monitor becomes dead space 297 | that mouse cannot move in. In the case, the dead space can be mapped to legal 298 | region of to-display. If complete region in from-display is specified, X2X 299 | maps only complete region to to-display and avoid the dead, but legal regions. 300 | .TP 301 | .B \-completeregionright 302 | .IP 303 | Describes rightmost coordinate of complete rectangle region in from-display. 304 | .TP 305 | .B \-completeregionup 306 | .IP 307 | Describes uppermost coordinate of complete rectangle region in from-display. 308 | .TP 309 | .B \-completeregionlow 310 | .IP 311 | Describes lowermost coordinate of complete rectangle region in from-display. 312 | .SH EXAMPLES 313 | Calling the system whose keyboard is to be used "primary" and the 314 | other system "secondary", you need to specify either \-from 315 | primary-x-display or \-to secondary-x-display. The x2x program can be 316 | run on either system. The easiest way to maintain security is to 317 | tunnel an X connection over ssh. Since x2x can be run on either 318 | computer, it can be invoked in either of the following ways, where we 319 | assume the local display on each system is :0. 320 | .TP 321 | run indirectly on secondary: 322 | .IP 323 | primary $ ssh \-X secondary x2x \-to :0 \-east 324 | .TP 325 | run indirectly on primary: 326 | .IP 327 | secondary $ ssh \-X primary x2x \-from :0 \-west 328 | .TP 329 | run directly indirectly on primary: 330 | .IP 331 | primary $ ssh \-A secondary env DISPLAY=:0.0 ssh \-X primary x2x \-from :0 \-east 332 | 333 | .RE 334 | If your primary display is configured with several monitors having different 335 | resolutions, \-completeregion(left|up|right|low) options can be helpful. 336 | suppose that you have two monitors connected to the primary system and the 337 | resolution of the left-side monitor is 300x300 while the right-side one is 338 | 400x400. Also, you aligned these two monitors to be vertically centric. 339 | Therefore, your primary system has virtually 700x400 resolution. 340 | 341 | The left monitor covers (0,50,300,350) of the virtual total resolution while 342 | the right monitor covers (300,0,700,400). The four numbers each represent left, 343 | top, right, and bottom. Also, you have two dead spaces: (0,0,300,50) and 344 | (0,350,300,400). Thus, the complete square region for this configuration would 345 | be (0,50,700,350). 346 | 347 | If no explicit description is provided, the x2x recognizes the virtual total 348 | resolution (0,0,700,400) only. As a consequence, the dead space region cannot 349 | be reached in the secondary system. You can solve this problem by teaching x2x 350 | that the real complete square region for the secondary system (0,50,700,350) 351 | using the \-comptereregion(left|up|right|low) options as below: 352 | .IP 353 | \-completeregionleft 0 \-completeregionup 50 -completeregionright 700 -completeregionlow 350 354 | 355 | .SH SEE ALSO 356 | The 357 | .URL http://synergy-project.org "synergy program" 358 | has similar functionality to that of x2x, supports multiple platforms, 359 | and when I try to use it my X session crashes. 360 | 361 | There is a nice 362 | .URL http://www.linuxjournal.com/content/share-keyboardmouse-between-multiple-computers-x2x "Linux Journal article on x2x" . 363 | .SH AUTHOR 364 | David Chaiken 365 | .br 366 | Mark Hayter (\-fromwin code, thanks to the WinVNC sources) 367 | .br 368 | Addition of \-north and \-south options by Charles Briscoe-Smith 369 | . 370 | .br 371 | Current maintaner is Mikhail Gusarov 372 | .SH BUGS 373 | This software is experimental! Heaven help you if your network 374 | connection should go down. Caveat hacker. TANSTAAFL. 375 | 376 | The 377 | .URL http://github.com/dottedmag/x2x "x2x repository and issue tracker" 378 | has moved to github. 379 | 380 | When using the \-fromwin option if the Ctrl-Alt-Del keysequence is used 381 | while the mouse is forwarded to the X display then the Ctrl and Alt 382 | key press events are reported to x2x and forwarded but no other key 383 | events are generated. Thus if the Ctrl-Alt-Del sequence is used to 384 | manually lock the Windows display when the display is unlocked the 385 | mouse will still be forwarded to the X screen and the X server will 386 | believe Ctrl and Alt are still pressed. Pressing and releasing Ctrl 387 | and Alt should restore correct operation, as should returning the 388 | mouse to the Windows display (or using the RightAlt-Home magic key 389 | sequence). 390 | 391 | If you have trouble with some keys not working, try setting the 392 | keymaps on both systems to be the same using \fBsetxkbmap\fR. 393 | If that's not enough, make sure that the output of \fBsetxkbmap \-query\fR is identical on both machines. 394 | 395 | .SH LAWYERESE 396 | Copyright (c) 1997 397 | Digital Equipment Corporation. All rights reserved. 398 | 399 | By downloading, installing, using, modifying or distributing this 400 | software, you agree to the following: 401 | 402 | 1. CONDITIONS. Subject to the following conditions, you may download, 403 | install, use, modify and distribute this software in source and binary forms: 404 | 405 | a) Any source code, binary code and associated documentation 406 | (including the online manual) used, modified or distributed must 407 | reproduce and retain the above copyright notice, this list of 408 | conditions and the following disclaimer. 409 | 410 | b) No right is granted to use any trade name, trademark or logo of 411 | Digital Equipment Corporation. Neither the "Digital Equipment 412 | Corporation" name nor any trademark or logo of Digital Equipment 413 | Corporation may be used to endorse or promote products derived from 414 | this software without the prior written permission of Digital 415 | Equipment Corporation. 416 | 417 | 2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL "AS IS" AND ANY 418 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 419 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 420 | PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY 421 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 422 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 423 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 424 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 425 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 426 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 427 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 428 | 429 | Windows 95 and Windows NT are trademarks of Microsoft Corporation. 430 | .br 431 | Exceed is a trademark of Hummingbird Communications Ltd. 432 | -------------------------------------------------------------------------------- /x2x.c: -------------------------------------------------------------------------------- 1 | /* 2 | * x2x: Uses the XTEST extension to forward mouse movements and 3 | * keystrokes from a window on one display to another display. Useful 4 | * for desks with multiple keyboards. 5 | * 6 | * Copyright (c) 1997 7 | * Digital Equipment Corporation. All rights reserved. 8 | * 9 | * By downloading, installing, using, modifying or distributing this 10 | * software, you agree to the following: 11 | * 12 | * 1. CONDITIONS. Subject to the following conditions, you may download, 13 | * install, use, modify and distribute this software in source and binary 14 | * forms: 15 | * 16 | * a) Any source code, binary code and associated documentation 17 | * (including the online manual) used, modified or distributed must 18 | * reproduce and retain the above copyright notice, this list of 19 | * conditions and the following disclaimer. 20 | * 21 | * b) No right is granted to use any trade name, trademark or logo of 22 | * Digital Equipment Corporation. Neither the "Digital Equipment 23 | * Corporation" name nor any trademark or logo of Digital Equipment 24 | * Corporation may be used to endorse or promote products derived from 25 | * this software without the prior written permission of Digital 26 | * Equipment Corporation. 27 | * 28 | * 2. DISCLAIMER. THIS SOFTWARE IS PROVIDED BY DIGITAL "AS IS" AND ANY 29 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 | * PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY 32 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 34 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 36 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 37 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 38 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | */ 40 | 41 | /* 42 | * Modified on 3 Oct 1998 by Charles Briscoe-Smith: 43 | * added options -north and -south 44 | */ 45 | 46 | /* Cygwin version with -fromwin to allow source to be a Windows 47 | * machine that is not running a X server. 48 | * Adapted by Mark Hayter 2003 using win2vnc ClientConnect.cpp code 49 | * 50 | * Original win2vnc copyright follows: 51 | */ 52 | // win2vnc, adapted from vncviewer by Fredrik Hubinette 2001 53 | // 54 | // Original copyright follows: 55 | // 56 | // Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 57 | // 58 | // This file is part of the VNC system. 59 | // 60 | // The VNC system is free software; you can redistribute it and/or modify 61 | // it under the terms of the GNU General Public License as published by 62 | // the Free Software Foundation; either version 2 of the License, or 63 | // (at your option) any later version. 64 | // 65 | // This program is distributed in the hope that it will be useful, 66 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 67 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 68 | // GNU General Public License for more details. 69 | // 70 | // You should have received a copy of the GNU General Public License 71 | // along with this program; if not, write to the Free Software 72 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 73 | // USA. 74 | // 75 | // If the source code for the VNC system is not available from the place 76 | // whence you received this file, check http://www.uk.research.att.com/vnc or contact 77 | // the authors on vnc@uk.research.att.com for information on obtaining it. 78 | 79 | 80 | 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | #include 91 | #include /* for selection */ 92 | #include 93 | #include 94 | #include 95 | #include 96 | #include 97 | 98 | #ifdef WIN_2_X 99 | #define _WIN32_WINNT 0x0500 100 | #include 101 | #include 102 | #include 103 | #include "keymap.h" 104 | #include "resource.h" 105 | 106 | #define X2X_MSG_HOTKEY (WM_USER + 1) 107 | 108 | #define DPMSModeOn 0 109 | extern Status DPMSForceLevel(Display *, unsigned short); 110 | /* We always support this: */ 111 | #define DPMSQueryExtension(DPY, EVBASE, ERBASE) TRUE 112 | #else 113 | #include 114 | #endif 115 | 116 | 117 | 118 | 119 | /*#define DEBUG*/ 120 | 121 | #ifndef MIN 122 | #define MIN(x,y) (((x) < (y)) ? (x) : (y)) 123 | #endif 124 | #ifndef MAX 125 | #define MAX(x,y) (((x) > (y)) ? (x) : (y)) 126 | #endif 127 | 128 | #define UTF8_STRING "UTF8_STRING" 129 | 130 | /********** 131 | * definitions for edge 132 | **********/ 133 | #define EDGE_NONE 0 /* don't transfer between edges of screens */ 134 | #define EDGE_NORTH 1 /* from display is on the north side of to display */ 135 | #define EDGE_SOUTH 2 /* from display is on the south side of to display */ 136 | #define EDGE_EAST 3 /* from display is on the east side of to display */ 137 | #define EDGE_WEST 4 /* from display is on the west side of to display */ 138 | 139 | /********** 140 | * stuff for selection forwarding 141 | **********/ 142 | typedef struct _dpyxtra { 143 | Display *otherDpy; 144 | int sState; 145 | Atom pingAtom; 146 | Bool pingInProg; 147 | Window propWin; 148 | } DPYXTRA, *PDPYXTRA; 149 | 150 | #define FAKE_KEY 0 151 | #define FAKE_BUTTON 1 152 | 153 | #define N_BUTTONS 20 154 | 155 | #define MAX_BUTTONMAPEVENTS 20 156 | 157 | #define GETDPYXTRA(DPY,PDPYINFO)\ 158 | (((DPY) == (PDPYINFO)->fromDpy) ?\ 159 | &((PDPYINFO)->fromDpyXtra) : &((PDPYINFO)->toDpyXtra)) 160 | 161 | /* values for sState */ 162 | #define SELSTATE_ON 0 163 | #define SELSTATE_OFF 1 164 | #define SELSTATE_WAIT 2 165 | 166 | /* special values for translated coordinates */ 167 | #define COORD_INCR -1 168 | #define COORD_DECR -2 169 | #define SPECIAL_COORD(COORD) (((COORD) < 0) ? (COORD) : 0) 170 | 171 | /* max unreasonable coordinates before accepting it */ 172 | #define MAX_UNREASONABLES 10 173 | 174 | /********** 175 | * structures for recording state of buttons and keys 176 | **********/ 177 | typedef struct _fakestr { 178 | struct _fakestr *pNext; 179 | int type; 180 | KeySym thing; 181 | KeyCode code; 182 | } FAKE, *PFAKE; 183 | 184 | 185 | /********** 186 | * display information 187 | **********/ 188 | typedef struct { 189 | /* stuff on "from" display */ 190 | Display *fromDpy; 191 | Atom fromDpyUtf8String; 192 | Window root; 193 | Window trigger; 194 | Window big; 195 | Window selWinFrom; 196 | int selRevFrom; 197 | GC textGC; 198 | Atom wmpAtom, wmdwAtom; 199 | Atom netWmWindowTypeAtom, netWmWindowTypeDockAtom; 200 | Atom netWmStrutAtom; 201 | Cursor grabCursor; 202 | Font fid; 203 | int width, height, twidth, theight, tascent; 204 | Bool vertical; 205 | int lastFromCoord; 206 | int unreasonableDelta; 207 | 208 | #ifdef WIN_2_X 209 | int unreasonableCount; 210 | /* From display info for Windows */ 211 | HWND bigwindow; 212 | HWND edgewindow; 213 | int onedge; 214 | int fromWidth, fromHeight; 215 | int wdelta; 216 | int lastFromY; 217 | HWND hwndNextViewer; 218 | // int initialClipboardSeen; 219 | char *winSelText; 220 | int owntoXsel; 221 | int expectSelNotify; 222 | int expectOwnClip; 223 | int winSSave; 224 | int nXbuttons; 225 | RECT monitorRect; 226 | RECT screenRect; 227 | int screenHeight; 228 | int screenWidth; 229 | int lastFromX; 230 | #endif /* WIN_2_X */ 231 | 232 | /* stuff on "to" display */ 233 | Display *toDpy; 234 | Atom toDpyUtf8String; 235 | Atom toDpyTargets; 236 | Window selWinTo; 237 | int selRevTo; 238 | unsigned int inverseMap[N_BUTTONS + 1]; /* inverse of button mapping */ 239 | 240 | /* state of connection */ 241 | int signal; /* gort signal? */ 242 | int mode; /* connection */ 243 | int eventMask; /* trigger */ 244 | 245 | /* coordinate conversion stuff */ 246 | int toScreen; 247 | int nScreens; 248 | short **xTables; /* precalculated conversion tables */ 249 | short **yTables; 250 | int fromConnCoord; /* location of cursor after conn/disc ops */ 251 | int fromDiscCoord; 252 | int fromIncrCoord; /* location of cursor after incr/decr ops */ 253 | int fromDecrCoord; 254 | 255 | /* selection forwarding info */ 256 | DPYXTRA fromDpyXtra; 257 | DPYXTRA toDpyXtra; 258 | Display *sDpy; 259 | XSelectionRequestEvent sEv; 260 | Time sTime; 261 | 262 | /* for recording state of buttons and keys */ 263 | PFAKE pFakeThings; 264 | 265 | } DPYINFO, *PDPYINFO; 266 | 267 | static DPYINFO dpyInfo; 268 | 269 | /* shadow displays */ 270 | typedef struct _shadow { 271 | struct _shadow *pNext; 272 | char *name; 273 | Display *dpy; 274 | long led_mask; 275 | Bool flush; 276 | int DPMSstatus; /* -1: not queried, 0: not supported, 1: supported */ 277 | } SHADOW, *PSHADOW; 278 | 279 | /* sticky keys */ 280 | typedef struct _sticky { 281 | struct _sticky *pNext; 282 | KeySym keysym; 283 | } STICKY, *PSTICKY; 284 | 285 | typedef int (*HANDLER)(Display *, PDPYINFO, XEvent *); /* event handler function */ 286 | 287 | /********** 288 | * functions 289 | **********/ 290 | static void ParseCommandLine(int, char **); 291 | static Display *OpenAndCheckDisplay(char *); 292 | static Bool CheckTestExtension(Display *); 293 | #ifndef WIN_2_X 294 | static int ErrorHandler(Display *, XErrorEvent *); 295 | #endif 296 | static void DoDPMSForceLevel(PSHADOW, CARD16); 297 | static void DoX2X(Display *, Display *); 298 | static void InitDpyInfo(PDPYINFO); 299 | static void DoConnect(PDPYINFO); 300 | static void DoDisconnect(PDPYINFO); 301 | static void RegisterEventHandlers(PDPYINFO); 302 | static Bool ProcessEvent(Display *, PDPYINFO); 303 | static Bool ProcessMotionNotify(Display*, PDPYINFO, XMotionEvent*); 304 | static Bool ProcessExpose(); 305 | static void DrawWindowText(PDPYINFO); 306 | static Bool ProcessEnterNotify(); 307 | static Bool ProcessButtonPress(); 308 | static Bool ProcessButtonRelease(); 309 | static Bool ProcessKeyEvent(); 310 | static Bool ProcessConfigureNotify(); 311 | static Bool ProcessClientMessage(); 312 | static Bool ProcessSelectionRequest(); 313 | static void SendPing(Display *, PDPYXTRA); 314 | static Bool ProcessPropertyNotify(); 315 | static Bool ProcessSelectionNotify(); 316 | static void SendSelectionNotify(XSelectionRequestEvent *); 317 | static Bool ProcessSelectionClear(); 318 | static Bool ProcessVisibility(); 319 | static Bool ProcessMapping(); 320 | static void FakeThingsUp(PDPYINFO); 321 | static void FakeAction(PDPYINFO, int, KeySym, Bool); 322 | static void RefreshPointerMapping(Display *, PDPYINFO); 323 | static void Usage(); 324 | static void *xmalloc(size_t); 325 | 326 | 327 | 328 | /* These prototypes need the typedefs */ 329 | #ifdef WIN_2_X 330 | static void MoveWindowToEdge(PDPYINFO); 331 | static int MoveWindowToScreen(PDPYINFO); 332 | static void DoWinConnect(PDPYINFO, int, int); 333 | static void DoWinDisconnect(PDPYINFO, int, int); 334 | static void SendButtonClick(PDPYINFO, int); 335 | LRESULT CALLBACK WinProcessMessage (HWND, UINT, WPARAM, LPARAM); 336 | void WinPointerEvent(PDPYINFO, int, int, DWORD, UINT); 337 | void WinKeyEvent(PDPYINFO, int, DWORD); 338 | void SendKeyEvent(PDPYINFO, KeySym, int, int, int); 339 | 340 | static Bool ProcessSelectionRequestW(); 341 | static Bool ProcessSelectionNotifyW(); 342 | static Bool ProcessSelectionClearW(); 343 | 344 | #ifdef DEBUGCHATTY 345 | char *msgtotext(int); 346 | #endif 347 | 348 | #endif /* WIN_2_X */ 349 | 350 | /********** 351 | * top-level variables 352 | **********/ 353 | static char *programStr = "x2x"; 354 | static char *fromDpyName = NULL; 355 | static char *toDpyName = NULL; 356 | static char *defaultFN = "-*-times-bold-r-*-*-*-180-*-*-*-*-*-*"; 357 | static char *fontName = "-*-times-bold-r-*-*-*-180-*-*-*-*-*-*"; 358 | static char *label = NULL; 359 | static char *title = NULL; 360 | static char *pingStr = "PING"; /* atom for ping request */ 361 | static char *geomStr = NULL; 362 | static Bool waitDpy = False; 363 | static Bool doBig = False; 364 | static Bool doMouse = True; 365 | static int doEdge = EDGE_NONE; 366 | static Bool doSel = True; 367 | static Bool doAutoUp = True; 368 | static Bool doResurface = False; 369 | static Bool winTransparent = False; 370 | static Bool doInputOnly = True; 371 | static PSHADOW shadows = NULL; 372 | static int triggerw = 2; 373 | static Bool doPointerMap = True; 374 | static PSTICKY stickies = NULL; 375 | static Bool doBtnBlock = False; 376 | static Bool doCapsLkHack = False; 377 | static Bool doClipCheck = False; 378 | static Bool doDpmsMouse = False; 379 | static int logicalOffset= 0; 380 | static int nButtons = 0; 381 | static KeySym buttonmap[N_BUTTONS + 1][MAX_BUTTONMAPEVENTS + 1]; 382 | static Bool noScale = False; 383 | static int compRegLeft = 0; 384 | static int compRegRight = 0; 385 | static int compRegUp = 0; 386 | static int compRegLow = 0; 387 | static Bool useStruts = False; 388 | 389 | #ifdef WIN_2_X 390 | /* These are used to allow pointer comparisons */ 391 | static char *fromWinName = "x2xFromWin"; 392 | static int dummy; 393 | static Display *fromWin = (Display *)&dummy; 394 | static HWND hWndSave; 395 | static HINSTANCE m_instance; 396 | #endif 397 | 398 | #ifdef DEBUG_COMPLREG 399 | #define debug_cmpreg printf 400 | #else 401 | void debug_cmpreg(const char *fmt, ...) 402 | { 403 | } 404 | #endif 405 | 406 | #ifdef DEBUG 407 | #define debug printf 408 | #else 409 | void debug(const char* fmt, ...) 410 | { 411 | } 412 | #endif 413 | 414 | #ifdef WIN_2_X 415 | 416 | #define MAX_WIN_ARGS 40 417 | 418 | int STDCALL 419 | WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow) 420 | { 421 | Display *fromDpy; 422 | PSHADOW pShadow; 423 | int argc; 424 | char *argv[MAX_WIN_ARGS]; 425 | char *ap; 426 | 427 | if (lpCmd[0] == ' ') 428 | { 429 | lpCmd++; 430 | } 431 | 432 | argv[0] = programStr; 433 | argc = 1; 434 | ap = lpCmd; 435 | 436 | /* XXX mdh - Should probably deal with quotes properly too */ 437 | while (*ap && (argc < MAX_WIN_ARGS)) { 438 | argv[argc++] = ap; 439 | while (*ap && (*ap != ' ')) ap++; 440 | if (*ap == ' ') *ap++ = 0; 441 | } 442 | m_instance = hInst; 443 | 444 | #else /* Not WIN_2_X */ 445 | /********** 446 | * main 447 | **********/ 448 | int main(argc, argv) 449 | int argc; 450 | char **argv; 451 | { 452 | Display *fromDpy; 453 | PSHADOW pShadow; 454 | 455 | #endif /* WIN_2_X */ 456 | #ifdef DEBUG 457 | setvbuf(stdout, NULL, _IONBF, 0); 458 | #endif 459 | 460 | XrmInitialize(); 461 | ParseCommandLine(argc, argv); 462 | 463 | #ifdef WIN_2_X 464 | if (fromDpyName != fromWinName) 465 | fromDpyName = XDisplayName(fromDpyName); 466 | #else 467 | fromDpyName = XDisplayName(fromDpyName); 468 | #endif 469 | 470 | toDpyName = XDisplayName(toDpyName); 471 | if (!strcasecmp(toDpyName, fromDpyName)) { 472 | fprintf(stderr, "%s: display names are both %s\n", programStr, toDpyName); 473 | exit(1); 474 | } 475 | 476 | /* no OS independent way to stop Xlib from complaining via stderr, 477 | but can always pipe stdout/stderr to /dev/null */ 478 | /* convert to real name: */ 479 | #ifdef WIN_2_X 480 | if (fromDpyName == fromWinName) { 481 | /* From is Windows, don't need to open */ 482 | fromDpy = fromWin; 483 | } else 484 | /* This ugly hanging else... */ 485 | #endif /* WIN_2_X */ 486 | /* ... qualifies this while in WIN_2_X case with an X source */ 487 | while ((fromDpy = XOpenDisplay(fromDpyName)) == NULL) { 488 | if (!waitDpy) { 489 | fprintf(stderr, "%s - error: can not open display %s\n", 490 | programStr, fromDpyName); 491 | exit(2); 492 | } /* END if */ 493 | sleep(10); 494 | } /* END while fromDpy */ 495 | (void)XSynchronize(fromDpy, True); 496 | 497 | /* toDpy is always the first shadow */ 498 | pShadow = (PSHADOW)xmalloc(sizeof(SHADOW)); 499 | pShadow->DPMSstatus = -1; 500 | pShadow->name = toDpyName; 501 | /* link into the global list */ 502 | pShadow->pNext = shadows; 503 | shadows = pShadow; 504 | 505 | /* initialize all of the shadows, including the toDpy */ 506 | for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) { 507 | pShadow->led_mask = 0; 508 | pShadow->flush = False; 509 | if (!(pShadow->dpy = OpenAndCheckDisplay(pShadow->name))) 510 | exit(3); 511 | } 512 | (void)XSynchronize(shadows->dpy, True); 513 | 514 | #ifndef WIN_2_X 515 | /* set error handler, 516 | so that program does not abort on non-critcal errors */ 517 | XSetErrorHandler(ErrorHandler); 518 | #endif 519 | 520 | /* run the x2x loop */ 521 | DoX2X(fromDpy, shadows->dpy); 522 | 523 | /* shut down gracefully */ 524 | 525 | #ifdef WIN_2_X 526 | /* Only close if it is a real X from display */ 527 | if (fromDpy != fromWin) 528 | XCloseDisplay(fromDpy); 529 | #else 530 | XCloseDisplay(fromDpy); 531 | #endif 532 | 533 | for (pShadow = shadows; pShadow; pShadow = pShadow->pNext) 534 | XCloseDisplay(pShadow->dpy); 535 | exit(0); 536 | 537 | } /* END main */ 538 | 539 | static Display *OpenAndCheckDisplay(name) 540 | char *name; 541 | { 542 | Display *openDpy; 543 | 544 | /* convert to real name: */ 545 | name = XDisplayName(name); 546 | while ((openDpy = XOpenDisplay(name)) == NULL) { 547 | if (!waitDpy) { 548 | fprintf(stderr, "%s - error: can not open display %s\n", 549 | programStr, name); 550 | return NULL; 551 | } /* END if */ 552 | sleep(10); 553 | } /* END while openDpy */ 554 | 555 | if (!CheckTestExtension(openDpy)) { 556 | fprintf(stderr, 557 | "%s - error: display %s does not support the test extension\n", 558 | programStr, name); 559 | return NULL; 560 | } 561 | return (openDpy); 562 | 563 | } /* END OpenAndCheckDisplay */ 564 | 565 | /********** 566 | * use standard X functions to parse the command line 567 | **********/ 568 | static void ParseCommandLine(argc, argv) 569 | int argc; 570 | char **argv; 571 | { 572 | int arg; 573 | PSHADOW pShadow; 574 | extern char *lawyerese; 575 | PSTICKY pNewSticky; 576 | KeySym keysym; 577 | int button; 578 | int eventno; 579 | char *keyname, *argptr; 580 | 581 | debug("programStr = %s\n", programStr); 582 | 583 | /* Clear button map */ 584 | for (button = 0; button <= N_BUTTONS; button++) 585 | buttonmap[button][0] = NoSymbol; 586 | 587 | for (arg = 1; arg < argc; ++arg) { 588 | #ifdef WIN_2_X 589 | if (!strcasecmp(argv[arg], "-fromWin")) { 590 | fromDpyName = fromWinName; 591 | /* XXX mdh - For now only support edge windows getting big */ 592 | /* Note: -east will override correctly (even if earlier on the line) */ 593 | doBig = True; 594 | if (doEdge == EDGE_NONE) doEdge = EDGE_WEST; 595 | doCapsLkHack = True; 596 | 597 | debug("fromDpyName = %s\n", fromDpyName); 598 | } else 599 | /* Note this else will qualify the if below... */ 600 | #endif /* WIN_2_X */ 601 | if (!strcasecmp(argv[arg], "-from")) { 602 | if (++arg >= argc) Usage(); 603 | fromDpyName = argv[arg]; 604 | 605 | debug("fromDpyName = %s\n", fromDpyName); 606 | } else if (!strcasecmp(argv[arg], "-to")) { 607 | if (++arg >= argc) Usage(); 608 | toDpyName = argv[arg]; 609 | 610 | debug("toDpyName = %s\n", toDpyName); 611 | } else if (!strcasecmp(argv[arg], "-font")) { 612 | if (++arg >= argc) Usage(); 613 | fontName = argv[arg]; 614 | 615 | debug("fontName = %s\n", fontName); 616 | } else if (!strcasecmp(argv[arg], "-label")) { 617 | if (++arg >= argc) Usage(); 618 | label = argv[arg]; 619 | 620 | debug("label = %s\n", label); 621 | } else if (!strcasecmp(argv[arg], "-title")) { 622 | if (++arg > argc) Usage(); 623 | title = argv[arg]; 624 | 625 | debug("title = %s\n", title); 626 | } else if (!strcasecmp(argv[arg], "-geometry")) { 627 | if (++arg >= argc) Usage(); 628 | geomStr = argv[arg]; 629 | 630 | debug("geometry = %s\n", geomStr); 631 | } else if (!strcasecmp(argv[arg], "-wait")) { 632 | waitDpy = True; 633 | 634 | debug("will wait for displays\n"); 635 | } else if (!strcasecmp(argv[arg], "-big")) { 636 | doBig = True; 637 | 638 | debug("will create big window on from display\n"); 639 | } else if (!strcasecmp(argv[arg], "-nomouse")) { 640 | doMouse = False; 641 | 642 | debug("will not capture mouse (eek!)\n"); 643 | } else if (!strcasecmp(argv[arg], "-nopointermap")) { 644 | doPointerMap = False; 645 | 646 | debug("will not do pointer mapping\n"); 647 | } else if (!strcasecmp(argv[arg], "-north")) { 648 | doEdge = EDGE_NORTH; 649 | 650 | debug("\"from\" is on the north side of \"to\"\n"); 651 | } else if (!strcasecmp(argv[arg], "-south")) { 652 | doEdge = EDGE_SOUTH; 653 | 654 | debug("\"from\" is on the south side of \"to\"\n"); 655 | } else if (!strcasecmp(argv[arg], "-east")) { 656 | doEdge = EDGE_EAST; 657 | 658 | debug("\"from\" is on the east side of \"to\"\n"); 659 | } else if (!strcasecmp(argv[arg], "-west")) { 660 | doEdge = EDGE_WEST; 661 | 662 | debug("\"from\" is on the west side of \"to\"\n"); 663 | } else if (!strcasecmp(argv[arg], "-nosel")) { 664 | doSel = False; 665 | 666 | debug("will not transmit X selections between displays\n"); 667 | } else if (!strcasecmp(argv[arg], "-noautoup")) { 668 | doAutoUp = False; 669 | 670 | debug("will not automatically lift keys and buttons\n"); 671 | } else if (!strcasecmp(argv[arg], "-buttonblock")) { 672 | doBtnBlock = True; 673 | 674 | debug("mouse buttons down will block disconnects\n"); 675 | } else if (!strcasecmp(argv[arg], "-capslockhack")) { 676 | doCapsLkHack = True; 677 | 678 | debug("behavior of CapsLock will be hacked\n"); 679 | } else if (!strcasecmp(argv[arg], "-dpmsmouse")) { 680 | doDpmsMouse = True; 681 | 682 | debug("mouse movement wakes monitor\n"); 683 | } else if (!strcasecmp(argv[arg], "-offset")) { 684 | if (++arg >= argc) Usage(); 685 | logicalOffset = atoi(argv[arg]); 686 | 687 | debug("logicalOffset %d\n", logicalOffset); 688 | } else if (!strcasecmp(argv[arg], "-clipcheck")) { 689 | doClipCheck = True; 690 | 691 | debug("Clipboard type will be checked for XA_STRING\n"); 692 | } else if (!strcasecmp(argv[arg], "-nocapslockhack")) { 693 | doCapsLkHack = False; 694 | 695 | debug("behavior of CapsLock will not be hacked\n"); 696 | } else if (!strcasecmp(argv[arg], "-sticky")) { 697 | if (++arg >= argc) Usage(); 698 | if ((keysym = XStringToKeysym(argv[arg])) != NoSymbol) { 699 | pNewSticky = (PSTICKY)xmalloc(sizeof(STICKY)); 700 | pNewSticky->pNext = stickies; 701 | pNewSticky->keysym = keysym; 702 | stickies = pNewSticky; 703 | 704 | debug("will press/release sticky key: %s\n", argv[arg]); 705 | } else { 706 | printf("x2x: warning: can't translate %s\n", argv[arg]); 707 | } 708 | } else if (!strcasecmp(argv[arg], "-buttonmap")) { 709 | if (++arg >= argc) Usage(); 710 | button = atoi(argv[arg]); 711 | 712 | if ((button < 1) || (button > N_BUTTONS)) 713 | printf("x2x: warning: invalid button %d\n", button); 714 | else if (++arg >= argc) 715 | Usage(); 716 | else 717 | { 718 | debug("will map button %d to keysyms '%s'\n", button, argv[arg]); 719 | 720 | argptr = argv[arg]; 721 | eventno = 0; 722 | while ((keyname = strtok(argptr, " \t\n\r")) != NULL) 723 | { 724 | if ((keysym = XStringToKeysym(keyname)) == NoSymbol) 725 | printf("x2x: warning: can't translate %s\n", keyname); 726 | else if (eventno + 1 >= MAX_BUTTONMAPEVENTS) 727 | printf("x2x: warning: too many keys mapped to button %d\n", 728 | button); 729 | else 730 | buttonmap[button][eventno++] = keysym; 731 | argptr = NULL; 732 | } 733 | buttonmap[button][eventno] = NoSymbol; 734 | } 735 | } else if (!strcasecmp(argv[arg], "-resurface")) { 736 | doResurface = True; 737 | 738 | debug("will resurface the trigger window when obscured\n"); 739 | } else if (!strcasecmp(argv[arg], "-win-output")) { 740 | doInputOnly = False; 741 | debug("trigger window will be an InputOutput window\n"); 742 | } else if (!strcasecmp(argv[arg], "-win-transparent")) { 743 | winTransparent = True; 744 | debug("trigger window will be transparent\n"); 745 | } else if (!strcasecmp(argv[arg], "-shadow")) { 746 | if (++arg >= argc) Usage(); 747 | pShadow = (PSHADOW)xmalloc(sizeof(SHADOW)); 748 | pShadow->DPMSstatus = -1; 749 | pShadow->name = argv[arg]; 750 | 751 | /* into the global list of shadows */ 752 | pShadow->pNext = shadows; 753 | shadows = pShadow; 754 | 755 | } else if (!strcasecmp(argv[arg], "-triggerw")) { 756 | if (++arg >= argc) Usage(); 757 | triggerw = atoi(argv[arg]); 758 | } else if (!strcasecmp(argv[arg], "-copyright")) { 759 | puts(lawyerese); 760 | } else if (!strcasecmp(argv[arg], "-noscale")) { 761 | noScale = True; 762 | } else if (!strcasecmp(argv[arg], "-completeregionleft")) { 763 | if (++arg >= argc) Usage(); 764 | compRegLeft = atoi(argv[arg]); 765 | } else if (!strcasecmp(argv[arg], "-completeregionright")) { 766 | if (++arg >= argc) Usage(); 767 | compRegRight = atoi(argv[arg]); 768 | } else if (!strcasecmp(argv[arg], "-completeregionup")) { 769 | if (++arg >= argc) Usage(); 770 | compRegUp = atoi(argv[arg]); 771 | } else if (!strcasecmp(argv[arg], "-completeregionlow")) { 772 | if (++arg >= argc) Usage(); 773 | compRegLow = atoi(argv[arg]); 774 | 775 | } else if (!strcasecmp(argv[arg], "-struts")) { 776 | useStruts = True; 777 | 778 | debug("will advertise struts in _NET_WM_STRUT\n"); 779 | } else { 780 | Usage(); 781 | } /* END if... */ 782 | } /* END for */ 783 | 784 | } /* END ParseCommandLine */ 785 | 786 | static void Usage() 787 | { 788 | #ifdef WIN_2_X 789 | printf("Usage: x2x [-fromwin | -from ][-to ] options..\n"); 790 | #else 791 | printf("Usage: x2x [-to | -from ] options...\n"); 792 | #endif 793 | printf(" -copyright\n"); 794 | printf(" -font \n"); 795 | printf(" -geometry \n"); 796 | printf(" -wait\n"); 797 | printf(" -big\n"); 798 | printf(" -buttonblock\n"); 799 | printf(" -nomouse\n"); 800 | printf(" -nopointermap\n"); 801 | printf(" -north\n"); 802 | printf(" -south\n"); 803 | printf(" -east\n"); 804 | printf(" -west\n"); 805 | printf(" -nosel\n"); 806 | printf(" -noautoup\n"); 807 | printf(" -resurface\n"); 808 | printf(" -win-output\n"); 809 | printf(" -win-transparent\n"); 810 | printf(" -capslockhack\n"); 811 | printf(" -nocapslockhack\n"); 812 | printf(" -clipcheck\n"); 813 | printf(" -shadow \n"); 814 | printf(" -sticky \n"); 815 | printf(" -label