]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
(follow_key): When downcasing, downcase just the
[gnu-emacs] / src / keyboard.c
index fc1ac681f16bb6f79089f0d6fe8687deecc678c8..e7e58365491b083a831a64bf8fdae6934c80427a 100644 (file)
@@ -20,7 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 /* Allow config.h to undefine symbols found here.  */
 #include <signal.h>
 
-#include "config.h"
+#include <config.h>
 #include <stdio.h>
 #undef NULL
 #include "termchar.h"
@@ -402,6 +402,7 @@ extern Lisp_Object Qmenu_enable;
 
 Lisp_Object recursive_edit_unwind (), command_loop ();
 Lisp_Object Fthis_command_keys ();
+Lisp_Object Qextended_command_history;
 
 /* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
    happens.  */
@@ -430,13 +431,11 @@ int flow_control;
 #endif
 #endif
 
-/* If we support X Windows, and won't get an interrupt when input
-   arrives from the server, poll periodically so we can detect C-g.  */
+/* If we support X Windows, turn on the code to poll periodically
+   to detect C-g.  It isn't actually used when doing interrupt input.  */
 #ifdef HAVE_X_WINDOWS
-#ifndef SIGIO
 #define POLL_FOR_INPUT
 #endif
-#endif
 \f
 /* Global variable declarations.  */
 
@@ -961,7 +960,8 @@ command_loop_1 ()
 #endif
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
-      if (! NILP (Vlucid_menu_bar_dirty_flag))
+      if (! NILP (Vlucid_menu_bar_dirty_flag)
+         && !NILP (Ffboundp (Qrecompute_lucid_menubar)))
        call0 (Qrecompute_lucid_menubar);
 
 #if 0 /* This is done in xdisp.c now.  */
@@ -994,7 +994,7 @@ command_loop_1 ()
 #endif /* 0 */
 
       /* Read next key sequence; i gets its length.  */
-      i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])), 0);
+      i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])), Qnil);
 
       ++num_input_keys;
 
