This patch provides support for the U... keysyms in latter XFree86 (?)
and X.org which represent UCS characters.  It's for Emacs 22 but may
apply simply to Emacs 21.

2005-09-29  Dave Love  <fx@gnu.org>

	* keyboard.c (Qucs, Qdecode_char): New.
	(syms_of_keyboard): Initialize them.
	(read_key_sequence): Deal with U... keysyms.

	* xterm.c (charset_0100_24ff, charset_2500_33ff)
	(charset_e000_ffff): New variables.
	(decode_ucs_keysym): New function.
	(handle_one_xevent): Use it.

Index: xterm.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/xterm.c,v
retrieving revision 1.873
diff -u -p -r1.873 xterm.c
--- xterm.c	16 Aug 2005 19:34:00 -0000	1.873
+++ xterm.c	29 Sep 2005 18:43:12 -0000
@@ -304,6 +304,9 @@ extern int errno;
 
 extern EMACS_INT extra_keyboard_modifiers;
 
+/* Charset ids for decoding.  */
+static int charset_0100_24ff, charset_2500_33ff, charset_e000_ffff;
+
 /* The keysyms to use for the various modifiers.  */
 
 Lisp_Object Vx_alt_keysym, Vx_hyper_keysym, Vx_meta_keysym, Vx_super_keysym;
@@ -5702,6 +5705,56 @@ event_handler_gdk (gxev, ev, data)
 }
 #endif /* USE_GTK */
 
+static int
+decode_ucs_keysym (KeySym keysym, struct input_event *inev)
+{
+  if (charset_0100_24ff == 0)
+    {
+      charset_0100_24ff = get_charset_id (intern ("mule-unicode-0100-24ff"));
+      charset_2500_33ff = get_charset_id (intern ("mule-unicode-2500-33ff"));
+      charset_e000_ffff = get_charset_id (intern ("mule-unicode-e000-ffff"));
+    }
+  keysym -= 0x1000000;
+  if (keysym < 128)
+    {
+      inev->kind = ASCII_KEYSTROKE_EVENT;
+      inev->code = keysym;
+    }
+  if (keysym < 160)
+    {
+      inev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
+      inev->code = keysym;
+    }
+  else if (keysym < 256)
+    {
+      inev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
+      inev->code = MAKE_CHAR (charset_latin_iso8859_1, keysym, 0);
+    }
+  else if (keysym < 0x2500)
+    {
+      keysym -= 0x100;
+      inev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
+      inev->code = MAKE_CHAR (charset_0100_24ff, keysym/96 + 32,
+			      (keysym % 96) + 32);
+    }
+  else if (keysym < 0x3400)
+    {
+      keysym -= 0x3400;
+      inev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
+      inev->code = MAKE_CHAR (charset_2500_33ff, keysym/96 + 32,
+			      (keysym % 96) + 32);
+    }
+  else if ((keysym >= 0xe000) && (keysym <= 0xffff))
+    {
+      keysym -= 0xe000;
+      inev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
+      inev->code = MAKE_CHAR (charset_e000_ffff, keysym/96 + 32,
+			      (keysym % 96) + 32);
+    }
+  else
+    return 1;
+  return 0;
+}
 
 /* Handles the XEvent EVENT on display DPYINFO.
 
@@ -6307,6 +6360,16 @@ handle_one_xevent (dpyinfo, eventp, fini
 	    }
 
 	  /* Now non-ASCII.  */
+
+	  /* Deal with the UCS keysyms supported by versions of X (but
+	     not obviously documented...).  We can't call Lisp
+	     (decode-char) here, but deal with any we can immediately
+	     to avoid consing key symbols.  Anything left over (like
+	     CJK) gets a chance to be decoded in read_key_sequence.  */
+	  if ((keysym > 0x1000000) && (keysym < 0x2000000))
+	    if (0 == decode_ucs_keysym (keysym, &inev.ie))
+	      goto done_keysym;
+
 	  if (HASH_TABLE_P (Vx_keysym_table)
 	      && (NATNUMP (c = Fgethash (make_number (keysym),
 					 Vx_keysym_table,
Index: keyboard.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/keyboard.c,v
retrieving revision 1.836
diff -u -p -r1.836 keyboard.c
--- keyboard.c	25 Aug 2005 08:20:12 -0000	1.836
+++ keyboard.c	29 Sep 2005 18:43:14 -0000
@@ -593,6 +593,8 @@ int timers_run;
 
 extern Lisp_Object Vprint_level, Vprint_length;
 
+static Lisp_Object Qucs, Qdecode_char;
+
 /* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
    happens.  */
 EMACS_TIME *input_available_clear_time;
@@ -8818,6 +8820,26 @@ read_key_sequence (keybuf, bufsize, prom
 	    key = read_char (NILP (prompt), nmaps,
 			     (Lisp_Object *) submaps, last_nonmenu_event,
 			     &used_mouse_menu);
+	    if (SYMBOLP (key))
+	      {
+		char *s = SDATA (SYMBOL_NAME (key));
+		if (s[0] == 'U')
+		  {
+		    /* Deal with Uxxxx keysyms from X (where X can be the
+		       full Unicode range).  */
+		    unsigned u; char c;
+		    if (2 == sscanf (s, "U%x%n", &u, &c) &&
+			(c == strlen (s)))
+		      {
+			Lisp_Object args[3], code;
+			args[0] = Qdecode_char;
+			args[1] = Qucs;
+			args[2] = make_number ((EMACS_INT) u);
+			if (!NILP (code = Ffuncall (3, args)))
+			  key = code;
+		      }
+		  }
+	      }
 	  }
 
 	  /* read_char returns t when it shows a menu and the user rejects it.
@@ -10935,6 +10957,11 @@ syms_of_keyboard ()
   staticpro (&Qinput_method_exit_on_first_char);
   Qinput_method_use_echo_area = intern ("input-method-use-echo-area");
   staticpro (&Qinput_method_use_echo_area);
+
+  Qucs = intern ("ucs");
+  staticpro (&Qucs);
+  Qdecode_char = intern ("decode-char");
+  staticpro (&Qdecode_char);
 
   Fset (Qinput_method_exit_on_first_char, Qnil);
   Fset (Qinput_method_use_echo_area, Qnil);
