Merge from emacs--devo--0
[bpt/emacs.git] / src / keymap.c
index 1d854f7..b4f7488 100644 (file)
@@ -1,13 +1,13 @@
 /* Manipulation of keymaps
    Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
                  1998, 1999, 2000, 2001, 2002, 2003, 2004,
-                 2005, 2006 Free Software Foundation, Inc.
+                 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -23,16 +23,21 @@ Boston, MA 02110-1301, USA.  */
 
 #include <config.h>
 #include <stdio.h>
+#if HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
 #include "lisp.h"
 #include "commands.h"
 #include "buffer.h"
 #include "charset.h"
 #include "keyboard.h"
+#include "frame.h"
 #include "termhooks.h"
 #include "blockinput.h"
 #include "puresize.h"
 #include "intervals.h"
 #include "keymap.h"
+#include "window.h"
 
 /* The number of elements in keymap vectors.  */
 #define DENSE_TABLE_SIZE (0200)
@@ -86,14 +91,6 @@ Lisp_Object Vminor_mode_overriding_map_alist;
 /* List of emulation mode keymap alists.  */
 Lisp_Object Vemulation_mode_map_alists;
 
-/* Keymap mapping ASCII function key sequences onto their preferred forms.
-   Initialized by the terminal-specific lisp files.  See DEFVAR for more
-   documentation.  */
-Lisp_Object Vfunction_key_map;
-
-/* Keymap mapping ASCII function key sequences onto their preferred forms.  */
-Lisp_Object Vkey_translation_map;
-
 /* A list of all commands given new bindings since a certain time
    when nil was stored here.
    This is used to speed up recomputation of menu key equivalents
@@ -425,7 +422,7 @@ Return PARENT.  PARENT should be nil or another keymap.  */)
 
       if (CHAR_TABLE_P (XCAR (list)))
        {
-         Lisp_Object indices[3];
+         int indices[3];
 
          map_char_table (fix_submap_inheritance, Qnil,
                          XCAR (list), XCAR (list),
@@ -724,7 +721,7 @@ map_keymap (map, fun, args, data, autoload)
        }
       else if (CHAR_TABLE_P (binding))
        {
-         Lisp_Object indices[3];
+         int indices[3];
          map_char_table (map_keymap_char_table_item, Qnil, binding, binding,
                          Fcons (make_save_value (fun, 0),
                                 Fcons (make_save_value (data, 0),
@@ -746,7 +743,10 @@ map_keymap_call (key, val, fun, dummy)
 DEFUN ("map-keymap", Fmap_keymap, Smap_keymap, 2, 3, 0,
        doc: /* Call FUNCTION once for each event binding in KEYMAP.
 FUNCTION is called with two arguments: the event that is bound, and
-the definition it is bound to.
+the definition it is bound to.  If the event is an integer, it may be
+a generic character (see Info node `(elisp)Splitting Characters'), and
+that means that all actual character events belonging to that generic
+character are bound to the definition.
 
 If KEYMAP has a parent, the parent's bindings are included as well.
 This works recursively: if the parent has itself a parent, then the
@@ -1072,7 +1072,7 @@ is not copied.  */)
       Lisp_Object elt = XCAR (keymap);
       if (CHAR_TABLE_P (elt))
        {
-         Lisp_Object indices[3];
+         int indices[3];
          elt = Fcopy_sequence (elt);
          map_char_table (copy_keymap_1, Qnil, elt, elt, elt, 0, indices);
        }
@@ -1117,7 +1117,9 @@ DEF is anything that can be a key's definition:
     or another symbol whose function definition is used, etc.),
  a cons (STRING . DEFN), meaning that DEFN is the definition
     (DEFN should be a valid definition in its own right),
- or a cons (MAP . CHAR), meaning use definition of CHAR in keymap MAP.
+ or a cons (MAP . CHAR), meaning use definition of CHAR in keymap MAP,
+ or an extended menu item definition.
+ (See info node `(elisp)Extended Menu Items'.)
 
 If KEYMAP is a sparse keymap with a binding for KEY, the existing
 binding is altered.  If there is no binding for KEY, the new pair
@@ -1147,9 +1149,10 @@ binding KEY to DEF is added at the front of KEYMAP.  */)
   if (SYMBOLP (def) && !EQ (Vdefine_key_rebound_commands, Qt))
     Vdefine_key_rebound_commands = Fcons (def, Vdefine_key_rebound_commands);
 
-  meta_bit = VECTORP (key) ? meta_modifier : 0x80;
+  meta_bit = (VECTORP (key) || (STRINGP (key) && STRING_MULTIBYTE (key))
+             ? meta_modifier : 0x80);
 
-  if (VECTORP (def) && ASIZE (def) > 0 && CONSP (AREF (def, make_number (0))))
+  if (VECTORP (def) && ASIZE (def) > 0 && CONSP (AREF (def, 0)))
     { /* DEF is apparently an XEmacs-style keyboard macro.  */
       Lisp_Object tmp = Fmake_vector (make_number (ASIZE (def)), Qnil);
       int i = ASIZE (def);
@@ -1216,17 +1219,42 @@ binding KEY to DEF is added at the front of KEYMAP.  */)
 
 /* This function may GC (it calls Fkey_binding).  */
 
-DEFUN ("command-remapping", Fcommand_remapping, Scommand_remapping, 1, 1, 0,
-       doc: /* Return the remapping for command COMMAND in current keymaps.
-Returns nil if COMMAND is not remapped (or not a symbol).  */)
-     (command)
-     Lisp_Object command;
+DEFUN ("command-remapping", Fcommand_remapping, Scommand_remapping, 1, 3, 0,
+       doc: /* Return the remapping for command COMMAND.
+Returns nil if COMMAND is not remapped (or not a symbol).
+
+If the optional argument POSITION is non-nil, it specifies a mouse
+position as returned by `event-start' and `event-end', and the
+remapping occurs in the keymaps associated with it.  It can also be a
+number or marker, in which case the keymap properties at the specified
+buffer position instead of point are used.  The KEYMAPS argument is
+ignored if POSITION is non-nil.
+
+If the optional argument KEYMAPS is non-nil, it should be a list of
+keymaps to search for command remapping.  Otherwise, search for the
+remapping in all currently active keymaps.  */)
+     (command, position, keymaps)
+     Lisp_Object command, position, keymaps;
 {
   if (!SYMBOLP (command))
     return Qnil;
 
   ASET (command_remapping_vector, 1, command);
-  return Fkey_binding (command_remapping_vector, Qnil, Qt);
+
+  if (NILP (keymaps))
+    return Fkey_binding (command_remapping_vector, Qnil, Qt, position);
+  else
+    {
+      Lisp_Object maps, binding;
+
+      for (maps = keymaps; !NILP (maps); maps = Fcdr (maps))
+       {
+         binding = Flookup_key (Fcar (maps), command_remapping_vector, Qnil);
+         if (!NILP (binding) && !INTEGERP (binding))
+           return binding;
+       }
+      return Qnil;
+    }
 }
 
 /* Value is number if KEY is too long; nil if valid but has no definition. */
@@ -1234,7 +1262,8 @@ Returns nil if COMMAND is not remapped (or not a symbol).  */)
 
 DEFUN ("lookup-key", Flookup_key, Slookup_key, 2, 3, 0,
        doc: /* In keymap KEYMAP, look up key sequence KEY.  Return the definition.
-nil means undefined.  See doc of `define-key' for kinds of definitions.
+A value of nil means undefined.  See doc of `define-key'
+for kinds of definitions.
 
 A number as value means KEY is "too long";
 that is, characters or symbols in it except for the last one
@@ -1277,7 +1306,7 @@ recognize the default bindings, just as `read-key-sequence' does.  */)
        c = Fevent_convert_list (c);
 
       /* Turn the 8th bit of string chars into a meta modifier.  */
-      if (INTEGERP (c) && XINT (c) & 0x80 && STRINGP (key))
+      if (STRINGP (key) && XINT (c) & 0x80 && !STRING_MULTIBYTE (key))
        XSETINT (c, (XINT (c) | meta_modifier) & ~0x80);
 
       /* Allow string since binding for `menu-bar-select-buffer'
@@ -1386,8 +1415,10 @@ silly_event_symbol_error (c)
 static Lisp_Object *cmm_modes = NULL, *cmm_maps = NULL;
 static int cmm_size = 0;
 
-/* Store a pointer to an array of the keymaps of the currently active
-   minor modes in *buf, and return the number of maps it contains.
+/* Store a pointer to an array of the currently active minor modes in
+   *modeptr, a pointer to an array of the keymaps of the currently
+   active minor modes in *mapptr, and return the number of maps
+   *mapptr contains.
 
    This function always returns a pointer to the same buffer, and may
    free or reallocate it, so if you want to keep it for a long time or
@@ -1503,14 +1534,47 @@ current_minor_maps (modeptr, mapptr)
 }
 
 DEFUN ("current-active-maps", Fcurrent_active_maps, Scurrent_active_maps,
-       0, 1, 0,
+       0, 2, 0,
        doc: /* Return a list of the currently active keymaps.
 OLP if non-nil indicates that we should obey `overriding-local-map' and
-`overriding-terminal-local-map'.  */)
-     (olp)
-     Lisp_Object olp;
+`overriding-terminal-local-map'.  POSITION can specify a click position
+like in the respective argument of `key-binding'. */)
+    (olp, position)
+    Lisp_Object olp, position;
 {
-  Lisp_Object keymaps = Fcons (current_global_map, Qnil);
+  int count = SPECPDL_INDEX ();
+
+  Lisp_Object keymaps;
+
+  /* If a mouse click position is given, our variables are based on
+     the buffer clicked on, not the current buffer.  So we may have to
+     switch the buffer here. */
+  
+  if (CONSP (position))
+    {
+      Lisp_Object window;
+      
+      window = POSN_WINDOW (position);
+         
+      if (WINDOWP (window)
+         && BUFFERP (XWINDOW (window)->buffer)
+         && XBUFFER (XWINDOW (window)->buffer) != current_buffer)
+       {
+         /* Arrange to go back to the original buffer once we're done
+            processing the key sequence.  We don't use
+            save_excursion_{save,restore} here, in analogy to
+            `read-key-sequence' to avoid saving point.  Maybe this
+            would not be a problem here, but it is easier to keep
+            things the same.
+         */
+             
+         record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+         
+         set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
+       }
+    }
+
+  keymaps = Fcons (current_global_map, Qnil);  
 
   if (!NILP (olp))
     {
@@ -1524,15 +1588,76 @@ OLP if non-nil indicates that we should obey `overriding-local-map' and
     }
   if (NILP (XCDR (keymaps)))
     {
-      Lisp_Object local;
       Lisp_Object *maps;
       int nmaps, i;
 
-      /* This usually returns the buffer's local map,
-        but that can be overridden by a `local-map' property.  */
-      local = get_local_map (PT, current_buffer, Qlocal_map);
-      if (!NILP (local))
-       keymaps = Fcons (local, keymaps);
+      Lisp_Object keymap, local_map;
+      EMACS_INT pt;
+
+      pt = INTEGERP (position) ? XINT (position)
+       : MARKERP (position) ? marker_position (position)
+       : PT;
+
+      /* Get the buffer local maps, possibly overriden by text or
+        overlay properties */
+
+      local_map = get_local_map (pt, current_buffer, Qlocal_map); 
+      keymap = get_local_map (pt, current_buffer, Qkeymap); 
+
+      if (CONSP (position))
+       {
+         Lisp_Object string;
+
+         /* For a mouse click, get the local text-property keymap
+            of the place clicked on, rather than point.  */
+         
+         if (POSN_INBUFFER_P (position))
+           {
+             Lisp_Object pos;
+
+             pos = POSN_BUFFER_POSN (position);
+             if (INTEGERP (pos)
+                 && XINT (pos) >= BEG && XINT (pos) <= Z)
+               {
+                 local_map = get_local_map (XINT (pos),
+                                            current_buffer, Qlocal_map);
+                 
+                 keymap = get_local_map (XINT (pos),
+                                         current_buffer, Qkeymap);
+               }
+           }
+
+         /* If on a mode line string with a local keymap,
+            or for a click on a string, i.e. overlay string or a
+            string displayed via the `display' property,
+            consider `local-map' and `keymap' properties of
+            that string.  */
+         
+         if (string = POSN_STRING (position),
+             (CONSP (string) && STRINGP (XCAR (string))))
+           {
+             Lisp_Object pos, map;
+             
+             pos = XCDR (string);
+             string = XCAR (string);
+             if (INTEGERP (pos)
+                 && XINT (pos) >= 0
+                 && XINT (pos) < SCHARS (string))
+               {
+                 map = Fget_text_property (pos, Qlocal_map, string);
+                 if (!NILP (map))
+                   local_map = map;
+
+                 map = Fget_text_property (pos, Qkeymap, string);
+                 if (!NILP (map))
+                   keymap = map;
+               }
+           }
+         
+       }
+
+      if (!NILP (local_map))
+       keymaps = Fcons (local_map, keymaps);
 
       /* Now put all the minor mode keymaps on the list.  */
       nmaps = current_minor_maps (0, &maps);
@@ -1541,18 +1666,18 @@ OLP if non-nil indicates that we should obey `overriding-local-map' and
        if (!NILP (maps[i]))
          keymaps = Fcons (maps[i], keymaps);
 
-      /* This returns nil unless there is a `keymap' property.  */
-      local = get_local_map (PT, current_buffer, Qkeymap);
-      if (!NILP (local))
-       keymaps = Fcons (local, keymaps);
+      if (!NILP (keymap))
+       keymaps = Fcons (keymap, keymaps);
     }
 
+  unbind_to (count, Qnil);
+
   return keymaps;
 }
 
 /* GC is possible in this function if it autoloads a keymap.  */
 
-DEFUN ("key-binding", Fkey_binding, Skey_binding, 1, 3, 0,
+DEFUN ("key-binding", Fkey_binding, Skey_binding, 1, 4, 0,
        doc: /* Return the binding for command KEY in current keymaps.
 KEY is a string or vector, a sequence of keystrokes.
 The binding is probably a symbol with a function definition.
@@ -1566,51 +1691,82 @@ recognize the default bindings, just as `read-key-sequence' does.
 Like the normal command loop, `key-binding' will remap the command
 resulting from looking up KEY by looking up the command in the
 current keymaps.  However, if the optional third argument NO-REMAP
-is non-nil, `key-binding' returns the unmapped command.  */)
-     (key, accept_default, no_remap)
-     Lisp_Object key, accept_default, no_remap;
+is non-nil, `key-binding' returns the unmapped command.
+
+If KEY is a key sequence initiated with the mouse, the used keymaps
+will depend on the clicked mouse position with regard to the buffer
+and possible local keymaps on strings.
+
+If the optional argument POSITION is non-nil, it specifies a mouse
+position as returned by `event-start' and `event-end', and the lookup
+occurs in the keymaps associated with it instead of KEY.  It can also
+be a number or marker, in which case the keymap properties at the
+specified buffer position instead of point are used.
+  */)
+    (key, accept_default, no_remap, position)
+    Lisp_Object key, accept_default, no_remap, position;
 {
   Lisp_Object *maps, value;
   int nmaps, i;
-  struct gcpro gcpro1;
+  struct gcpro gcpro1, gcpro2;
+  int count = SPECPDL_INDEX ();
 
-  GCPRO1 (key);
+  GCPRO2 (key, position);
 
-#ifdef HAVE_MOUSE
-  if (VECTORP (key)
-      && ASIZE (key) > 0
-      && CONSP (AREF (key, 0))
-      && SYMBOLP (XCAR (AREF (key, 0)))
-      && CONSP (XCDR (AREF (key, 0))))
+  if (NILP (position) && VECTORP (key))
     {
-      Lisp_Object map, obj, pos = XCAR (XCDR (AREF (key, 0)));
+      Lisp_Object event
+       /* mouse events may have a symbolic prefix indicating the
+          scrollbar or mode line */
+       = AREF (key, SYMBOLP (AREF (key, 0)) && ASIZE (key) > 1 ? 1 : 0);
+
+      /* We are not interested in locations without event data */
 
-      if (XINT (Flength (pos)) == 10 && INTEGERP (XCAR (XCDR (pos))))
+      if (EVENT_HAS_PARAMETERS (event) && CONSP (XCDR (event)))
        {
-         obj = Fnth (make_number(4), pos);
-         map = Fget_char_property (XCAR (XCDR (pos)),
-                                   Qkeymap,
-                                   NILP (obj) ?
-                                   Fwindow_buffer (XCAR (pos))
-                                   : XCAR (obj));
-         if (!NILP (Fkeymapp (map)))
-           {
-             value = Flookup_key (map, key, accept_default);
-             if (! NILP (value) && !INTEGERP (value))
-               goto done;
-           }
+         Lisp_Object kind = EVENT_HEAD_KIND (EVENT_HEAD (event));
+         if (EQ (kind, Qmouse_click))
+           position = EVENT_START (event);
        }
     }
-#endif /* HAVE_MOUSE  */
 
-  if (!NILP (current_kboard->Voverriding_terminal_local_map))
+  /* Key sequences beginning with mouse clicks
+     are read using the keymaps of the buffer clicked on, not
+     the current buffer.  So we may have to switch the buffer
+     here. */
+
+  if (CONSP (position))
+    {
+      Lisp_Object window;
+
+      window = POSN_WINDOW (position);
+
+      if (WINDOWP (window)
+         && BUFFERP (XWINDOW (window)->buffer)
+         && XBUFFER (XWINDOW (window)->buffer) != current_buffer)
+       {
+         /* Arrange to go back to the original buffer once we're done
+            processing the key sequence.  We don't use
+            save_excursion_{save,restore} here, in analogy to
+            `read-key-sequence' to avoid saving point.  Maybe this
+            would not be a problem here, but it is easier to keep
+            things the same.
+         */
+
+         record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+
+         set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
+       }
+    }
+
+  if (! NILP (current_kboard->Voverriding_terminal_local_map))
     {
       value = Flookup_key (current_kboard->Voverriding_terminal_local_map,
                           key, accept_default);
       if (! NILP (value) && !INTEGERP (value))
        goto done;
     }
-  else if (!NILP (Voverriding_local_map))
+  else if (! NILP (Voverriding_local_map))
     {
       value = Flookup_key (Voverriding_local_map, key, accept_default);
       if (! NILP (value) && !INTEGERP (value))
@@ -1618,12 +1774,71 @@ is non-nil, `key-binding' returns the unmapped command.  */)
     }
   else
     {
-      Lisp_Object local;
+      Lisp_Object keymap, local_map;
+      EMACS_INT pt;
+
+      pt = INTEGERP (position) ? XINT (position)
+       : MARKERP (position) ? marker_position (position)
+       : PT;
+
+      local_map = get_local_map (pt, current_buffer, Qlocal_map);
+      keymap = get_local_map (pt, current_buffer, Qkeymap);
+
+      if (CONSP (position))
+       {
+         Lisp_Object string;
+
+         /* For a mouse click, get the local text-property keymap
+            of the place clicked on, rather than point.  */
+
+         if (POSN_INBUFFER_P (position))
+           {
+             Lisp_Object pos;
+
+             pos = POSN_BUFFER_POSN (position);
+             if (INTEGERP (pos)
+                 && XINT (pos) >= BEG && XINT (pos) <= Z)
+               {
+                 local_map = get_local_map (XINT (pos),
+                                            current_buffer, Qlocal_map);
 
-      local = get_local_map (PT, current_buffer, Qkeymap);
-      if (! NILP (local))
+                 keymap = get_local_map (XINT (pos),
+                                         current_buffer, Qkeymap);
+               }
+           }
+
+         /* If on a mode line string with a local keymap,
+            or for a click on a string, i.e. overlay string or a
+            string displayed via the `display' property,
+            consider `local-map' and `keymap' properties of
+            that string.  */
+
+         if (string = POSN_STRING (position),
+             (CONSP (string) && STRINGP (XCAR (string))))
+           {
+             Lisp_Object pos, map;
+
+             pos = XCDR (string);
+             string = XCAR (string);
+             if (INTEGERP (pos)
+                 && XINT (pos) >= 0
+                 && XINT (pos) < SCHARS (string))
+               {
+                 map = Fget_text_property (pos, Qlocal_map, string);
+                 if (!NILP (map))
+                   local_map = map;
+
+                 map = Fget_text_property (pos, Qkeymap, string);
+                 if (!NILP (map))
+                   keymap = map;
+               }
+           }
+
+       }
+
+      if (! NILP (keymap))
        {
-         value = Flookup_key (local, key, accept_default);
+         value = Flookup_key (keymap, key, accept_default);
          if (! NILP (value) && !INTEGERP (value))
            goto done;
        }
@@ -1640,10 +1855,9 @@ is non-nil, `key-binding' returns the unmapped command.  */)
              goto done;
          }
 
-      local = get_local_map (PT, current_buffer, Qlocal_map);
-      if (! NILP (local))
+      if (! NILP (local_map))
        {
-         value = Flookup_key (local, key, accept_default);
+         value = Flookup_key (local_map, key, accept_default);
          if (! NILP (value) && !INTEGERP (value))
            goto done;
        }
@@ -1652,6 +1866,8 @@ is non-nil, `key-binding' returns the unmapped command.  */)
   value = Flookup_key (current_global_map, key, accept_default);
 
  done:
+  unbind_to (count, Qnil);
+
   UNGCPRO;
   if (NILP (value) || INTEGERP (value))
     return Qnil;
@@ -1662,7 +1878,7 @@ is non-nil, `key-binding' returns the unmapped command.  */)
   if (NILP (no_remap) && SYMBOLP (value))
     {
       Lisp_Object value1;
-      if (value1 = Fcommand_remapping (value), !NILP (value1))
+      if (value1 = Fcommand_remapping (value, position, Qnil), !NILP (value1))
        value = value1;
     }
 
@@ -1823,12 +2039,23 @@ DEFUN ("current-minor-mode-maps", Fcurrent_minor_mode_maps, Scurrent_minor_mode_
 \f
 /* Help functions for describing and documenting keymaps.              */
 
+struct accessible_keymaps_data {
+  Lisp_Object maps, tail, thisseq;
+  /* Does the current sequence end in the meta-prefix-char?  */
+  int is_metized;
+};
 
 static void
-accessible_keymaps_1 (key, cmd, maps, tail, thisseq, is_metized)
-     Lisp_Object maps, tail, thisseq, key, cmd;
-     int is_metized;           /* If 1, `key' is assumed to be INTEGERP.  */
+accessible_keymaps_1 (key, cmd, args, data)
+     Lisp_Object key, cmd, args;
+     /* Use void* to be compatible with map_keymap_function_t.  */
+     void *data;
 {
+  struct accessible_keymaps_data *d = data; /* Cast! */
+  Lisp_Object maps = d->maps;
+  Lisp_Object tail = d->tail;
+  Lisp_Object thisseq = d->thisseq;
+  int is_metized = d->is_metized && INTEGERP (key);
   Lisp_Object tem;
 
   cmd = get_keymap (get_keyelt (cmd, 0), 0, 0);
@@ -1882,17 +2109,6 @@ accessible_keymaps_1 (key, cmd, maps, tail, thisseq, is_metized)
     }
 }
 
-static void
-accessible_keymaps_char_table (args, index, cmd)
-     Lisp_Object args, index, cmd;
-{
-  accessible_keymaps_1 (index, cmd,
-                       XCAR (XCAR (args)),
-                       XCAR (XCDR (args)),
-                       XCDR (XCDR (args)),
-                       XINT (XCDR (XCAR (args))));
-}
-
 /* This function cannot GC.  */
 
 DEFUN ("accessible-keymaps", Faccessible_keymaps, Saccessible_keymaps,
@@ -1907,13 +2123,10 @@ then the value includes only maps for prefixes that start with PREFIX.  */)
      Lisp_Object keymap, prefix;
 {
   Lisp_Object maps, tail;
-  int prefixlen = 0;
+  int prefixlen = XINT (Flength (prefix));
 
   /* no need for gcpro because we don't autoload any keymaps.  */
 
-  if (!NILP (prefix))
-    prefixlen = XINT (Flength (prefix));
-
   if (!NILP (prefix))
     {
       /* If a prefix was specified, start with the keymap (if any) for
@@ -1924,7 +2137,9 @@ then the value includes only maps for prefixes that start with PREFIX.  */)
         if the prefix is not defined in this particular map.
         It might even give us a list that isn't a keymap.  */
       tem = get_keymap (tem, 0, 0);
-      if (CONSP (tem))
+      /* If the keymap is autoloaded `tem' is not a cons-cell, but we still
+        want to return it.  */
+      if (!NILP (tem))
        {
          /* Convert PREFIX to a vector now, so that later on
             we don't have to deal with the possibility of a string.  */
@@ -1964,57 +2179,26 @@ then the value includes only maps for prefixes that start with PREFIX.  */)
 
   for (tail = maps; CONSP (tail); tail = XCDR (tail))
     {
-      register Lisp_Object thisseq, thismap;
+      struct accessible_keymaps_data data;
+      register Lisp_Object thismap = Fcdr (XCAR (tail));
       Lisp_Object last;
-      /* Does the current sequence end in the meta-prefix-char?  */
-      int is_metized;
 
-      thisseq = Fcar (Fcar (tail));
-      thismap = Fcdr (Fcar (tail));
-      last = make_number (XINT (Flength (thisseq)) - 1);
-      is_metized = (XINT (last) >= 0
+      data.thisseq = Fcar (XCAR (tail));
+      data.maps = maps;
+      data.tail = tail;
+      last = make_number (XINT (Flength (data.thisseq)) - 1);
+      /* Does the current sequence end in the meta-prefix-char?  */
+      data.is_metized = (XINT (last) >= 0
                    /* Don't metize the last char of PREFIX.  */
                    && XINT (last) >= prefixlen
-                   && EQ (Faref (thisseq, last), meta_prefix_char));
-
-      for (; CONSP (thismap); thismap = XCDR (thismap))
-       {
-         Lisp_Object elt;
-
-         elt = XCAR (thismap);
-
-         QUIT;
-
-         if (CHAR_TABLE_P (elt))
-           {
-             Lisp_Object indices[3];
-
-             map_char_table (accessible_keymaps_char_table, Qnil, elt,
-                             elt, Fcons (Fcons (maps, make_number (is_metized)),
-                                         Fcons (tail, thisseq)),
-                             0, indices);
-           }
-         else if (VECTORP (elt))
-           {
-             register int i;
+                   && EQ (Faref (data.thisseq, last), meta_prefix_char));
 
-             /* Vector keymap.  Scan all the elements.  */
-             for (i = 0; i < ASIZE (elt); i++)
-               accessible_keymaps_1 (make_number (i), AREF (elt, i),
-                                     maps, tail, thisseq, is_metized);
-
-           }
-         else if (CONSP (elt))
-           accessible_keymaps_1 (XCAR (elt), XCDR (elt),
-                                 maps, tail, thisseq,
-                                 is_metized && INTEGERP (XCAR (elt)));
-
-       }
+      /* Since we can't run lisp code, we can't scan autoloaded maps.  */
+      if (CONSP (thismap))
+       map_keymap (thismap, accessible_keymaps_1, Qnil, &data, 0);
     }
-
   return maps;
 }
-\f
 Lisp_Object Qsingle_key_description, Qkey_description;
 
 /* This function cannot GC.  */
@@ -2059,7 +2243,7 @@ spaces are put between sequence elements, etc.  */)
          len += 2;
        }
       else if (len == 0)