@@ -1230,7 +1230,7 @@ input_poll_signal ()
 start_polling ()
 {
 #ifdef POLL_FOR_INPUT
-  if (read_socket_hook)
+  if (read_socket_hook && !interrupt_input)
     {
       poll_suppress_count--;
       if (poll_suppress_count == 0)
@@ -1248,7 +1248,7 @@ start_polling ()
 stop_polling ()
 {
 #ifdef POLL_FOR_INPUT
-  if (read_socket_hook)
+  if (read_socket_hook && !interrupt_input)
     {
       if (poll_suppress_count == 0)
        {
@@ -1259,6 +1259,27 @@ stop_polling ()
     }
 #endif
 }
+
+/* Set the value of poll_suppress_count to COUNT
+   and start or stop polling accordingly.  */
+
+void
+set_poll_suppress_count (count)
+     int count;
+{
+#ifdef POLL_FOR_INPUT
+  if (count == 0 && poll_suppress_count != 0)
+    {
+      poll_suppress_count = 1;
+      start_polling ();
+    }
+  else if (count != 0 && poll_suppress_count == 0)
+    {
+      stop_polling ();
+    }
+  poll_suppress_count = count;
+#endif
+}
 \f
 /* Applying the control modifier to CHARACTER.  */
 int
@@ -1434,6 +1455,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   /* If in middle of key sequence and minibuffer not active,
      start echoing if enough time elapses.  */
   if (minibuf_level == 0 && !immediate_echo && this_command_key_count > 0
+      && ! noninteractive
       && echo_keystrokes > 0
       && (echo_area_glyphs == 0 || *echo_area_glyphs == 0))
     {
@@ -1763,8 +1785,8 @@ kbd_buffer_store_event (event)
             get returned to Emacs as an event, the next event read
             will set Vlast_event_frame again, so this is safe to do.  */
          {
-           Lisp_Object focus =
-             FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window));
+           Lisp_Object focus
+             FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window));
 
            if (NILP (focus))
              internal_last_event_frame = event->frame_or_window;
@@ -1796,13 +1818,23 @@ kbd_buffer_store_event (event)
   if (kbd_fetch_ptr - 1 != kbd_store_ptr)
     {
       kbd_store_ptr->kind = event->kind;
-      kbd_store_ptr->code = event->code;
-      kbd_store_ptr->part = event->part;
-      kbd_store_ptr->frame_or_window = event->frame_or_window;
-      kbd_store_ptr->modifiers = event->modifiers;
-      kbd_store_ptr->x = event->x;
-      kbd_store_ptr->y = event->y;
-      kbd_store_ptr->timestamp = event->timestamp;
+      if (event->kind == selection_request_event)
+       {
+         /* We must not use the ordinary copying code for this case,
+            since `part' is an enum and copying it might not copy enough
+            in this case.  */
+         bcopy (event, kbd_store_ptr, sizeof (*event));
+       }
+      else
+       {
+         kbd_store_ptr->code = event->code;
+         kbd_store_ptr->part = event->part;
+         kbd_store_ptr->frame_or_window = event->frame_or_window;
+         kbd_store_ptr->modifiers = event->modifiers;
+         kbd_store_ptr->x = event->x;
+         kbd_store_ptr->y = event->y;
+         kbd_store_ptr->timestamp = event->timestamp;
+       }
       (XVECTOR (kbd_buffer_frame_or_window)->contents[kbd_store_ptr
                                                      - kbd_buffer]
        = event->frame_or_window);
@@ -2179,10 +2211,10 @@ static Lisp_Object button_down_location;
 /* Information about the most recent up-going button event:  Which
    button, what location, and what time. */
 
-static int button_up_button;
-static int button_up_x;
-static int button_up_y;
-static unsigned long button_up_time;
+static int last_mouse_button;
+static int last_mouse_x;
+static int last_mouse_y;
+static unsigned long button_down_time;
 
 /* The maximum time between clicks to make a double-click,
    or Qnil to disable double-click detection,
@@ -2214,7 +2246,7 @@ make_lispy_event (event)
       /* A simple keystroke.  */
     case ascii_keystroke:
       {
-       int c = XFASTINT (event->code);
+       int c = XFASTINT (event->code) & 0377;
        /* Turn ASCII characters into control characters
           when proper.  */
        if (event->modifiers & ctrl_modifier)
@@ -2226,14 +2258,14 @@ make_lispy_event (event)
        c |= (event->modifiers
              & (meta_modifier | alt_modifier
                 | hyper_modifier | super_modifier));
-       button_up_time = 0;
+       button_down_time = 0;
        return c;
       }
 
       /* A function key.  The symbol may need to have modifier prefixes
         tacked onto it.  */
     case non_ascii_keystroke:
-      button_up_time = 0;
+      button_down_time = 0;
       return modify_event_symbol (XFASTINT (event->code), event->modifiers,
                                  Qfunction_key,
                                  lispy_function_keys, &func_key_syms,
@@ -2247,6 +2279,7 @@ make_lispy_event (event)
     case scroll_bar_click:
       {
        int button = XFASTINT (event->code);
+       int is_double;
        Lisp_Object position;
        Lisp_Object *start_pos_ptr;
        Lisp_Object start_pos;
@@ -2338,10 +2371,34 @@ make_lispy_event (event)
        start_pos = *start_pos_ptr;
        *start_pos_ptr = Qnil;
 
+       is_double = (button == last_mouse_button
+                    && XINT (event->x) == last_mouse_x
+                    && XINT (event->y) == last_mouse_y
+                    && button_down_time != 0
+                    && (EQ (Vdouble_click_time, Qt)
+                        || (INTEGERP (Vdouble_click_time)
+                            && ((int)(event->timestamp - button_down_time)
+                                < XINT (Vdouble_click_time)))));
+       last_mouse_button = button;
+       last_mouse_x = XINT (event->x);
+       last_mouse_y = XINT (event->y);
+
        /* If this is a button press, squirrel away the location, so
            we can decide later whether it was a click or a drag.  */
        if (event->modifiers & down_modifier)
-         *start_pos_ptr = Fcopy_alist (position);
+         {
+           if (is_double)
+             {
+               double_click_count++;
+               event->modifiers |= ((double_click_count > 2)
+                                    ? triple_modifier
+                                    : double_modifier);
+             }
+           else
+             double_click_count = 1;
+           button_down_time = event->timestamp;
+           *start_pos_ptr = Fcopy_alist (position);
+         }
 
        /* Now we're releasing a button - check the co-ordinates to
            see if this was a click or a drag.  */
@@ -2371,33 +2428,16 @@ make_lispy_event (event)
                if (EQ (event->x, XCONS (down)->car)
                    && EQ (event->y, XCONS (down)->cdr))
                  {
-                   if (button == button_up_button
-                       && XINT (event->x) == button_up_x
-                       && XINT (event->y) == button_up_y
-                       && button_up_time != 0
-                       && (EQ (Vdouble_click_time, Qt)
-                           || (INTEGERP (Vdouble_click_time)
-                               && ((int)(event->timestamp - button_up_time)
-                                   < XINT (Vdouble_click_time)))))
-                     {
-                       double_click_count++;
-                       event->modifiers |= ((double_click_count > 2)
-                                            ? triple_modifier
-                                            : double_modifier);
-                     }
+                   if (is_double && double_click_count > 1)
+                     event->modifiers |= ((double_click_count > 2)
+                                          ? triple_modifier
+                                          : double_modifier);
                    else
-                     {
-                       double_click_count = 1;
-                       event->modifiers |= click_modifier;
-                     }
-                   button_up_button = button;
-                   button_up_x = XINT (event->x);
-                   button_up_y = XINT (event->y);
-                   button_up_time = event->timestamp;
+                     event->modifiers |= click_modifier;
                  }
                else
                  {
-                   button_up_time = 0;
+                   button_down_time = 0;
                    event->modifiers |= drag_modifier;
                  }
              }
@@ -2657,10 +2697,10 @@ apply_modifiers_uncached (modifiers, base, base_len)
     if (modifiers & meta_modifier)  { *p++ = 'M'; *p++ = '-'; }
     if (modifiers & shift_modifier) { *p++ = 'S'; *p++ = '-'; }
     if (modifiers & super_modifier) { *p++ = 's'; *p++ = '-'; }
-    if (modifiers & down_modifier)  { strcpy (p, "down-");  p += 5; }
-    if (modifiers & drag_modifier)  { strcpy (p, "drag-");  p += 5; }
     if (modifiers & double_modifier)  { strcpy (p, "double-");  p += 7; }
     if (modifiers & triple_modifier)  { strcpy (p, "triple-");  p += 7; }
+    if (modifiers & down_modifier)  { strcpy (p, "down-");  p += 5; }
+    if (modifiers & drag_modifier)  { strcpy (p, "drag-");  p += 5; }
     /* The click modifier is denoted by the absence of other modifiers.  */
 
     *p = '\0';
@@ -2987,7 +3027,10 @@ read_avail_input (expected)
     nread = (*read_socket_hook) (0, buf, KBD_BUFFER_SIZE, expected, expected);
   else
     {
-      unsigned char cbuf[KBD_BUFFER_SIZE];
+      /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
+        the kbd_buffer can really hold.  That may prevent loss
+        of characters on some systems when input is stuffed at us.  */
+      unsigned char cbuf[KBD_BUFFER_SIZE - 1];
 
 #ifdef FIONREAD
       /* Find out how much input is available.  */
@@ -3004,7 +3047,7 @@ read_avail_input (expected)
       if (nread > sizeof cbuf)
        nread = sizeof cbuf;
 #else /* no FIONREAD */
-#ifdef USG
+#if defined(USG) || defined(DGUX)
       /* Read some input if available, but don't wait.  */
       nread = sizeof cbuf;
       fcntl (fileno (stdin), F_SETFL, O_NDELAY);
@@ -3016,23 +3059,26 @@ read_avail_input (expected)
       /* Now read; for one reason or another, this will not block.  */
       while (1)
        {
-         nread = read (fileno (stdin), cbuf, nread);
+         int value = read (fileno (stdin), cbuf, nread);
 #ifdef AIX
          /* The kernel sometimes fails to deliver SIGHUP for ptys.
             This looks incorrect, but it isn't, because _BSD causes
             O_NDELAY to be defined in fcntl.h as O_NONBLOCK,
             and that causes a value other than 0 when there is no input.  */
-         if (nread == 0)
+         if (value == 0)
            kill (SIGHUP, 0);
 #endif
          /* Retry the read if it is interrupted.  */
-         if (nread >= 0
+         if (value >= 0
              || ! (errno == EAGAIN || errno == EFAULT
 #ifdef EBADSLT
                    || errno == EBADSLT
 #endif
                    ))
-           break;
+           {
+             nread = value;
+             break;
+           }
        }
 
 #ifndef FIONREAD
@@ -3613,7 +3659,8 @@ follow_key (key, nmaps, current, defs, next)
       if (XINT (key) & shift_modifier)
        XSETINT (key, XINT (key) & ~shift_modifier);
       else
-       XSETINT (key, DOWNCASE (XINT (key)));
+       XSETINT (key, (DOWNCASE (XINT (key) & 0x3ffff)
+                      | (XINT (key) & ~0x3ffff)));
 
       first_binding = nmaps;
       for (i = nmaps - 1; i >= 0; i--)
@@ -3675,7 +3722,7 @@ static int
 read_key_sequence (keybuf, bufsize, prompt)
      Lisp_Object *keybuf;
      int bufsize;
-     char *prompt;
+     Lisp_Object prompt;
 {
   int count = specpdl_ptr - specpdl;
 
@@ -3739,7 +3786,12 @@ read_key_sequence (keybuf, bufsize, prompt)
      we put it off for later.  While we're reading, we keep the event here.  */
   Lisp_Object delayed_switch_frame;
 
+  /* See the comment below... */
+#if defined (GOBBLE_FIRST_EVENT)
   Lisp_Object first_event;
+#endif
+
+  struct buffer *starting_buffer;
 
   int junk;
 
@@ -3759,8 +3811,8 @@ read_key_sequence (keybuf, bufsize, prompt)
 
   if (INTERACTIVE)
     {
-      if (prompt)
-       echo_prompt (prompt);
+      if (!NILP (prompt))
+       echo_prompt (XSTRING (prompt)->data);
       else if (cursor_in_echo_area)
        /* This doesn't put in a dash if the echo buffer is empty, so
           you don't always see a dash hanging out in the minibuffer.  */
@@ -3773,20 +3825,24 @@ read_key_sequence (keybuf, bufsize, prompt)
     echo_start = echo_length ();
   keys_start = this_command_key_count;
 
-#if 0 /* This doesn't quite work, because some of the things
-        that read_char does cannot safely be bypassed.
-        It seems too risky to try to make this work right.  */ 
+#if defined (GOBBLE_FIRST_EVENT)
+  /* This doesn't quite work, because some of the things that read_char
+     does cannot safely be bypassed.  It seems too risky to try to make
+     this work right.  */ 
+
   /* Read the first char of the sequence specially, before setting
      up any keymaps, in case a filter runs and switches buffers on us.  */
-  first_event = read_char (!prompt, 0, submaps, last_nonmenu_event,
+  first_event = read_char (NILP (prompt), 0, submaps, last_nonmenu_event,
                           &junk);
-#endif
+#endif /* GOBBLE_FIRST_EVENT */
 
   /* We jump here when the key sequence has been thoroughly changed, and
      we need to rescan it starting from the beginning.  When we jump here,
      keybuf[0..mock_input] holds the sequence we should reread.  */
  replay_sequence:
 
+  starting_buffer = current_buffer;
+
   /* Build our list of keymaps.
      If we recognize a function key and replace its escape sequence in
      keybuf with its symbol, or if the sequence starts with a mouse
@@ -3816,9 +3872,7 @@ read_key_sequence (keybuf, bufsize, prompt)
     if (! NILP (submaps[first_binding]))
       break;
 
-  /* We jump here when a function key substitution has forced us to
-     reprocess the current key sequence.  keybuf[0..mock_input] is the
-     sequence we want to reread.  */
+  /* Start from the beginning in keybuf.  */
   t = 0;
 
   /* These are no-ops the first time through, but if we restart, they
@@ -3890,7 +3944,7 @@ read_key_sequence (keybuf, bufsize, prompt)
        {
          struct buffer *buf = current_buffer;
 
-         key = read_char (!prompt, nmaps, submaps, last_nonmenu_event,
+         key = read_char (NILP (prompt), nmaps, submaps, last_nonmenu_event,
                           &used_mouse_menu);
 
          /* read_char returns t when it shows a menu and the user rejects it.
@@ -3907,6 +3961,17 @@ read_key_sequence (keybuf, bufsize, prompt)
              goto done;
            }
          
+         /* If we have a quit that was typed in another frame, and
+            quit_throw_to_read_char switched buffers,
+            replay to get the right keymap.  */
+         if (EQ (key, quit_char) && current_buffer != starting_buffer)
+           {
+             keybuf[t++] = key;
+             mock_input = t;
+             Vquit_flag = Qnil;
+             goto replay_sequence;
+           }
+           
          Vquit_flag = Qnil;
        }
 
@@ -4063,80 +4128,86 @@ read_key_sequence (keybuf, bufsize, prompt)
              Lisp_Object breakdown = parse_modifiers (head);
              int modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
 
-             /* We drop unbound `down-' events altogether.  */
-             if (modifiers & down_modifier)
+             /* Attempt to reduce an unbound mouse event to a simpler
+                event that is bound:
+                  Drags reduce to clicks.
+                  Double-clicks reduce to clicks.
+                  Triple-clicks reduce to double-clicks, then to clicks.
+                  Down-clicks are eliminated.
+                  Double-downs reduce to downs, then are eliminated.
+                  Triple-downs reduce to double-downs, then to downs,
+                    then are eliminated. */
+             if (modifiers & (down_modifier | drag_modifier
+                              | double_modifier | triple_modifier))
                {
-                 /* Dispose of this event by simply jumping back to
-                    replay_key, to get another event.
-
-                    Note that if this event came from mock input,
-                    then just jumping back to replay_key will just
-                    hand it to us again.  So we have to wipe out any
-                    mock input.
-
-                    We could delete keybuf[t] and shift everything
-                    after that to the left by one spot, but we'd also
-                    have to fix up any variable that points into
-                    keybuf, and shifting isn't really necessary
-                    anyway.
-
-                    Adding prefixes for non-textual mouse clicks
-                    creates two characters of mock input, and both
-                    must be thrown away.  If we're only looking at
-                    the prefix now, we can just jump back to
-                    replay_key.  On the other hand, if we've already
-                    processed the prefix, and now the actual click
-                    itself is giving us trouble, then we've lost the
-                    state of the keymaps we want to backtrack to, and
-                    we need to replay the whole sequence to rebuild
-                    it.
-
-                    Beyond that, only function key expansion could
-                    create more than two keys, but that should never
-                    generate mouse events, so it's okay to zero
-                    mock_input in that case too.
-
-                    Isn't this just the most wonderful code ever?  */
-                 if (t == last_real_key_start)
-                   {
-                     mock_input = 0;
-                     goto replay_key;
-                   }
-                 else
-                   {
-                     mock_input = last_real_key_start;
-                     goto replay_sequence;
-                   }
-               }
-
-             /* We turn unbound `drag-' events into `click-'
-                events, if the click would be bound.  */
-             else if (modifiers & (drag_modifier | double_modifier
-                                   | triple_modifier))
-               {
-                 while (modifiers & (drag_modifier | double_modifier
-                                     | triple_modifier))
+                 while (modifiers & (down_modifier | drag_modifier
+                                     | double_modifier | triple_modifier))
                    {
                      Lisp_Object new_head, new_click;
                      if (modifiers & triple_modifier)
                        modifiers ^= (double_modifier | triple_modifier);
-                     else
+                     else if (modifiers & (drag_modifier | double_modifier))
                        modifiers &= ~(drag_modifier | double_modifier);
-                     new_head =
-                       apply_modifiers (modifiers, XCONS (breakdown)->car);
-                     new_click =
-                       Fcons (new_head, Fcons (EVENT_START (key), Qnil));
+                     else
+                       {
+                         /* Dispose of this `down' event by simply jumping
+                            back to replay_key, to get another event.
+
+                            Note that if this event came from mock input,
+                            then just jumping back to replay_key will just
+                            hand it to us again.  So we have to wipe out any
+                            mock input.
+
+                            We could delete keybuf[t] and shift everything
+                            after that to the left by one spot, but we'd also
+                            have to fix up any variable that points into
+                            keybuf, and shifting isn't really necessary
+                            anyway.
+
+                            Adding prefixes for non-textual mouse clicks
+                            creates two characters of mock input, and both
+                            must be thrown away.  If we're only looking at
+                            the prefix now, we can just jump back to
+                            replay_key.  On the other hand, if we've already
+                            processed the prefix, and now the actual click
+                            itself is giving us trouble, then we've lost the
+                            state of the keymaps we want to backtrack to, and
+                            we need to replay the whole sequence to rebuild
+                            it.
+
+                            Beyond that, only function key expansion could
+                            create more than two keys, but that should never
+                            generate mouse events, so it's okay to zero
+                            mock_input in that case too.
+
+                            Isn't this just the most wonderful code ever?  */
+                         if (t == last_real_key_start)
+                           {
+                             mock_input = 0;
+                             goto replay_key;
+                           }
+                         else
+                           {
+                             mock_input = last_real_key_start;
+                             goto replay_sequence;
+                           }
+                       }
+
+                     new_head
+                       = apply_modifiers (modifiers, XCONS (breakdown)->car);
+                     new_click
+                       = Fcons (new_head, Fcons (EVENT_START (key), Qnil));
 
                      /* Look for a binding for this new key.  follow_key
                         promises that it didn't munge submaps the
                         last time we called it, since key was unbound.  */
-                     first_binding =
-                       (follow_key (new_click,
-                                    nmaps   - local_first_binding,
-                                    submaps + local_first_binding,
-                                    defs    + local_first_binding,
-                                    submaps + local_first_binding)
-                        + local_first_binding);
+                     first_binding
+                       (follow_key (new_click,
+                                      nmaps   - local_first_binding,
+                                      submaps + local_first_binding,
+                                      defs    + local_first_binding,
+                                      submaps + local_first_binding)
+                          + local_first_binding);
 
                      /* If that click is bound, go for it.  */
                      if (first_binding < nmaps)
@@ -4190,6 +4261,27 @@ read_key_sequence (keybuf, bufsize, prompt)
              fkey_next
                = get_keyelt (access_keymap (fkey_next, key, 1, 0));
 
+             /* If the function key map gives a function, not an
+                array, then call the function with no args and use
+                its value instead.  */
+             if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
+                 && fkey_end == t)
+               {
+                 struct gcpro gcpro1, gcpro2, gcpro3;
+                 Lisp_Object tem;
+                 tem = fkey_next;
+
+                 GCPRO3 (fkey_map, keytran_map, delayed_switch_frame);
+                 fkey_next = call1 (fkey_next, prompt);
+                 UNGCPRO;
+                 /* If the function returned something invalid,
+                    barf--don't ignore it.
+                    (To ignore it safely, we would need to gcpro a bunch of 
+                    other variables.)  */
+                 if (! (VECTORP (fkey_next) || STRINGP (fkey_next)))
+                   error ("Function in function-key-map returns invalid key sequence");
+               }
+
              /* If keybuf[fkey_start..fkey_end] is bound in the
                 function key map and it's a suffix of the current
                 sequence (i.e. fkey_end == t), replace it with
@@ -4197,7 +4289,7 @@ read_key_sequence (keybuf, bufsize, prompt)
              if ((VECTORP (fkey_next) || STRINGP (fkey_next))
                  && fkey_end == t)
                {
-                 int len = Flength (fkey_next);
+                 int len = XFASTINT (Flength (fkey_next));
 
                  t = fkey_start + len;
                  if (t >= bufsize)
@@ -4212,8 +4304,8 @@ read_key_sequence (keybuf, bufsize, prompt)
                      int i;
 
                      for (i = 0; i < len; i++)
-                       XFASTINT (keybuf[fkey_start + i]) =
-                         XSTRING (fkey_next)->data[i];
+                       XFASTINT (keybuf[fkey_start + i])
+                         XSTRING (fkey_next)->data[i];
                    }
                  
                  mock_input = t;
@@ -4262,14 +4354,35 @@ read_key_sequence (keybuf, bufsize, prompt)
            keytran_next
              = get_keyelt (access_keymap (keytran_next, key, 1, 0));
 
+           /* If the key translation map gives a function, not an
+              array, then call the function with no args and use
+              its value instead.  */
+           if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
+               && keytran_end == t)
+             {
+               struct gcpro gcpro1, gcpro2, gcpro3;
+               Lisp_Object tem;
+               tem = keytran_next;
+
+               GCPRO3 (keytran_map, keytran_map, delayed_switch_frame);
+               keytran_next = call1 (keytran_next, prompt);
+               UNGCPRO;
+               /* If the function returned something invalid,
+                  barf--don't ignore it.
+                  (To ignore it safely, we would need to gcpro a bunch of 
+                  other variables.)  */
+               if (! (VECTORP (keytran_next) || STRINGP (keytran_next)))
+                 error ("Function in function-key-map returns invalid key sequence");
+             }
+
            /* If keybuf[keytran_start..keytran_end] is bound in the
-              function key map and it's a suffix of the current
+              key translation map and it's a suffix of the current
               sequence (i.e. keytran_end == t), replace it with
               the binding and restart with keytran_start at the end. */
            if ((VECTORP (keytran_next) || STRINGP (keytran_next))
                && keytran_end == t)
              {
-               int len = Flength (keytran_next);
+               int len = XFASTINT (Flength (keytran_next));
 
                t = keytran_start + len;
                if (t >= bufsize)
@@ -4351,7 +4464,7 @@ and `quit-flag' is not set.\n\
 If the key sequence starts with a mouse click, then the sequence is read\n\
 using the keymaps of the buffer of the window clicked in, not the buffer\n\
 of the selected window as normal.\n\
-\n\
+""\n\
 `read-key-sequence' drops unbound button-down events, since you normally\n\
 only care about the click or drag events which follow them.  If a drag\n\
 or multi-click event is unbound, but the corresponding click event would\n\
@@ -4392,8 +4505,7 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 2, 0,
   if (NILP (continue_echo))
     this_command_key_count = 0;
 
-  i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
-                        NILP (prompt) ? 0 : XSTRING (prompt)->data);
+  i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])), prompt);
 
   if (i == -1)
     {
@@ -4503,11 +4615,11 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
 
   /* Prompt with buf, and then read a string, completing from and
      restricting to the set of all defined commands.  Don't provide
-     any initial input.  The last Qnil says not to perform a 
-     peculiar hack on the initial input.  */
+     any initial input.  Save the command read on the extended-command
+     history list. */
   function = Fcompleting_read (build_string (buf),
                               Vobarray, Qcommandp,
-                              Qt, Qnil, Qnil);
+                              Qt, Qnil, Qextended_command_history);
 
   /* Set this_command_keys to the concatenation of saved_keys and
      function, followed by a RET.  */
@@ -4896,6 +5008,8 @@ quit_throw_to_read_char ()
   if (poll_suppress_count == 0)
     abort ();
 #endif
+  if (XFRAME (internal_last_event_frame) != selected_frame)
+    Fhandle_switch_frame (make_lispy_switch_frame (internal_last_event_frame));
 
   _longjmp (getcjmp, 1);
 }
@@ -4917,7 +5031,11 @@ See also `current-input-mode'.")
   if (!NILP (quit)
       && (XTYPE (quit) != Lisp_Int
          || XINT (quit) < 0 || XINT (quit) > 0400))
-    error ("set-input-mode: QUIT must be an ASCII character.");
+    error ("set-input-mode: QUIT must be an ASCII character");
+
+#ifdef POLL_FOR_INPUT
+  stop_polling ();
+#endif
 
   reset_sys_modes ();
 #ifdef SIGIO
@@ -4947,6 +5065,11 @@ See also `current-input-mode'.")
     quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
 
   init_sys_modes ();
+
+#ifdef POLL_FOR_INPUT
+  poll_suppress_count = 1;
+  start_polling ();
+#endif
   return Qnil;
 }
 
@@ -5160,6 +5283,10 @@ syms_of_keyboard ()
   this_command_keys = Fmake_vector (make_number (40), Qnil);
   staticpro (&this_command_keys);
 
+  Qextended_command_history = intern ("extended-command-history");
+  Fset (Qextended_command_history, Qnil);
+  staticpro (&Qextended_command_history);
+
   kbd_buffer_frame_or_window
     = Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil);
   staticpro (&kbd_buffer_frame_or_window);
@@ -5332,7 +5459,7 @@ all input characters will have the control modifier applied to them.\n\
 \n\
 Note that the character ?\C-@, equivalent to the integer zero, does\n\
 not count as a control character; rather, it counts as a character\n\
-with no modifiers; thus, setting extra_keyboard_modifiers to zero\n\
+with no modifiers; thus, setting `extra-keyboard-modifiers' to zero\n\
 cancels any modification.");
   extra_keyboard_modifiers = 0;