From ce2fdb720d45aa9ddebc277542166d71d7888650 Mon Sep 17 00:00:00 2001
From: dscho <dscho>
Date: Thu, 19 Dec 2002 14:40:13 +0000
Subject: new version of x11vnc from Karl Runge

---
 contrib/x11vnc.c | 201 ++++++++++++++++++++++++++++++++++++++++++++-----------
 contrib/zippy.c  |   2 +-
 2 files changed, 164 insertions(+), 39 deletions(-)

diff --git a/contrib/x11vnc.c b/contrib/x11vnc.c
index c937a22..e5367db 100644
--- a/contrib/x11vnc.c
+++ b/contrib/x11vnc.c
@@ -1,5 +1,5 @@
 /*
- * x0vnc.c: a VNC server for X displays.
+ * x11vnc.c: a VNC server for X displays.
  *
  * Copyright (c) 2002 Karl J. Runge <runge@karlrunge.com>  All rights reserved.
  *
@@ -21,45 +21,30 @@
  *
  * This program is based heavily on the following programs:
  *
- *       original x11vnc.c of the libvncserver project (Johannes E. Schindelin)
+ *       the originial x11vnc.c in libvncserver (Johannes E. Schindelin)
  *       krfb, the KDE desktopsharing project (Tim Jansen)
  *	 x0rfbserver, the original native X vnc server (Jens Wagner)
  *
  * The primary goal of this program is to create a portable and simple
  * command-line server utility that allows a VNC viewer to connect to an
- * actual X display (as x11vnc, krfb, and x0rfbserver do).  The only
- * non-standard dependency of this program is the static library
- * libvncserver.a (although in some environments libjpeg.so may not be
- * readily available).  To increase portability it is written in plain C.
+ * actual X display (as the above do).  The only non-standard dependency
+ * of this program is the static library libvncserver.a (although in
+ * some environments libjpeg.so may not be readily available and needs
+ * to be installed, it may be found at ftp://ftp.uu.net/graphics/jpeg/).
+ * To increase portability it is written in plain C.
  *
  * The next goal is to improve performance and interactive response.
  * The algorithm currently used here to achieve this is that of krfb
  * (based on x0rfbserver algorithm).  Additional heuristics are also
- * applied.  Currently there are a bit too many of these...
+ * applied (currently there are a bit too many of these...)
  *
  * To build:
- * Obtain the libvncserver package (http://libvncserver.sourceforge.net)
- * and ensure that "make" and "make x11vnc" work correctly.  Defining
- * HAVE_PTHREADS in the Makefile is recommended.  One then could move the
- * x11vnc.c file aside, copy this file in its place into the source tree,
- * and issue:
- *
- *	make x11vnc
- *	mv x11vnc x0vnc
- *
- * to create the x0vnc binary.  Otherwise, with x0vnc.c copied to
- * libvncserver source directory, something like this should work:
- *
- * gcc -Wall  -DALLOW24BPP -I.  -DBACKCHANNEL -c x0vnc.c
- * gcc -o x0vnc x0vnc.o  -L. -lvncserver -L/usr/local/lib -lz -ljpeg \
- *     -L/usr/X11R6/lib -lX11 -lXext -lXtst
- *
- * include -DHAVE_PTHREADS ... -lpthread to use threads.
- *
- * On Solaris the 2nd command might look something like:
- *
- * gcc -o x0vnc x0vnc.o -L. -lvncserver -L/usr/local/lib -lz -ljpeg \
- *     -lsocket -lnsl -L/usr/X/lib -R/usr/X/lib -lX11 -lXext -lXtst 
+ * Obtain the libvncserver package (http://libvncserver.sourceforge.net).
+ * As of 12/2002 this version of x11vnc.c is contained in the libvncserver
+ * CVS tree.  Parameters in the Makefile should be adjusted to the build
+ * system and then "make x11vnc" should create it.  For earlier releases
+ * (say libvncserver-0.4) this file may be inserted in place of the
+ * original x11vnc.c file.
  */
 
 #include <unistd.h>
@@ -71,11 +56,24 @@
 #include <X11/extensions/XTest.h>
 #include <X11/keysym.h>
 
+/*
+ * Work around Bool and KeySym same names in X and rfb.
+ * Bool is #define int in <X11/Xlib.h>
+ * KeySym is typedef XID in <X11/X.h>
+ * (note that X and rfb KeySym types are the same so a bit silly to worry...
+ * the Bool types are different though)
+ */
+typedef Bool X_Bool;
+typedef KeySym X_KeySym;
+
+/* the #define Bool can be removed: */
 #ifdef Bool
 #undef Bool
 #endif