-       return empty_string;
+       return empty_unibyte_string;
       return Fconcat (len - 1, args);
     }
 
@@ -2281,16 +2465,29 @@ around function keys and event symbols.  */)
       else
        SPLIT_CHAR (without_bits, charset, c1, c2);
 
-      if (charset
-         && CHARSET_DEFINED_P (charset)
-         && ((c1 >= 0 && c1 < 32)
-             || (c2 >= 0 && c2 < 32)))
+      if (! CHAR_VALID_P (without_bits, 1))
+       {
+         char buf[256];
+
+         sprintf (buf, "Invalid char code %ld", XINT (key));
+         return build_string (buf);
+       }
+      else if (charset
+              && ((c1 == 0 && c2 == -1) || c2 == 0))
        {
          /* Handle a generic character.  */
          Lisp_Object name;
-         name = CHARSET_TABLE_INFO (charset, CHARSET_LONG_NAME_IDX);
+         char buf[256];
+
+         name = CHARSET_TABLE_INFO (charset, CHARSET_SHORT_NAME_IDX);
          CHECK_STRING (name);
-         return concat2 (build_string ("Character set "), name);
+         if (c1 == 0)
+           /* Only a charset is specified.   */
+           sprintf (buf, "Generic char %d: all of ", without_bits);
+         else
+           /* 1st code-point of 2-dimensional charset is specified.   */
+           sprintf (buf, "Generic char %d: row %d of ", without_bits, c1);
+         return concat2 (build_string (buf), name);
        }
       else
        {
@@ -2415,8 +2612,8 @@ ascii_sequence_p (seq)
 /* where-is - finding a command in a set of keymaps.                   */
 
 static Lisp_Object where_is_internal ();
-static Lisp_Object where_is_internal_1 ();
-static void where_is_internal_2 ();
+static void where_is_internal_1 P_ ((Lisp_Object key, Lisp_Object binding,
+                                    Lisp_Object args, void *data));
 
 /* Like Flookup_key, but uses a list of keymaps SHADOW instead of a single map.
    Returns the first non-nil binding found in any of those maps.  */
@@ -2445,6 +2642,12 @@ shadow_lookup (shadow, key, flag)
 
 static Lisp_Object Vmouse_events;
 
+struct where_is_internal_data {
+  Lisp_Object definition, noindirect, this, last;
+  int last_is_meta;
+  Lisp_Object sequences;
+};
+
 /* This function can GC if Flookup_key autoloads any keymaps.  */
 
 static Lisp_Object
@@ -2458,15 +2661,6 @@ where_is_internal (definition, keymaps, firstonly, noindirect, no_remap)
   /* 1 means ignore all menu bindings entirely.  */
   int nomenus = !NILP (firstonly) && !EQ (firstonly, Qnon_ascii);
 
-  /* If this command is remapped, then it has no key bindings
-     of its own.  */
-  if (NILP (no_remap) && SYMBOLP (definition))
-    {
-      Lisp_Object tem;
-      if (tem = Fcommand_remapping (definition), !NILP (tem))
-       return Qnil;
-    }
-
   found = keymaps;
   while (CONSP (found))
     {
@@ -2480,10 +2674,18 @@ where_is_internal (definition, keymaps, firstonly, noindirect, no_remap)
   found = Qnil;
   sequences = Qnil;
 
+  /* If this command is remapped, then it has no key bindings
+     of its own.  */
+  if (NILP (no_remap)
+      && SYMBOLP (definition)
+      && !NILP (Fcommand_remapping (definition, Qnil, keymaps)))
+    RETURN_UNGCPRO (Qnil);
+
   for (; !NILP (maps); maps = Fcdr (maps))
     {
       /* Key sequence to reach map, and the map that it reaches */
       register Lisp_Object this, map, tem;
+      struct where_is_internal_data data;
 
       /* In order to fold [META-PREFIX-CHAR CHAR] sequences into
         [M-CHAR] sequences, check if last character of the sequence
@@ -2508,148 +2710,94 @@ where_is_internal (definition, keymaps, firstonly, noindirect, no_remap)
 
       QUIT;
 
-      while (CONSP (map))
-       {
-         /* Because the code we want to run on each binding is rather
-            large, we don't want to have two separate loop bodies for
-            sparse keymap bindings and tables; we want to iterate one
-            loop body over both keymap and vector bindings.
-
-            For this reason, if Fcar (map) is a vector, we don't
-            advance map to the next element until i indicates that we
-            have finished off the vector.  */
-         Lisp_Object elt, key, binding;
-         elt = XCAR (map);
-         map = XCDR (map);
+      data.definition = definition;
+      data.noindirect = noindirect;
+      data.this = this;
+      data.last = last;
+      data.last_is_meta = last_is_meta;
+      data.sequences = Qnil;
 
-         sequences = Qnil;
+      if (CONSP (map))
+       map_keymap (map, where_is_internal_1, Qnil, &data, 0);
 
-         QUIT;
+      sequences = data.sequences;
 
-         /* Set key and binding to the current key and binding, and
-            advance map and i to the next binding.  */
-         if (VECTORP (elt))
+      while (CONSP (sequences))
+       {
+         Lisp_Object sequence, remapped, function;
+         
+         sequence = XCAR (sequences);
+         sequences = XCDR (sequences);
+
+         /* If the current sequence is a command remapping with
+            format [remap COMMAND], find the key sequences
+            which run COMMAND, and use those sequences instead.  */
+         remapped = Qnil;
+         if (NILP (no_remap)
+             && VECTORP (sequence) && XVECTOR (sequence)->size == 2
+             && EQ (AREF (sequence, 0), Qremap)
+             && (function = AREF (sequence, 1), SYMBOLP (function)))
            {
-             Lisp_Object sequence;
-             int i;
-             /* In a vector, look at each element.  */
-             for (i = 0; i < XVECTOR (elt)->size; i++)
+             Lisp_Object remapped1;
+             
+             remapped1 = where_is_internal (function, keymaps, firstonly, noindirect, Qt);
+             if (CONSP (remapped1))
                {
-                 binding = AREF (elt, i);
-                 XSETFASTINT (key, i);
-                 sequence = where_is_internal_1 (binding, key, definition,
-                                                 noindirect, this,
-                                                 last, nomenus, last_is_meta);
-                 if (!NILP (sequence))
-                   sequences = Fcons (sequence, sequences);
+                 /* Verify that this key binding actually maps to the
+                    remapped command (see below).  */
+                 if (!EQ (shadow_lookup (keymaps, XCAR (remapped1), Qnil), function))
+                   continue;
+                 sequence = XCAR (remapped1);
+                 remapped = XCDR (remapped1);
+                 goto record_sequence;
                }
            }
-         else if (CHAR_TABLE_P (elt))
-           {
-             Lisp_Object indices[3];
-             Lisp_Object args;
-
-             args = Fcons (Fcons (Fcons (definition, noindirect),
-                                  Qnil), /* Result accumulator.  */
-                           Fcons (Fcons (this, last),
-                                  Fcons (make_number (nomenus),
-                                         make_number (last_is_meta))));
-             map_char_table (where_is_internal_2, Qnil, elt, elt, args,
-                             0, indices);
-             sequences = XCDR (XCAR (args));
-           }
-         else if (CONSP (elt))
-           {
-             Lisp_Object sequence;
 
-             key = XCAR (elt);
-             binding = XCDR (elt);
+         /* Verify that this key binding is not shadowed by another
+            binding for the same key, before we say it exists.
 
-             sequence = where_is_internal_1 (binding, key, definition,
-                                             noindirect, this,
-                                             last, nomenus, last_is_meta);
-             if (!NILP (sequence))
-               sequences = Fcons (sequence, sequences);
-           }
+            Mechanism: look for local definition of this key and if
+            it is defined and does not match what we found then
+            ignore this key.
 
+            Either nil or number as value from Flookup_key
+            means undefined.  */
+         if (!EQ (shadow_lookup (keymaps, sequence, Qnil), definition))
+           continue;
 
-         while (!NILP (sequences))
+       record_sequence:
+         /* Don't annoy user with strings from a menu such as
+            Select Paste.  Change them all to "(any string)",
+            so that there seems to be only one menu item
+            to report. */
+         if (! NILP (sequence))
            {
-             Lisp_Object sequence, remapped, function;
-
-             sequence = XCAR (sequences);
-             sequences = XCDR (sequences);
-
-             /* If the current sequence is a command remapping with
-                format [remap COMMAND], find the key sequences
-                which run COMMAND, and use those sequences instead.  */
-             remapped = Qnil;
-             if (NILP (no_remap)
-                 && VECTORP (sequence) && XVECTOR (sequence)->size == 2
-                 && EQ (AREF (sequence, 0), Qremap)
-                 && (function = AREF (sequence, 1), SYMBOLP (function)))
-               {
-                 Lisp_Object remapped1;
-
-                 remapped1 = where_is_internal (function, keymaps, firstonly, noindirect, Qt);
-                 if (CONSP (remapped1))
-                   {
-                     /* Verify that this key binding actually maps to the
-                        remapped command (see below).  */
-                     if (!EQ (shadow_lookup (keymaps, XCAR (remapped1), Qnil), function))
-                       continue;
-                     sequence = XCAR (remapped1);
-                     remapped = XCDR (remapped1);
-                     goto record_sequence;
-                   }
-               }
-
-             /* Verify that this key binding is not shadowed by another
-                binding for the same key, before we say it exists.
-
-                Mechanism: look for local definition of this key and if
-                it is defined and does not match what we found then
-                ignore this key.
-
-                Either nil or number as value from Flookup_key
-                means undefined.  */
-             if (!EQ (shadow_lookup (keymaps, sequence, Qnil), definition))
-               continue;
-
-           record_sequence:
-             /* Don't annoy user with strings from a menu such as
-                Select Paste.  Change them all to "(any string)",
-                so that there seems to be only one menu item
-                to report. */
-             if (! NILP (sequence))
-               {
-                 Lisp_Object tem;
-                 tem = Faref (sequence, make_number (XVECTOR (sequence)->size - 1));
-                 if (STRINGP (tem))
-                   Faset (sequence, make_number (XVECTOR (sequence)->size - 1),
-                          build_string ("(any string)"));
-               }
+             Lisp_Object tem;
+             tem = Faref (sequence, make_number (XVECTOR (sequence)->size - 1));
+             if (STRINGP (tem))
+               Faset (sequence, make_number (XVECTOR (sequence)->size - 1),
+                      build_string ("(any string)"));
+           }
 
-             /* It is a true unshadowed match.  Record it, unless it's already
-                been seen (as could happen when inheriting keymaps).  */
-             if (NILP (Fmember (sequence, found)))
-               found = Fcons (sequence, found);
-
-             /* If firstonly is Qnon_ascii, then we can return the first
-                binding we find.  If firstonly is not Qnon_ascii but not
-                nil, then we should return the first ascii-only binding
-                we find.  */
-             if (EQ (firstonly, Qnon_ascii))
-               RETURN_UNGCPRO (sequence);
-             else if (!NILP (firstonly) && ascii_sequence_p (sequence))
-               RETURN_UNGCPRO (sequence);
-
-             if (CONSP (remapped))
-               {
-                 sequence = XCAR (remapped);
-                 remapped = XCDR (remapped);
-                 goto record_sequence;
-               }
+         /* It is a true unshadowed match.  Record it, unless it's already
+            been seen (as could happen when inheriting keymaps).  */
+         if (NILP (Fmember (sequence, found)))
+           found = Fcons (sequence, found);
+
+         /* If firstonly is Qnon_ascii, then we can return the first
+            binding we find.  If firstonly is not Qnon_ascii but not
+            nil, then we should return the first ascii-only binding
+            we find.  */
+         if (EQ (firstonly, Qnon_ascii))
+           RETURN_UNGCPRO (sequence);
+         else if (!NILP (firstonly) && ascii_sequence_p (sequence))
+           RETURN_UNGCPRO (sequence);
+
+         if (CONSP (remapped))
+           {
+             sequence = XCAR (remapped);
+             remapped = XCDR (remapped);
+             goto record_sequence;
            }
        }
     }
@@ -2702,7 +2850,7 @@ remapped command in the returned list.  */)
   else if (!NILP (keymap))
     keymaps = Fcons (keymap, Fcons (current_global_map, Qnil));
   else
-    keymaps = Fcurrent_active_maps (Qnil);
+    keymaps = Fcurrent_active_maps (Qnil, Qnil);
 
   /* Only use caching for the menubar (i.e. called with (def nil t nil).
      We don't really need to check `keymap'.  */
@@ -2768,53 +2916,19 @@ remapped command in the returned list.  */)
   return result;
 }
 
