From c41ab764b8557eb888ab5acfcac281b1d9e4822f Mon Sep 17 00:00:00 2001
From: runge <runge>
Date: Thu, 29 Jul 2004 01:04:27 +0000
Subject:  x11vnc: -add_keysyms dynamically add missing keysyms to X server

---
 ChangeLog        |   3 ++
 x11vnc/ChangeLog |   3 ++
 x11vnc/x11vnc.c  | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 152 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index 43a7407..9f81ac6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+2004-07-28  Karl Runge <runge@karlrunge.com>
+	* x11vnc: -add_keysyms dynamically add missing keysyms to X server
+
 2004-07-26  Karl Runge <runge@karlrunge.com>
 	* x11vnc: first pass at doing modtweak via XKEYBOARD extension (-xkb)
 	* -skip_keycodes; reset modtweaks on event MappingNotify.
diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog
index 51e517a..ceeeb97 100644
--- a/x11vnc/ChangeLog
+++ b/x11vnc/ChangeLog
@@ -1,3 +1,6 @@
+2004-07-28  Karl Runge <runge@karlrunge.com>
+	* -add_keysyms dynamically add missing keysyms to X server
+
 2004-07-26  Karl Runge <runge@karlrunge.com>
 	* first pass at doing modtweak via XKEYBOARD extension (-xkb)
 	* -skip_keycodes option for use with -xkb
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c
index 44bcb80..f2f3b2b 100644
--- a/x11vnc/x11vnc.c
+++ b/x11vnc/x11vnc.c
@@ -156,7 +156,7 @@
 #endif
 
 /*        date +'"lastmod:    %Y-%m-%d";' */
-char lastmod[] = "lastmod:    2004-07-26";
+char lastmod[] = "lastmod:    2004-07-28";
 
 /* X display info */
 Display *dpy = 0;
@@ -257,6 +257,10 @@ void clear_modifiers(int init);
 void clear_keys(void);
 void copy_screen(void);
 
+int add_keysym(KeySym);
+void delete_keycode(KeyCode);
+void delete_added_keycodes(void);
+
 double dtime(double *);
 
 void initialize_blackout(char *);
@@ -347,6 +351,7 @@ int xkbcompat = 0;		/* ignore XKEYBOARD extension */
 int use_xkb = 0;		/* try to open Xkb connection (for bell or other) */
 int use_xkb_modtweak = 0;	/* -xkb */
 char *skip_keycodes = NULL;
+int add_keysyms = 0;		/* automatically add keysyms to X server */
 
 int old_pointer = 0;		/* use the old way of updating the pointer */
 int single_copytile = 0;	/* use the old way copy_tiles() */
@@ -476,6 +481,9 @@ void clean_up_exit (int ret) {
 		}
 	}
 
+	/* X keyboard cleanups */
+	delete_added_keycodes();
+
 	if (clear_mods == 1) {
 		clear_modifiers(0);
 	} else if (clear_mods == 2) {
@@ -537,6 +545,10 @@ static void interrupted (int sig) {
 			break;
 		}
 	}