-#define Bool RFBBool
+
+/* the KeySym typedef cannot be removed, so use an alias for rest of file: */
 #define KeySym RFBKeySym
+
 #include "rfb.h"
 
 Display *dpy = 0;
@@ -129,6 +127,8 @@ int shared = 0;		/* share vnc display. */
 int view_only = 0;	/* client can only watch. */
 int connect_once = 1;	/* allow only one client connection. */
 
+int use_altgr = 0;	/* use the altgr_keyboard modifier tweak */
+
 /*
  * waitms is the msec to wait between screen polls.  Not too old h/w shows
  * poll times of 15-35ms, so maybe this value cuts the rest load by 2 or so.
@@ -143,7 +143,7 @@ int tile_fuzz = 2;	/* tolerance for suspecting changed tiles touching */
 			/* a known changed tile. */
 int grow_fill = 3;	/* do the grow islands heuristic with this width. */
 int gaps_fill = 4;	/* do a final pass to try to fill gaps between tiles. */
-double fs_frac = 0.5;	/* threshold tile fraction to do fullscreen updates. */
+double fs_frac = 0.6;	/* threshold tile fraction to do fullscreen updates. */
 
 #define NSCAN 32
 int scanlines[NSCAN] = {	 /* scan pattern jitter from x0rfbserver */
@@ -217,6 +217,115 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
 	return(RFB_CLIENT_ACCEPT);
 }
 