-/* This is the function that Fwhere_is_internal calls using map_char_table.
-   ARGS has the form
-   (((DEFINITION . NOINDIRECT) . (KEYMAP . RESULT))
-    .
-    ((THIS . LAST) . (NOMENUS . LAST_IS_META)))
-   Since map_char_table doesn't really use the return value from this function,
-   we the result append to RESULT, the slot in ARGS.
-
-   This function can GC because it calls where_is_internal_1 which can
-   GC.  */
-
-static void
-where_is_internal_2 (args, key, binding)
-     Lisp_Object args, key, binding;
-{
-  Lisp_Object definition, noindirect, this, last;
-  Lisp_Object result, sequence;
-  int nomenus, last_is_meta;
-  struct gcpro gcpro1, gcpro2, gcpro3;
-
-  GCPRO3 (args, key, binding);
-  result = XCDR (XCAR (args));
-  definition = XCAR (XCAR (XCAR (args)));
-  noindirect = XCDR (XCAR (XCAR (args)));
-  this = XCAR (XCAR (XCDR (args)));
-  last = XCDR (XCAR (XCDR (args)));
-  nomenus = XFASTINT (XCAR (XCDR (XCDR (args))));
-  last_is_meta = XFASTINT (XCDR (XCDR (XCDR (args))));
-
-  sequence = where_is_internal_1 (binding, key, definition, noindirect,
-                                 this, last, nomenus, last_is_meta);
-
-  if (!NILP (sequence))
-    XSETCDR (XCAR (args), Fcons (sequence, result));
-
-  UNGCPRO;
-}
-
-
 /* This function can GC because get_keyelt can.  */
 