+
+	/* X keyboard cleanups */
+	delete_added_keycodes();
+
 	if (clear_mods == 1) {
 		clear_modifiers(0);
 	} else if (clear_mods == 2) {
@@ -1810,6 +1822,107 @@ void clear_keys(void) {
 	XFlush(dpy);
 }
 		
+static KeySym added_keysyms[0x100];
+
+int add_keysym(KeySym keysym) {
+	int minkey, maxkey, syms_per_keycode;
+	int kc, n, ret = 0;
+	static int first = 1;
+	KeySym *keymap;
+
+	if (first) {
+		for (n=0; n < 0x100; n++) {
+			added_keysyms[n] = NoSymbol;
+		}
+		first = 0;
+	}
+	if (keysym == NoSymbol) {
+		return 0;
+	}
+
+	XDisplayKeycodes(dpy, &minkey, &maxkey);
+	keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
+	    &syms_per_keycode);
+
+	for (kc = minkey+1; kc <= maxkey; kc++) {
+		int i, is_empty = 1;
+		char *str;
+		KeySym new[8];
+
+		for (n=0; n < syms_per_keycode; n++) {
+			if (keymap[ (kc-minkey) * syms_per_keycode + n]
+			    != NoSymbol) {
+				is_empty = 0;
+				break;
+			}
+		}
+		if (! is_empty) {
+			continue;
+		}
+
+		for (i=0; i<8; i++) {
+			new[i] = NoSymbol;
+		}
+		if (add_keysyms == 2) {
+			for(i=0; i < syms_per_keycode; i++) {
+				new[i] = keysym;
+				if (i >= 7) break;
+			}
+		} else {
+			new[0] = keysym;
+			
+		}
+
+		XChangeKeyboardMapping(dpy, kc, syms_per_keycode,
+		    new, 1);
+
+		str = XKeysymToString(keysym);
+		rfbLog("added missing keysym to X display: %03d 0x%x \"%s\"\n",
+		    kc, keysym, str ? str : "null");
+
+		XFlush(dpy);
+		added_keysyms[kc] = keysym;
+		ret = kc;
+		break;
+	}
+	XFree(keymap);
+	return ret;
+}
+
+void delete_keycode(KeyCode kc) {
+	int minkey, maxkey, syms_per_keycode, i;
+	KeySym *keymap;
+	KeySym ksym, new[8];
+	char *str;
+
+	XDisplayKeycodes(dpy, &minkey, &maxkey);
+	keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1),
+	    &syms_per_keycode);
+
+	for (i=0; i<8; i++) {
+		new[i] = NoSymbol;
+	}
+	XChangeKeyboardMapping(dpy, kc, syms_per_keycode, new, 1);
+
+	ksym = XKeycodeToKeysym(dpy, kc, 0);
+	str = XKeysymToString(ksym);
+	rfbLog("deleted keycode from X display: %03d 0x%x \"%s\"\n",
+	    kc, ksym, str ? str : "null");
+
+	XFree(keymap);
+	XFlush(dpy);
+}
+
+void delete_added_keycodes(void) {
+	int kc;
+	for (kc = 0; kc < 0x100; kc++) {
+		if (added_keysyms[kc] != NoSymbol) {
+			delete_keycode(kc);
+			added_keysyms[kc] = NoSymbol;
+		}
+	}
+}
+
 /*
  * The following is for an experimental -remap option to allow the user
  * to remap keystrokes.  It is currently confusing wrt modifiers...
@@ -2337,6 +2450,18 @@ static void xkb_tweak_keyboard(rfbBool down, rfbKeySym keysym,
 		got_kbstate = 1;
 		PKBSTATE
 	}
+
+	if (!found && add_keysyms && keysym && ! IsModifierKey(keysym)) {
+		int new_kc = add_keysym(keysym);
+		if (new_kc != 0) {
+			found = 1;
+			kc_f[0] = new_kc;
+			grp_f[0] = 0; 
+			lvl_f[0] = 0; 
+			state_f[0] = 0;
+		}
+	}
+
 	if (!found && debug_keyboard) {
 		char *str = XKeysymToString(keysym);
 		fprintf(stderr, "    *** NO key found for: 0x%x %s  "
@@ -2889,6 +3014,12 @@ static void modifier_tweak_keyboard(rfbBool down, rfbKeySym keysym,
 		k = XKeysymToKeycode(dpy, (KeySym) keysym);
 		X_UNLOCK;
 	}
+	if (k == NoSymbol && add_keysyms && ! IsModifierKey(keysym)) {
+		int new_kc = add_keysym(keysym);
+		if (new_kc) {
+			k = new_kc;
+		}
+	}
 	if (debug_keyboard) {
 		rfbLog("modifier_tweak_keyboard: KeySym 0x%x \"%s\" -> "
 		    "KeyCode 0x%x%s\n", (int) keysym, XKeysymToString(keysym),
@@ -2993,6 +3124,12 @@ void keyboard(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
 
 	k = XKeysymToKeycode(dpy, (KeySym) keysym);
 
+	if (k == NoSymbol && add_keysyms && ! IsModifierKey(keysym)) {
+		int new_kc = add_keysym(keysym);
+		if (new_kc) {
+			k = new_kc;
+		}
+	}
 	if (debug_keyboard) {
 		char *str = XKeysymToString(keysym);
 		rfbLog("keyboard(): KeySym 0x%x \"%s\" -> KeyCode 0x%x%s\n",
@@ -3846,6 +3983,7 @@ void watch_xevents(void) {
 	}
 
 	if (XCheckTypedEvent(dpy, MappingNotify, &xev)) {
+		XRefreshKeyboardMapping((XMappingEvent *) &xev);
 		if (use_modifier_tweak) {
 			X_UNLOCK;
 			initialize_modtweak();
@@ -7838,6 +7976,10 @@ static void print_help(void) {
 "                       keycodes.  Use this option to help x11vnc in the reverse\n"
 "                       problem it tries to solve: Keysym -> Keycode(s) when\n"
 "                       ambiguities exist.  E.g. -skip_keycodes 94,114\n"
+"-add_keysyms           If a keysym is received from a VNC viewer, but\n"
+"                       that keysym does not exist in the X server, then\n"
+"                       add the keysym to the X server's keyboard mapping.\n"
+"                       Added keysyms will be removed when exiting.\n"
 #if 0
 "-xkbcompat             Ignore the XKEYBOARD extension.  Use as a workaround for\n"
 "                       some keyboard mapping problems.  E.g. if you are using\n"
@@ -8394,6 +8536,8 @@ int main(int argc, char* argv[]) {
 			skip_keycodes = argv[++i];
 		} else if (!strcmp(arg, "-xkbcompat")) {
 			xkbcompat = 1;
+		} else if (!strcmp(arg, "-add_keysyms")) {
+			add_keysyms++;
 		} else if (!strcmp(arg, "-clear_mods")) {
 			clear_mods = 1;
 		} else if (!strcmp(arg, "-clear_keys")) {
@@ -8751,6 +8895,7 @@ int main(int argc, char* argv[]) {
 		fprintf(stderr, "xkb:        %d\n", use_xkb_modtweak);
 		fprintf(stderr, "skipkeys:   %s\n", skip_keycodes ? skip_keycodes
                     : "null");
+		fprintf(stderr, "addkeysyms: %d\n", add_keysyms);
 		fprintf(stderr, "xkbcompat:  %d\n", xkbcompat);
 		fprintf(stderr, "clearmods:  %d\n", clear_mods);
 		fprintf(stderr, "remap:      %s\n", remap_file ? remap_file
-- 
cgit v1.2.3