+/* For tweaking modifiers wrt the Alt-Graph key */
+
+#define LEFTSHIFT 1
+#define RIGHTSHIFT 2
+#define ALTGR 4
+char mod_state = 0;
+
+char modifiers[0x100];
+KeyCode keycodes[0x100], left_shift_code, right_shift_code, altgr_code;
+
+void initialize_keycodes() {
+	X_KeySym key, *keymap;
+	int i, j, minkey, maxkey, syms_per_keycode;
+
+	memset(modifiers, -1, sizeof(modifiers));
+
+	XDisplayKeycodes(dpy, &minkey, &maxkey);
+
+	keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
+	    &syms_per_keycode);
+
+	for (i = minkey; i <= maxkey; i++) {
+		for (j = 0; j < syms_per_keycode; j++) {
+			key = keymap[ (i - minkey) * syms_per_keycode + j ];
+			if ( key >= ' ' && key < 0x100
+			    && i == XKeysymToKeycode(dpy, key) ) {
+				keycodes[key] = i;
+				modifiers[key] = j;
+			}
+		}
+	}
+
+	left_shift_code = XKeysymToKeycode(dpy, XK_Shift_L);
+	right_shift_code = XKeysymToKeycode(dpy, XK_Shift_R);
+	altgr_code = XKeysymToKeycode(dpy, XK_Mode_switch);
+
+	XFree ((void *) keymap);
+}
+
+void tweak_mod(char mod, Bool down) {
+	Bool is_shift = mod_state & (LEFTSHIFT|RIGHTSHIFT);
+	X_Bool dn = (X_Bool) down;
+
+	if (mod < 0) {
+		return;
+	}
+
+	X_LOCK
+	if (is_shift && mod != 1) {
+	    if (mod_state & LEFTSHIFT) {
+		XTestFakeKeyEvent(dpy, left_shift_code, !dn, CurrentTime);
+	    }
+	    if (mod_state & RIGHTSHIFT) {
+		XTestFakeKeyEvent(dpy, right_shift_code, !dn, CurrentTime);
+	    }
+	}
+	if ( ! is_shift && mod == 1 ) {
+		XTestFakeKeyEvent(dpy, left_shift_code, dn, CurrentTime);
+	}
+	if ( (mod_state & ALTGR) && mod != 2 ) {
+		XTestFakeKeyEvent(dpy, altgr_code, !dn, CurrentTime);
+	}
+	if ( ! (mod_state & ALTGR) && mod == 2 ) {
+		XTestFakeKeyEvent(dpy, altgr_code, dn, CurrentTime);
+	}
+	X_UNLOCK
+}
+
+static void altgr_keyboard(Bool down, KeySym keysym, rfbClientPtr client) {
+	KeyCode k;
+	int tweak = 0;
+
+	if (view_only) {
+		return;
+	}
+
+#define ADJUSTMOD(sym, state) \
+	if (keysym == sym) { \
+		if (down) { \
+			mod_state |= state; \
+		} else { \
+			mod_state &= ~state; \
+		} \
+	}
+
+	ADJUSTMOD(XK_Shift_L, LEFTSHIFT)
+	ADJUSTMOD(XK_Shift_R, RIGHTSHIFT)
+	ADJUSTMOD(XK_Mode_switch, ALTGR)
+
+	if ( down && keysym >= ' ' && keysym < 0x100 ) {
+		tweak = 1;
+		tweak_mod(modifiers[keysym], True);
+		k = keycodes[keysym];
+	} else {
+		X_LOCK
+		k = XKeysymToKeycode(dpy, (X_KeySym) keysym);
+		X_UNLOCK
+	}
+	if ( k != NoSymbol ) {
+		X_LOCK
+		XTestFakeKeyEvent(dpy, k, (X_Bool) down, CurrentTime);
+		X_UNLOCK
+	}
+
+	if ( tweak ) {
+		tweak_mod(modifiers[keysym], False);
+	}
+}
+
 /* key event handler */
 static void keyboard(Bool down, KeySym keysym, rfbClientPtr client) {
 	KeyCode k;
@@ -224,19 +333,23 @@ static void keyboard(Bool down, KeySym keysym, rfbClientPtr client) {
 	if (view_only) {
 		return;
 	}
+	
+	if (use_altgr) {
+		altgr_keyboard(down, keysym, client);
+		return;
+	}
 
 	X_LOCK
 
-	/* KeySym is XID in <X11/X.h> */
-	k = XKeysymToKeycode(dpy, (XID) keysym);
+	k = XKeysymToKeycode(dpy, (X_KeySym) keysym);
 
 	if ( k != NoSymbol ) {
-		/* Bool is int in <X11/Xlib.h> */
-		XTestFakeKeyEvent(dpy, k, (int) down, CurrentTime);
+		XTestFakeKeyEvent(dpy, k, (X_Bool) down, CurrentTime);
 		XFlush(dpy);
 
 		got_user_input++;
 	}
+
 	X_UNLOCK
 }
 
@@ -1212,7 +1325,7 @@ void watch_loop(void) {
 
 void print_help() {
 	char help[] = 
-"x0vnc options:\n"
+"x11vnc options:\n"
 "\n"
 "-defer time            time in ms to wait for updates before sending to\n"
 "                       client [rfbDeferUpdateTime]  (default %d)\n"
@@ -1231,6 +1344,9 @@ void print_help() {
 "                       horizontal tiles into one big rectangle)  (default %s).\n"
 "-nohints               do not use hints; send each tile separately.\n"
 "\n"
+"-altgr                 use a mechanism to properly handle the AltGr modifier\n"
+"                       on certain keyboards (default %d).\n"
+"-noaltgr               send the keysym directly to the X server.\n"
 "-threads               use threaded algorithm [rfbRunEventLoop] if compiled\n"
 "                       with threads (default %s).\n"
 "-nothreads             do not use [rfbRunEventLoop].\n"
@@ -1242,8 +1358,9 @@ void print_help() {
 ;
 	fprintf(stderr, help, defer_update, waitms, gaps_fill, grow_fill,
 	    fs_frac, tile_fuzz,
-	    use_hints ? "on":"off", use_threads ? "on":"off",
-	    view_only ? "on":"off", shared ? "on":"off");
+	    use_hints ? "on":"off", use_altgr ? "on":"off",
+	    use_threads ? "on":"off", view_only ? "on":"off",
+	    shared ? "on":"off");
 	rfbUsage();
 	exit(1);
 }
@@ -1282,6 +1399,10 @@ int main(int argc, char** argv) {
 			use_threads = 1;
 		} else if (!strcmp(argv[i], "-nothreads")) {
 			use_threads = 0;
+		} else if (!strcmp(argv[i], "-altgr")) {
+			use_altgr = 1;
+		} else if (!strcmp(argv[i], "-noaltgr")) {
+			use_altgr = 0;
 		} else if (!strcmp(argv[i], "-viewonly")) {
 			view_only = 1;
 		} else if (!strcmp(argv[i], "-shared")) {
@@ -1370,6 +1491,10 @@ int main(int argc, char** argv) {
 
 	initialize_shm();
 
+	if (use_altgr) {
+		initialize_keycodes();
+	}
+
 	printf("screen setup finished.\n");
 
 	watch_loop();
diff --git a/contrib/zippy.c b/contrib/zippy.c
index 58ad3ee..ff2d042 100644
--- a/contrib/zippy.c
+++ b/contrib/zippy.c
@@ -139,7 +139,7 @@ void linecount (char* frame_buffer)
 
 void on_key_press (Bool down,KeySym key,rfbClientPtr cl)
 {
-        if (down)		//or else the action occurs on both the press and depress
+        if (down)		/* or else the action occurs on both the press and depress */
 	switch (key) {
 
         case XK_b:
-- 
cgit v1.2.3