-static Lisp_Object
-where_is_internal_1 (binding, key, definition, noindirect, this, last,
-                    nomenus, last_is_meta)
-     Lisp_Object binding, key, definition, noindirect, this, last;
-     int nomenus, last_is_meta;
+static void
+where_is_internal_1 (key, binding, args, data)
+     Lisp_Object key, binding, args;
+     void *data;
 {
+  struct where_is_internal_data *d = data; /* Cast! */
+  Lisp_Object definition = d->definition;
+  Lisp_Object noindirect = d->noindirect;
+  Lisp_Object this = d->this;
+  Lisp_Object last = d->last;
+  int last_is_meta = d->last_is_meta;
   Lisp_Object sequence;
 
   /* Search through indirections unless that's not wanted.  */
@@ -2828,7 +2942,7 @@ where_is_internal_1 (binding, key, definition, noindirect, this, last,
        || EQ (binding, definition)
        || (CONSP (definition) && !NILP (Fequal (binding, definition)))))
     /* Doesn't match.  */
-    return Qnil;
+    return;
 
   /* We have found a match.  Construct the key sequence where we found it.  */
   if (INTEGERP (key) && last_is_meta)
@@ -2843,10 +2957,9 @@ where_is_internal_1 (binding, key, definition, noindirect, this, last,
     {
       Lisp_Object sequences = Fgethash (binding, where_is_cache, Qnil);
       Fputhash (binding, Fcons (sequence, sequences), where_is_cache);
-      return Qnil;
     }
   else
-    return sequence;
+    d->sequences = Fcons (sequence, d->sequences);
 }
 \f
 /* describe-bindings - summarizing all the bindings in a set of keymaps.  */
@@ -2873,17 +2986,19 @@ Keyboard translations:\n\n\
 You type        Translation\n\
 --------        -----------\n";
 
+  CHECK_BUFFER (buffer);
+
   shadow = Qnil;
   GCPRO1 (shadow);
 
   outbuf = Fcurrent_buffer ();
 
   /* Report on alternates for keys.  */
-  if (STRINGP (Vkeyboard_translate_table) && !NILP (prefix))
+  if (STRINGP (current_kboard->Vkeyboard_translate_table) && !NILP (prefix))
     {
       int c;
-      const unsigned char *translate = SDATA (Vkeyboard_translate_table);
-      int translate_len = SCHARS (Vkeyboard_translate_table);
+      const unsigned char *translate = SDATA (current_kboard->Vkeyboard_translate_table);
+      int translate_len = SCHARS (current_kboard->Vkeyboard_translate_table);
 
       for (c = 0; c < translate_len; c++)
        if (translate[c] != c)
@@ -2906,14 +3021,14 @@ You type        Translation\n\
            insert ("\n", 1);
 
            /* Insert calls signal_after_change which may GC. */
-           translate = SDATA (Vkeyboard_translate_table);
+           translate = SDATA (current_kboard->Vkeyboard_translate_table);
          }
 
       insert ("\n", 1);
     }
 
-  if (!NILP (Vkey_translation_map))
-    describe_map_tree (Vkey_translation_map, 0, Qnil, prefix,
+  if (!NILP (current_kboard->Vlocal_key_translation_map))
+    describe_map_tree (current_kboard->Vlocal_key_translation_map, 0, Qnil, prefix,
                       "Key translations", nomenu, 1, 0, 0);
 
 
@@ -3002,8 +3117,8 @@ You type        Translation\n\
                     "\f\nGlobal Bindings", nomenu, 0, 1, 0);
 
   /* Print the function-key-map translations under this prefix.  */
-  if (!NILP (Vfunction_key_map))
-    describe_map_tree (Vfunction_key_map, 0, Qnil, prefix,
+  if (!NILP (current_kboard->Vlocal_function_key_map))
+    describe_map_tree (current_kboard->Vlocal_function_key_map, 0, Qnil, prefix,
                       "\f\nFunction key map translations", nomenu, 1, 0, 0);
 
   UNGCPRO;
@@ -3336,9 +3451,13 @@ describe_map (map, prefix, elt_describer, partial, shadow,
              tem = shadow_lookup (shadow, kludge, Qt);
              if (!NILP (tem))
                {
+                 /* If both bindings are keymaps, this key is a prefix key,
+                    so don't say it is shadowed.  */
+                 if (KEYMAPP (definition) && KEYMAPP (tem))
+                   ;
                  /* Avoid generating duplicate entries if the
-                    shadowed binding has the same definition. */
-                 if (mention_shadow && !EQ (tem, definition))
+                    shadowed binding has the same definition.  */
+                 else if (mention_shadow && !EQ (tem, definition))
                    this_shadowed = 1;
                  else
                    continue;
@@ -3969,37 +4088,6 @@ the same way.  The "active" keymaps in each alist are used before
 `minor-mode-map-alist' and `minor-mode-overriding-map-alist'.  */);
   Vemulation_mode_map_alists = Qnil;
 
-
-  DEFVAR_LISP ("function-key-map", &Vfunction_key_map,
-              doc: /* Keymap that translates key sequences to key sequences during input.
-This is used mainly for mapping ASCII function key sequences into
-real Emacs function key events (symbols).
-
-The `read-key-sequence' function replaces any subsequence bound by
-`function-key-map' with its binding.  More precisely, when the active
-keymaps have no binding for the current key sequence but
-`function-key-map' binds a suffix of the sequence to a vector or string,
-`read-key-sequence' replaces the matching suffix with its binding, and
-continues with the new sequence.
-
-If the binding is a function, it is called with one argument (the prompt)
-and its return value (a key sequence) is used.
-
-The events that come from bindings in `function-key-map' are not
-themselves looked up in `function-key-map'.
-
-For example, suppose `function-key-map' binds `ESC O P' to [f1].
-Typing `ESC O P' to `read-key-sequence' would return [f1].  Typing
-`C-x ESC O P' would return [?\\C-x f1].  If [f1] were a prefix
-key, typing `ESC O P x' would return [f1 x].  */);
-  Vfunction_key_map = Fmake_sparse_keymap (Qnil);
-
-  DEFVAR_LISP ("key-translation-map", &Vkey_translation_map,
-              doc: /* Keymap of key translations that can override keymaps.
-This keymap works like `function-key-map', but comes after that,
-and its non-prefix bindings override ordinary bindings.  */);
-  Vkey_translation_map = Qnil;
-
   staticpro (&Vmouse_events);
   Vmouse_events = Fcons (intern ("menu-bar"),
                  Fcons (intern ("tool-bar"),