(detect_coding_iso2022): Do not exclude posibility of
[bpt/emacs.git] / src / keyboard.c
index f46194d..39629ae 100644 (file)
@@ -1,5 +1,5 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95,96 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,89,93,94,95,96,97 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA.  */
 #include "window.h"
 #include "commands.h"
 #include "buffer.h"
+#include "charset.h"
 #include "disptab.h"
 #include "dispextern.h"
 #include "keyboard.h"
@@ -170,6 +171,9 @@ static int inhibit_local_menu_bar_menus;
 /* Nonzero means C-g should cause immediate error-signal.  */
 int immediate_quit;
 
+/* The user's ERASE setting.  */
+Lisp_Object Vtty_erase_char;
+
 /* Character to recognize as the help char.  */
 Lisp_Object Vhelp_char;
 
@@ -268,17 +272,17 @@ static int last_non_minibuf_size;
 static Lisp_Object Vauto_save_timeout;
 
 /* Total number of times read_char has returned.  */
-int num_input_chars;
+int num_input_events;
 
 /* Total number of times read_char has returned, outside of macros.  */
-int num_nonmacro_input_chars;
+int num_nonmacro_input_events;
 
 /* Auto-save automatically when this many characters have been typed
    since the last time.  */
 
 static int auto_save_interval;
 
-/* Value of num_nonmacro_input_chars as of last auto save.  */
+/* Value of num_nonmacro_input_events as of last auto save.  */
 
 int last_auto_save;
 
@@ -293,14 +297,12 @@ int last_point_position;
 /* The buffer that was current when the last command was started.  */
 Lisp_Object last_point_position_buffer;
 
-#ifdef MULTI_FRAME
 /* The frame in which the last input event occurred, or Qmacro if the
    last event came from a macro.  We use this to determine when to
    generate switch-frame events.  This may be cleared by functions
    like Fselect_frame, to make sure that a switch-frame event is
    generated by the next character.  */
 Lisp_Object internal_last_event_frame;
-#endif
 
 /* A user-visible version of the above, intended to allow users to
    figure out where the last event came from, if the event doesn't
@@ -315,6 +317,7 @@ Lisp_Object Qself_insert_command;
 Lisp_Object Qforward_char;
 Lisp_Object Qbackward_char;
 Lisp_Object Qundefined;
+Lisp_Object Qtimer_event_handler;
 
 /* read_key_sequence stores here the command definition of the
    key sequence that it reads.  */
@@ -341,6 +344,8 @@ Lisp_Object Vdeactivate_mark;
 Lisp_Object Vlucid_menu_bar_dirty_flag;
 Lisp_Object Qrecompute_lucid_menubar, Qactivate_menubar_hook;
 
+Lisp_Object Qecho_area_clear_hook;
+
 /* Hooks to run before and after each command.  */
 Lisp_Object Qpre_command_hook, Vpre_command_hook;
 Lisp_Object Qpost_command_hook, Vpost_command_hook;
@@ -439,7 +444,6 @@ Lisp_Object Qmake_frame_visible;
 /* Symbols to denote kinds of events.  */
 Lisp_Object Qfunction_key;
 Lisp_Object Qmouse_click;
-Lisp_Object Qtimer_event;
 /* Lisp_Object Qmouse_movement; - also an event header */
 
 /* Properties of event headers.  */
@@ -476,6 +480,10 @@ EMACS_TIME timer_check ();
 
 extern char *x_get_keysym_name ();
 
+static void record_menu_key ();
+
+void swallow_events ();
+
 Lisp_Object Qpolling_period;
 
 /* List of absolute timers.  Appears in order of next scheduled event.  */
@@ -521,9 +529,6 @@ int flow_control;
 #ifdef HAVE_WINDOW_SYSTEM
 #define POLL_FOR_INPUT
 #endif
-
-/* Non-nil enables Column Number mode.  */
-Lisp_Object Vcolumn_number_mode;
 \f
 /* Global variable declarations.  */
 
@@ -755,6 +760,10 @@ recursive_edit_1 ()
   val = command_loop ();
   if (EQ (val, Qt))
     Fsignal (Qquit, Qnil);
+  /* Handle throw from read_minibuf when using minibuffer
+     while it's active but we're in another window.  */
+  if (STRINGP (val))
+    Fsignal (Qerror, Fcons (val, Qnil));
 
   return unbind_to (count, Qnil);
 }
@@ -763,7 +772,7 @@ recursive_edit_1 ()
 
 record_auto_save ()
 {
-  last_auto_save = num_nonmacro_input_chars;
+  last_auto_save = num_nonmacro_input_events;
 }
 
 /* Make an auto save happen as soon as possible at command level.  */
@@ -888,10 +897,23 @@ cmd_error (data)
      Lisp_Object data;
 {
   Lisp_Object old_level, old_length;
+  char macroerror[50];
+
+  if (!NILP (executing_macro))
+    {
+      if (executing_macro_iterations == 1)
+       sprintf (macroerror, "After 1 kbd macro iteration: ");
+      else
+       sprintf (macroerror, "After %d kbd macro iterations: ",
+                executing_macro_iterations);
+    }
+  else
+    *macroerror = 0;
 
   Vstandard_output = Qt;
   Vstandard_input = Qt;
   Vexecuting_macro = Qnil;
+  executing_macro = Qnil;
   current_kboard->Vprefix_arg = Qnil;
   cancel_echoing ();
 
@@ -900,7 +922,7 @@ cmd_error (data)
   old_length = Vprint_length;
   XSETFASTINT (Vprint_level, 10);
   XSETFASTINT (Vprint_length, 10);
-  cmd_error_internal (data, NULL);
+  cmd_error_internal (data, macroerror);
   Vprint_level = old_level;
   Vprint_length = old_length;
 
@@ -1054,7 +1076,7 @@ Lisp_Object
 command_loop_1 ()
 {
   Lisp_Object cmd, tem;
-  int lose;
+  int lose, lose2;
   int nonundocount;
   Lisp_Object keybuf[30];
   int i;
@@ -1090,7 +1112,7 @@ command_loop_1 ()
     {
       if (NILP (Vunread_command_events)
          && NILP (Vexecuting_macro)
-         && !NILP (sit_for (0, post_command_idle_delay, 0, 1)))
+         && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
        safe_run_hooks (Qpost_command_idle_hook);
     }
 
@@ -1126,7 +1148,8 @@ command_loop_1 ()
 
          Fsit_for (make_number (2), Qnil, Qnil);
          /* Clear the echo area.  */
-         message2 (0);
+         message2 (0, 0);
+         safe_run_hooks (Qecho_area_clear_hook);
 
          unbind_to (count, Qnil);
 
@@ -1144,7 +1167,6 @@ command_loop_1 ()
 #endif /* C_ALLOCA */
 
 #if 0
-#ifdef MULTI_FRAME
       /* Select the frame that the last event came from.  Usually,
         switch-frame events will take care of this, but if some lisp
         code swallows a switch-frame event, we'll fix things up here.
@@ -1152,7 +1174,6 @@ command_loop_1 ()
       if (FRAMEP (internal_last_event_frame)
          && XFRAME (internal_last_event_frame) != selected_frame)
        Fselect_frame (internal_last_event_frame, Qnil);
-#endif
 #endif
       /* If it has changed current-menubar from previous value,
         really recompute the menubar from the value.  */
@@ -1167,7 +1188,11 @@ command_loop_1 ()
 
       /* Read next key sequence; i gets its length.  */
       i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
-                            Qnil, 0, 1);
+                            Qnil, 0, 1, 1);
+
+      /* A filter may have run while we were reading the input.  */
+      if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+       set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
 
       ++num_input_keys;
 
@@ -1248,22 +1273,27 @@ command_loop_1 ()
                {
                   struct Lisp_Char_Table *dp
                    = window_display_table (XWINDOW (selected_window));
-                 lose = FETCH_CHAR (PT);
-                 SET_PT (PT + 1);
+                 lose = FETCH_BYTE (PT);
+                 SET_PT (forward_point (1));
                  if ((dp
                       ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
                          ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
                           : (NILP (DISP_CHAR_VECTOR (dp, lose))
                              && (lose >= 0x20 && lose < 0x7f)))
                       : (lose >= 0x20 && lose < 0x7f))
+                     /* To extract the case of continuation on
+                         wide-column characters.  */
+                     && (WIDTH_BY_CHAR_HEAD (FETCH_BYTE (PT)) == 1)
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
+                     && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
+                         >= OVERLAY_MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_point)
                          == PT - 1)
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
-                     && NILP (Vcolumn_number_mode)
+                     && NILP (XWINDOW (selected_window)->column_number_displayed)
                      && NILP (Vexecuting_macro))
                    no_redisplay = direct_output_forward_char (1);
                  goto directly_done;
@@ -1272,8 +1302,8 @@ command_loop_1 ()
                {
                   struct Lisp_Char_Table *dp
                    = window_display_table (XWINDOW (selected_window));
-                 SET_PT (PT - 1);
-                 lose = FETCH_CHAR (PT);
+                 SET_PT (forward_point (-1));
+                 lose = FETCH_BYTE (PT);
                  if ((dp
                       ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
                          ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
@@ -1282,12 +1312,14 @@ command_loop_1 ()
                       : (lose >= 0x20 && lose < 0x7f))
                      && (XFASTINT (XWINDOW (selected_window)->last_modified)
                          >= MODIFF)
+                     && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
+                         >= OVERLAY_MODIFF)
                      && (XFASTINT (XWINDOW (selected_window)->last_point)
                          == PT + 1)
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
-                     && NILP (Vcolumn_number_mode)
+                     && NILP (XWINDOW (selected_window)->column_number_displayed)
                      && NILP (Vexecuting_macro))
                    no_redisplay = direct_output_forward_char (-1);
                  goto directly_done;
@@ -1296,7 +1328,7 @@ command_loop_1 ()
                       /* Try this optimization only on ascii keystrokes.  */
                       && INTEGERP (last_command_char))
                {
-                 unsigned char c = XINT (last_command_char);
+                 unsigned int c = XINT (last_command_char);
                  int value;
 
                  if (NILP (Vexecuting_macro)
@@ -1311,13 +1343,15 @@ command_loop_1 ()
                    }
                  lose = ((XFASTINT (XWINDOW (selected_window)->last_modified)
                           < MODIFF)
+                         || (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
+                             < OVERLAY_MODIFF)
                          || (XFASTINT (XWINDOW (selected_window)->last_point)
                              != PT)
                          || MODIFF <= SAVE_MODIFF
                          || windows_or_buffers_changed
                          || !EQ (current_buffer->selective_display, Qnil)
                          || detect_input_pending ()
-                         || !NILP (Vcolumn_number_mode)
+                         || !NILP (XWINDOW (selected_window)->column_number_displayed)
                          || !NILP (Vexecuting_macro));
                  value = internal_self_insert (c, 0);
                  if (value)
@@ -1326,7 +1360,7 @@ command_loop_1 ()
                    nonundocount = 0;
 
                  if (!lose
-                     && (PT == ZV || FETCH_CHAR (PT) == '\n'))
+                     && (PT == ZV || FETCH_BYTE (PT) == '\n'))
                    {
                      struct Lisp_Char_Table *dp
                        = window_display_table (XWINDOW (selected_window));
@@ -1373,22 +1407,6 @@ command_loop_1 ()
        }
     directly_done: ;
 
-      /* Note that the value cell will never directly contain nil
-        if the symbol is a local variable.  */
-      if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
-       safe_run_hooks (Qpost_command_hook);
-
-      if (!NILP (Vdeferred_action_list))
-       safe_run_hooks (Qdeferred_action_function);
-
-      if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
-       {
-         if (NILP (Vunread_command_events)
-             && NILP (Vexecuting_macro)
-             && !NILP (sit_for (0, post_command_idle_delay, 0, 1)))
-           safe_run_hooks (Qpost_command_idle_hook);
-       }
-
       /* If there is a prefix argument,
         1) We don't want Vlast_command to be ``universal-argument''
         (that would be dumb), so don't set Vlast_command,
@@ -1410,6 +1428,22 @@ command_loop_1 ()
          this_single_command_key_start = 0;
        }
 
+      /* Note that the value cell will never directly contain nil
+        if the symbol is a local variable.  */
+      if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
+       safe_run_hooks (Qpost_command_hook);
+
+      if (!NILP (Vdeferred_action_list))
+       safe_run_hooks (Qdeferred_action_function);
+
+      if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
+       {
+         if (NILP (Vunread_command_events)
+             && NILP (Vexecuting_macro)
+             && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
+           safe_run_hooks (Qpost_command_idle_hook);
+       }
+
       if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
        {
          if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
@@ -1664,17 +1698,22 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
      Lisp_Object prev_event;
      int *used_mouse_menu;
 {
-  register Lisp_Object c;
+  Lisp_Object c;
   int count;
   jmp_buf local_getcjmp;
   jmp_buf save_jump;
   int key_already_recorded = 0;
   Lisp_Object tem, save;
   Lisp_Object also_record;
+  struct gcpro gcpro1;
+
   also_record = Qnil;
 
   before_command_key_count = this_command_key_count;
   before_command_echo_length = echo_length ();
+  c = Qnil;
+
+  GCPRO1 (c);
 
  retry:
 
@@ -1713,7 +1752,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   if (!NILP (Vexecuting_macro))
     {
-#ifdef MULTI_FRAME
       /* We set this to Qmacro; since that's not a frame, nobody will
         try to switch frames on us, and the selected window will
         remain unchanged.
@@ -1725,7 +1763,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
         events read from a macro should never cause a new frame to be
         selected. */
       Vlast_event_frame = internal_last_event_frame = Qmacro;
-#endif
 
       /* Exit the macro if we are at the end.
         Also, some things replace the macro with t
@@ -1734,7 +1771,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          || executing_macro_index >= XFASTINT (Flength (Vexecuting_macro)))
        {
          XSETINT (c, -1);
-         return c;
+         RETURN_UNGCPRO (c);
        }
 
       c = Faref (Vexecuting_macro, make_number (executing_macro_index));
@@ -1757,9 +1794,15 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       goto reread_first;
     }
 
-  if (commandflag >= 0 && !input_pending
-      && !detect_input_pending_run_timers (0))
-    redisplay ();
+  if (commandflag >= 0)
+    {
+      if (input_pending
+         || detect_input_pending_run_timers (0))
+       swallow_events (0);
+
+      if (!input_pending)
+       redisplay ();
+    }
 
   /* Message turns off echoing unless more keystrokes turn it on again. */
   if (echo_area_glyphs && *echo_area_glyphs
@@ -1800,10 +1843,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (_setjmp (local_getcjmp))
     {
       XSETINT (c, quit_char);
-#ifdef MULTI_FRAME
       XSETFRAME (internal_last_event_frame, selected_frame);
       Vlast_event_frame = internal_last_event_frame;
-#endif
       /* If we report the quit char as an event,
         don't do so more than once.  */
       if (!NILP (Vinhibit_quit))
@@ -1825,6 +1866,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
            *tailp = Fcons (c, Qnil);
            kb->kbd_queue_has_data = 1;
            current_kboard = kb;
+           /* This is going to exit from read_char
+              so we had better get rid of this frame's stuff.  */
+           UNGCPRO;
            longjmp (wrong_kboard_jmpbuf, 1);
          }
       }
@@ -1855,9 +1899,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        {
          save_getcjmp (save_jump);
          restore_getcjmp (local_getcjmp);
-         tem0 = sit_for (echo_keystrokes, 0, 1, 1);
+         tem0 = sit_for (echo_keystrokes, 0, 1, 1, 0);
          restore_getcjmp (save_jump);
-         if (EQ (tem0, Qt))
+         if (EQ (tem0, Qt)
+             && ! CONSP (Vunread_command_events))
            echo_now ();
        }
     }
@@ -1866,7 +1911,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   if (commandflag != 0
       && auto_save_interval > 0
-      && num_nonmacro_input_chars - last_auto_save > max (auto_save_interval, 20)
+      && num_nonmacro_input_events - last_auto_save > max (auto_save_interval, 20)
       && !detect_input_pending_run_timers (0))
     {
       Fdo_auto_save (Qnil, Qnil);
@@ -1886,7 +1931,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Don't bring up a menu if we already have another event.  */
       && NILP (Vunread_command_events)
       && unread_command_char < 0)
-    c = read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
+    {
+      c = read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
+
+      /* Now that we have read an event, Emacs is not idle.  */
+      timer_stop_idle ();
+
+      RETURN_UNGCPRO (c);
+    }
 
   /* Maybe autosave and/or garbage collect due to idleness.  */
 
@@ -1908,7 +1960,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
       /* Auto save if enough time goes by without input.  */
       if (commandflag != 0
-         && num_nonmacro_input_chars > last_auto_save
+         && num_nonmacro_input_events > last_auto_save
          && INTEGERP (Vauto_save_timeout)
          && XINT (Vauto_save_timeout) > 0)
        {
@@ -1917,10 +1969,11 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          save_getcjmp (save_jump);
          restore_getcjmp (local_getcjmp);
          tem0 = sit_for (delay_level * XFASTINT (Vauto_save_timeout) / 4,
-                         0, 1, 1);
+                         0, 1, 1, 0);
          restore_getcjmp (save_jump);
 
-         if (EQ (tem0, Qt))
+         if (EQ (tem0, Qt)
+             && ! CONSP (Vunread_command_events))
            {
              Fdo_auto_save (Qnil, Qnil);
 
@@ -1936,6 +1989,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        }
     }
 
+  /* If this has become non-nil here, it has been set by a timer
+     or sentinel or filter.  */
+  if (CONSP (Vunread_command_events))
+    {
+      c = XCONS (Vunread_command_events)->car;
+      Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+    }
+
   /* Read something from current KBOARD's side queue, if possible.  */
 
   if (NILP (c))
@@ -1950,12 +2011,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          if (NILP (current_kboard->kbd_queue))
            current_kboard->kbd_queue_has_data = 0;
          input_pending = readable_events (0);
-#ifdef MULTI_FRAME
          if (EVENT_HAS_PARAMETERS (c)
              && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qswitch_frame))
            internal_last_event_frame = XCONS (XCONS (c)->cdr)->car;
          Vlast_event_frame = internal_last_event_frame;
-#endif
        }
     }
 
@@ -1975,6 +2034,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        if (kb->kbd_queue_has_data)
          {
            current_kboard = kb;
+           /* This is going to exit from read_char
+              so we had better get rid of this frame's stuff.  */
+           UNGCPRO;
            longjmp (wrong_kboard_jmpbuf, 1);
          }
     }
@@ -2012,6 +2074,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          if (single_kboard)
            goto wrong_kboard;
          current_kboard = kb;
+         /* This is going to exit from read_char
+            so we had better get rid of this frame's stuff.  */
+         UNGCPRO;
          longjmp (wrong_kboard_jmpbuf, 1);
        }
 #endif
@@ -2037,10 +2102,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  non_reread:
 
-  /* Now that we have read an event, Emacs is not idle--
-     unless the event was a timer event (not used now).  */
-  if (! (CONSP (c) && EQ (XCONS (c)->car, Qtimer_event)))
-    timer_stop_idle ();
+  timer_stop_idle ();
 
   start_polling ();
 
@@ -2056,12 +2118,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
  non_reread_1:
 
   /* Buffer switch events are only for internal wakeups
-     so don't show them to the user.  */
-  if (BUFFERP (c))
-    return c;
-
-  if (key_already_recorded)
-    return c;
+     so don't show them to the user.
+     Also, don't record a key if we already did.  */
+  if (BUFFERP (c) || key_already_recorded)
+    RETURN_UNGCPRO (c);
 
   /* Process special events within read_char
      and loop around to read another event.  */
@@ -2086,6 +2146,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     }
 
   /* Wipe the echo area.  */
+  if (echo_area_glyphs)
+    safe_run_hooks (Qecho_area_clear_hook);
   echo_area_glyphs = 0;
 
   /* Handle things that only apply to characters.  */
@@ -2093,7 +2155,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
     {
       /* If kbd_buffer_get_event gave us an EOF, return that.  */
       if (XINT (c) == -1)
-       return c;
+       RETURN_UNGCPRO (c);
 
       if (STRINGP (Vkeyboard_translate_table)
          && XSTRING (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c))
@@ -2141,6 +2203,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
  from_macro:
  reread_first:
+
   before_command_key_count = this_command_key_count;
   before_command_echo_length = echo_length ();
 
@@ -2165,7 +2228,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   /* Re-reading in the middle of a command */
  reread:
   last_input_char = c;
-  num_input_chars++;
+  num_input_events++;
 
   /* Process the help character specially if enabled */
   if (!NILP (Vhelp_form) && help_char_p (c))
@@ -2197,7 +2260,40 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        }
     }
 
-  return c;
+  RETURN_UNGCPRO (c);
+}
+
+/* Record a key that came from a mouse menu.
+   Record it for echoing, for this-command-keys, and so on.  */
+
+static void
+record_menu_key (c)
+     Lisp_Object c;
+{
+  /* Wipe the echo area.  */
+  echo_area_glyphs = 0;
+
+  record_char (c);
+
+  before_command_key_count = this_command_key_count;
+  before_command_echo_length = echo_length ();
+
+  /* Don't echo mouse motion events.  */
+  if (echo_keystrokes)
+    {
+      echo_char (c);
+
+      /* Once we reread a character, echoing can happen
+        the next time we pause to read a new one.  */
+      ok_to_echo_at_next_pause = 0;
+    }
+
+  /* Record this character as part of the current key.  */
+  add_command_key (c);
+
+  /* Re-reading in the middle of a command */
+  last_input_char = c;
+  num_input_events++;
 }
 
 /* Return 1 if should recognize C as "the help character".  */
@@ -2261,7 +2357,7 @@ record_char (c)
 
   store_kbd_macro_char (c);
 
-  num_nonmacro_input_chars++;
+  num_nonmacro_input_events++;
 }
 
 Lisp_Object
@@ -2465,7 +2561,6 @@ kbd_buffer_store_event (event)
            }
 #endif
 
-#ifdef MULTI_FRAME
          /* If this results in a quit_char being returned to Emacs as
             input, set Vlast_event_frame properly.  If this doesn't
             get returned to Emacs as an event, the next event read
@@ -2479,7 +2574,6 @@ kbd_buffer_store_event (event)
            internal_last_event_frame = focus;
            Vlast_event_frame = focus;
          }
-#endif
 
          last_event_timestamp = event->timestamp;
          interrupt_signal ();
@@ -2602,6 +2696,15 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 #endif /* not VMS */
     }
 
+  if (CONSP (Vunread_command_events))
+    {
+      Lisp_Object first;
+      first = XCONS (Vunread_command_events)->car;
+      Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+      *kbp = current_kboard;
+      return first;
+    }
+
   /* At this point, we know that there is a readable event available
      somewhere.  If the event queue is empty, then there must be a
      mouse movement enabled and available.  */
@@ -2714,7 +2817,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
         time, and leave the event in the queue for next time.  */
       else
        {
-#ifdef MULTI_FRAME
          Lisp_Object frame;
          Lisp_Object focus;
 
@@ -2732,7 +2834,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
              && XFRAME (frame) != selected_frame)
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
-#endif /* MULTI_FRAME */
 
          /* If we didn't decide to make a switch-frame event, go ahead
             and build a real event from the queue entry.  */
@@ -2779,7 +2880,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 
       obj = Qnil;
 
-#ifdef MULTI_FRAME
       /* Decide if we should generate a switch-frame event.  Don't
         generate switch-frame events for motion outside of all Emacs
         frames.  */
@@ -2796,7 +2896,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
        }
-#endif
 
       /* If we didn't decide to make a switch-frame event, go ahead and
         return a mouse-motion event.  */
@@ -2811,9 +2910,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 
   input_pending = readable_events (0);
 
-#ifdef MULTI_FRAME
   Vlast_event_frame = internal_last_event_frame;
-#endif
 
   return (obj);
 }
@@ -2875,29 +2972,6 @@ swallow_events (do_display)
          abort ();
 #endif
        }
-      /* Note that timer_event is currently never used.  */
-      else if (event->kind == timer_event)
-       {
-         Lisp_Object tem, lisp_event;
-         int was_locked = single_kboard;
-
-         tem = get_keymap_1 (Vspecial_event_map, 0, 0);
-         tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
-                           1);
-         lisp_event = Fcons (Qtimer_event,
-                             Fcons (Fcdr (event->frame_or_window), Qnil));
-         kbd_fetch_ptr = event + 1;
-         if (kbd_fetch_ptr == kbd_store_ptr)
-           input_pending = 0;
-         Fcommand_execute (tem, Qnil, Fvector (1, &lisp_event), Qt);
-         timers_run++;
-         if (do_display)
-           redisplay_preserve_echo_area ();
-
-         /* Resume allowing input from any kboard, if that was true before.  */
-         if (!was_locked)
-           any_kboard_state ();
-       }
       else
        break;
     }
@@ -2968,8 +3042,6 @@ timer_check (do_it_now)
   EMACS_TIME nexttime;
   EMACS_TIME now, idleness_now;
   Lisp_Object timers, idle_timers, chosen_timer;
-  /* Nonzero if we generate some events.  */
-  int events_generated = 0;
   struct gcpro gcpro1, gcpro2, gcpro3;
 
   EMACS_SET_SECS (nexttime, -1);
@@ -3106,64 +3178,27 @@ timer_check (do_it_now)
        {
          if (NILP (vector[0]))
            {
+             Lisp_Object tem;
+             int was_locked = single_kboard;
+             int count = specpdl_ptr - specpdl;
+
              /* Mark the timer as triggered to prevent problems if the lisp
                 code fails to reschedule it right.  */
              vector[0] = Qt;
 
-             /* Run the timer or queue a timer event.  */
-             if (1)
-               {
-                 Lisp_Object tem, event;
-                 int was_locked = single_kboard;
-                 int count = specpdl_ptr - specpdl;
-
-                 specbind (Qinhibit_quit, Qt);
+             specbind (Qinhibit_quit, Qt);
 
-                 tem = get_keymap_1 (Vspecial_event_map, 0, 0);
-                 tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
-                                   1);
-                 event = Fcons (Qtimer_event, Fcons (chosen_timer, Qnil));
-                 Fcommand_execute (tem, Qnil, Fvector (1, &event), Qt);
-                 timers_run++;
+             call1 (Qtimer_event_handler, chosen_timer);
+             timers_run++;
 
-                 unbind_to (count, Qnil);
+             unbind_to (count, Qnil);
 
-                 /* Resume allowing input from any kboard, if that was true before.  */
-                 if (!was_locked)
-                   any_kboard_state ();
+             /* Resume allowing input from any kboard, if that was true before.  */
+             if (!was_locked)
+               any_kboard_state ();
 
-                 /* Since we have handled the event,
-                    we don't need to tell the caller to wake up and do it.  */
-               }
-#if 0
-             else
-               {
-                 /* Generate a timer event so the caller will handle it.  */
-                 struct input_event event;
-
-                 event.kind = timer_event;
-                 event.modifiers = 0;
-                 event.x = event.y = Qnil;
-                 event.timestamp = triggertime;
-                 /* Store the timer in the frame slot.  */
-                 event.frame_or_window
-                   = Fcons (Fselected_frame (), chosen_timer);
-                 kbd_buffer_store_event (&event);
-
-                 last_timer_event = event;
-
-                 /* Tell caller to handle this event right away.  */
-                 events_generated = 1;
-                 EMACS_SET_SECS (nexttime, 0);
-                 EMACS_SET_USECS (nexttime, 0);
-
-                 /* Don't queue more than one event at once.
-                    When Emacs is ready for another, it will
-                    queue the next one.  */
-                 UNGCPRO;
-                 return nexttime;
-               }
-#endif /* 0 */
+             /* Since we have handled the event,
+                we don't need to tell the caller to wake up and do it.  */
            }
        }
       else
@@ -3171,10 +3206,6 @@ timer_check (do_it_now)
           return the amount of time to wait before it is ripe.  */
        {
          UNGCPRO;
-         /* But if we generated an event,
-            tell the caller to handle it now.  */
-         if (events_generated)
-           return nexttime;
          return difference;
        }
     }
@@ -3443,7 +3474,42 @@ char *lispy_function_keys[] =
     "oem_clear",     /* VK_OEM_CLEAR      0xFE */
   };
 
-#else
+#else /* not HAVE_NTGUI */
+
+#ifdef XK_kana_A
+static char *lispy_kana_keys[] =
+  {
+    /* X Keysym value */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x400 .. 0x40f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x410 .. 0x41f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x420 .. 0x42f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x430 .. 0x43f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x440 .. 0x44f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x450 .. 0x45f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x460 .. 0x46f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,"overline",0,
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x480 .. 0x48f */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x490 .. 0x49f */
+    0, "kana-fullstop", "kana-openingbracket", "kana-closingbracket", 
+    "kana-comma", "kana-conjunctive", "kana-WO", "kana-a",
+    "kana-i", "kana-u", "kana-e", "kana-o",
+    "kana-ya", "kana-yu", "kana-yo", "kana-tsu",
+    "prolongedsound", "kana-A", "kana-I", "kana-U",
+    "kana-E", "kana-O", "kana-KA", "kana-KI",
+    "kana-KU", "kana-KE", "kana-KO", "kana-SA",
+    "kana-SHI", "kana-SU", "kana-SE", "kana-SO",
+    "kana-TA", "kana-CHI", "kana-TSU", "kana-TE",
+    "kana-TO", "kana-NA", "kana-NI", "kana-NU",
+    "kana-NE", "kana-NO", "kana-HA", "kana-HI",
+    "kana-FU", "kana-HE", "kana-HO", "kana-MA",
+    "kana-MI", "kana-MU", "kana-ME", "kana-MO",
+    "kana-YA", "kana-YU", "kana-YO", "kana-RA",
+    "kana-RI", "kana-RU", "kana-RE", "kana-RO",
+    "kana-WA", "kana-N", "voicedsound", "semivoicedsound",
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x4e0 .. 0x4ef */
+    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x4f0 .. 0x4ff */
+  };
+#endif /* XK_kana_A */
 
 #define FUNCTION_KEY_OFFSET 0xff00
 
@@ -3466,7 +3532,8 @@ static char *lispy_function_keys[] =
     0, 0, 0, 0, 0, 0, 0,
     "escape",
     0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0xff20...2f */
+    0, "kanji", "muhenkan", 
+             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0xff20...2f */
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0xff30...3f */
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 0xff40...4f */
 
@@ -3541,9 +3608,31 @@ static char *lispy_function_keys[] =
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,     /* 0xfff0 */
     0, 0, 0, 0, 0, 0, 0, "delete"
-    };
+  };
 
-#endif /* HAVE_NTGUI */
+/* ISO 9995 Function and Modifier Keys; the first byte is 0xFE.  */
+#define ISO_FUNCTION_KEY_OFFSET 0xfe00
+
+static char *iso_lispy_function_keys[] =
+  {
+    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xfe00 */
+    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xfe08 */
+    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xfe10 */
+    0, 0, 0, 0, 0, 0, 0, 0,    /* 0xfe18 */
+    "iso-lefttab",             /* 0xfe20 */
+    "iso-move-line-up", "iso-move-line-down", 
+    "iso-partial-line-up", "iso-partial-line-down", 
+    "iso-partial-space-left", "iso-partial-space-right", 
+    "iso-set-margin-left", "iso-set-margin-right", /* 0xffe27, 28 */
+    "iso-release-margin-left", "iso-release-margin-right",
+    "iso-release-both-margins",
+    "iso-fast-cursor-left", "iso-fast-cursor-right",
+    "iso-fast-cursor-up", "iso-fast-cursor-down",
+    "iso-continuous-underline", "iso-discontinuous-underline", /* 0xfe30, 31 */
+    "iso-emphasize", "iso-center-object", "iso-enter", /* ... 0xfe34 */
+  };
+
+#endif /* not HAVE_NTGUI */
 
 static char *lispy_mouse_names[] =
 {
@@ -3623,6 +3712,10 @@ make_lispy_event (event)
        c |= (event->modifiers
              & (meta_modifier | alt_modifier
                 | hyper_modifier | super_modifier));
+       /* Distinguish Shift-SPC from SPC.  */
+       if ((event->code & 0377) == 040
+           && event->modifiers & shift_modifier)
+         c |= shift_modifier;
        button_down_time = 0;
        XSETFASTINT (lispy_c, c);
        return lispy_c;
@@ -3657,17 +3750,33 @@ make_lispy_event (event)
                                      (unsigned)-1);
        }
 
-      return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
-                                 event->modifiers,
-                                 Qfunction_key, Qnil,
-                                 lispy_function_keys, &func_key_syms,
-                                 (sizeof (lispy_function_keys)
-                                  / sizeof (lispy_function_keys[0])));
-      break;
-
-      /* Note that timer_event is currently never used.  */
-    case timer_event:
-      return Fcons (Qtimer_event, Fcons (Fcdr (event->frame_or_window), Qnil));
+#ifdef XK_kana_A
+      if (event->code >= 0x400 && event->code < 0x500)
+       return modify_event_symbol (event->code - 0x400,
+                                   event->modifiers & ~shift_modifier,
+                                   Qfunction_key, Qnil,
+                                   lispy_kana_keys, &func_key_syms,
+                                   (sizeof (lispy_kana_keys)
+                                    / sizeof (lispy_kana_keys[0])));
+#endif /* XK_kana_A */
+
+#ifdef ISO_FUNCTION_KEY_OFFSET
+      if (event->code < FUNCTION_KEY_OFFSET
+         && event->code >= ISO_FUNCTION_KEY_OFFSET)
+       return modify_event_symbol (event->code - ISO_FUNCTION_KEY_OFFSET,
+                                   event->modifiers,
+                                   Qfunction_key, Qnil,
+                                   iso_lispy_function_keys, &func_key_syms,
+                                   (sizeof (iso_lispy_function_keys)
+                                    / sizeof (iso_lispy_function_keys[0])));
+      else
+#endif
+       return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
+                                   event->modifiers,
+                                   Qfunction_key, Qnil,
+                                   lispy_function_keys, &func_key_syms,
+                                   (sizeof (lispy_function_keys)
+                                    / sizeof (lispy_function_keys[0])));
 
 #ifdef HAVE_MOUSE
       /* A mouse click.  Figure out where it is, decide whether it's
@@ -3762,7 +3871,7 @@ make_lispy_event (event)
            else
              {
                int pixcolumn, pixrow;
-               column -= XINT (XWINDOW (window)->left);
+               column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
                row -= XINT (XWINDOW (window)->top);
                glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
                XSETINT (event->x, pixcolumn);
@@ -3914,7 +4023,7 @@ make_lispy_event (event)
       }
 
 #ifdef WINDOWSNT
-    case win32_scroll_bar_click:
+    case w32_scroll_bar_click:
       {
        int button = event->code;
        int is_double;
@@ -3942,7 +4051,7 @@ make_lispy_event (event)
                                        Fcons (part, Qnil)))));
        }
 
-       /* Always treat Win32 scroll bar events as clicks. */
+       /* Always treat W32 scroll bar events as clicks. */
        event->modifiers |= click_modifier;
 
        {
@@ -3988,7 +4097,6 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
      Lisp_Object x, y;
      unsigned long time;
 {
-#ifdef MULTI_FRAME
   /* Is it a scroll bar movement?  */
   if (frame && ! NILP (bar_window))
     {
@@ -4007,18 +4115,13 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
 
   /* Or is it an ordinary mouse movement?  */
   else
-#endif /* MULTI_FRAME */
     {
       int area;
       Lisp_Object window;
       Lisp_Object posn;
       int column, row;
 
-#ifdef MULTI_FRAME
       if (frame)
-#else
-      if (1)
-#endif
        {
          /* It's in a frame; which window on that frame?  */
          pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row,
@@ -4031,7 +4134,7 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
       if (WINDOWP (window))
        {
          int pixcolumn, pixrow;
-         column -= XINT (XWINDOW (window)->left);
+         column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
          row -= XINT (XWINDOW (window)->top);
          glyph_to_pixel_coords (frame, column, row, &pixcolumn, &pixrow);
          XSETINT (x, pixcolumn);
@@ -4045,13 +4148,11 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
            XSETINT (posn,
                     buffer_posn_from_coords (XWINDOW (window), column, row));
        }
-#ifdef MULTI_FRAME
       else if (frame != 0)
        {
          XSETFRAME (window, frame);
          posn = Qnil;
        }
-#endif
       else
        {
          window = Qnil;
@@ -4465,7 +4566,7 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
       /* No; let's create it.  */
       if (!NILP (name_alist))
        value = Fcdr_safe (Fassq (symbol_int, name_alist));
-      else if (name_table[symbol_num])
+      else if (name_table != 0 && name_table[symbol_num])
        value = intern (name_table[symbol_num]);
 
 #ifdef HAVE_WINDOW_SYSTEM
@@ -4707,7 +4808,7 @@ gobble_input (expected)
   if (interrupt_input)
     {
       SIGMASKTYPE mask;
-      mask = sigblockx (SIGIO);
+      mask = sigblock (sigmask (SIGIO));
       read_avail_input (expected);
       sigsetmask (mask);
     }
@@ -4716,7 +4817,7 @@ gobble_input (expected)
   if (read_socket_hook && !interrupt_input && poll_suppress_count == 0)
     {
       SIGMASKTYPE mask;
-      mask = sigblockx (SIGALRM);
+      mask = sigblock (sigmask (SIGALRM));
       read_avail_input (expected);
       sigsetmask (mask);
     }
@@ -4756,7 +4857,7 @@ record_asynch_buffer_change ()
   if (interrupt_input)
     {
       SIGMASKTYPE mask;
-      mask = sigblockx (SIGIO);
+      mask = sigblock (sigmask (SIGIO));
       kbd_buffer_store_event (&event);
       sigsetmask (mask);
     }
@@ -4793,8 +4894,7 @@ read_avail_input (expected)
 
   if (read_socket_hook)
     /* No need for FIONREAD or fcntl; just say don't wait.  */
-    nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE,
-                                expected, expected);
+    nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE, expected);
   else
     {
       /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
@@ -4848,6 +4948,13 @@ read_avail_input (expected)
 #else
          nread = read (input_fd, cbuf, n_to_read);
 #endif
+         /* POSIX infers that processes which are not in the session leader's
+            process group won't get SIGHUP's at logout time.  BSDI adheres to
+            this part standard and returns -1 from read(0) with errno==EIO
+            when the control tty is taken away.
+            Jeffrey Honig <jch@bsdi.com> says this is generally safe.  */
+         if (nread == -1 && errno == EIO)
+           kill (0, SIGHUP);
 #if defined (AIX) && (! defined (aix386) && defined (_BSD))
          /* The kernel sometimes fails to deliver SIGHUP for ptys.
             This looks incorrect, but it isn't, because _BSD causes
@@ -4891,11 +4998,7 @@ read_avail_input (expected)
            cbuf[i] &= ~0x80;
 
          buf[i].code = cbuf[i];
-#ifdef MULTI_FRAME
          XSETFRAME (buf[i].frame_or_window, selected_frame);
-#else
-         buf[i].frame_or_window = Qnil;
-#endif
        }
     }
 
@@ -4927,7 +5030,7 @@ input_available_signal (signo)
   extern int select_alarmed;
 #endif
 
-#if defined(USG) && !defined(POSIX_SIGNALS)
+#if defined (USG) && !defined (POSIX_SIGNALS)
   /* USG systems forget handlers when they are used;
      must reestablish each time */
   signal (signo, input_available_signal);
@@ -5093,7 +5196,7 @@ menu_bar_items (old)
   for (mapno = nmaps - 1; mapno >= 0; mapno--)
     {
       if (! NILP (maps[mapno]))
-       def = get_keyelt (access_keymap (maps[mapno], Qmenu_bar, 1, 0));
+       def = get_keyelt (access_keymap (maps[mapno], Qmenu_bar, 1, 0), 0);
       else
        def = Qnil;
 
@@ -5381,6 +5484,8 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
        {
          Lisp_Object tem;
 
+         record_menu_key (XCONS (value)->car);
+
          /* If we got multiple events, unread all but
             the first.
             There is no way to prevent those unread events
@@ -5391,10 +5496,13 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
             they won't confuse things.  */
          for (tem = XCONS (value)->cdr; !NILP (tem);
               tem = XCONS (tem)->cdr)
-           if (SYMBOLP (XCONS (tem)->car)
-               || INTEGERP (XCONS (tem)->car))
-             XCONS (tem)->car
-               = Fcons (XCONS (tem)->car, Qnil);
+           {
+             record_menu_key (XCONS (tem)->car);
+             if (SYMBOLP (XCONS (tem)->car)
+                 || INTEGERP (XCONS (tem)->car))
+               XCONS (tem)->car
+                 = Fcons (XCONS (tem)->car, Qnil);
+           }
 
          /* If we got more than one event, put all but the first
             onto this list to be read later.
@@ -5675,7 +5783,7 @@ follow_key (key, nmaps, current, defs, next)
          {
            Lisp_Object def;
            def = get_keyelt (access_keymap (current[i],
-                                            meta_prefix_char, 1, 0));
+                                            meta_prefix_char, 1, 0), 0);
 
            /* Note that since we pass the resulting bindings through
               get_keymap_1, non-prefix bindings for meta-prefix-char
@@ -5700,7 +5808,7 @@ follow_key (key, nmaps, current, defs, next)
          else
            map = current[i];
 
-         defs[i] = get_keyelt (access_keymap (map, key, 1, 0));
+         defs[i] = get_keyelt (access_keymap (map, key, 1, 0), 0);
          if (! NILP (defs[i]))
            first_binding = i;
        }
@@ -5748,16 +5856,20 @@ follow_key (key, nmaps, current, defs, next)
 
    If the user switches frames in the midst of a key sequence, we put
    off the switch-frame event until later; the next call to
-   read_char will return it.  */
+   read_char will return it.
+
+   If FIX_CURRENT_BUFFER is nonzero, we restore current_buffer
+   from the selected window's buffer.  */
 
 static int
 read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
-                  can_return_switch_frame)
+                  can_return_switch_frame, fix_current_buffer)
      Lisp_Object *keybuf;
      int bufsize;
      Lisp_Object prompt;
      int dont_downcase_last;
      int can_return_switch_frame;
+     int fix_current_buffer;
 {
   int count = specpdl_ptr - specpdl;
 
@@ -5849,12 +5961,12 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   /* Save the status of key translation before each step,
      so that we can restore this after downcasing.  */
   Lisp_Object prev_fkey_map;
-  Lisp_Object prev_fkey_start;
-  Lisp_Object prev_fkey_end;
+  int prev_fkey_start;
+  int prev_fkey_end;
 
   Lisp_Object prev_keytran_map;
-  Lisp_Object prev_keytran_start;
-  Lisp_Object prev_keytran_end;
+  int prev_keytran_start;
+  int prev_keytran_end;
 
   int junk;
 
@@ -6097,6 +6209,14 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          if (BUFFERP (key))
            {
              mock_input = t;
+             /* Reset the current buffer from the selected window
+                in case something changed the former and not the latter.
+                This is to be more consistent with the behavior
+                of the command_loop_1.  */
+             if (fix_current_buffer)
+               if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+                 Fset_buffer (XWINDOW (selected_window)->buffer);
+
              orig_local_map = get_local_map (PT, current_buffer);
              goto replay_sequence;
            }
@@ -6440,7 +6560,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  fkey_next
                    = get_keymap_1
                      (get_keyelt
-                      (access_keymap (fkey_map, meta_prefix_char, 1, 0)),
+                      (access_keymap (fkey_map, meta_prefix_char, 1, 0), 0),
                       0, 1);
                  XSETFASTINT (key, XFASTINT (key) & ~meta_modifier);
                }
@@ -6448,7 +6568,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                fkey_next = fkey_map;
 
              fkey_next
-               = get_keyelt (access_keymap (fkey_next, key, 1, 0));
+               = get_keyelt (access_keymap (fkey_next, key, 1, 0), 0);
 
 #if 0 /* I didn't turn this on, because it might cause trouble
         for the mapping of return into C-m and tab into C-i.  */
@@ -6548,7 +6668,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                keytran_next
                  = get_keymap_1
                    (get_keyelt
-                    (access_keymap (keytran_map, meta_prefix_char, 1, 0)),
+                    (access_keymap (keytran_map, meta_prefix_char, 1, 0), 0),
                     0, 1);
                XSETFASTINT (key, XFASTINT (key) & ~meta_modifier);
              }
@@ -6556,7 +6676,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              keytran_next = keytran_map;
 
            keytran_next
-             = get_keyelt (access_keymap (keytran_next, key, 1, 0));
+             = get_keyelt (access_keymap (keytran_next, key, 1, 0), 0);
 
            /* If the key translation map gives a function, not an
               array, then call the function with no args and use
@@ -6817,7 +6937,7 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
 
   i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
                         prompt, ! NILP (dont_downcase_last),
-                        ! NILP (can_return_switch_frame));
+                        ! NILP (can_return_switch_frame), 0);
 
   if (i == -1)
     {
@@ -6874,7 +6994,13 @@ a special event, so ignore the prefix argument and don't clear it.")
       final = Findirect_function (cmd);
 
       if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload)))
-       do_autoload (final, cmd);
+       {
+         struct gcpro gcpro1, gcpro2;
+
+         GCPRO2 (cmd, prefixarg);
+         do_autoload (final, cmd);
+         UNGCPRO;
+       }
       else
        break;
     }
@@ -6918,12 +7044,13 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   Lisp_Object function;
   char buf[40];
   Lisp_Object saved_keys;
-  struct gcpro gcpro1;
+  Lisp_Object bindings, value;
+  struct gcpro gcpro1, gcpro2;
 
   saved_keys = Fvector (this_command_key_count,
                        XVECTOR (this_command_keys)->contents);
   buf[0] = 0;
-  GCPRO1 (saved_keys);
+  GCPRO2 (saved_keys, prefixarg);
 
   if (EQ (prefixarg, Qminus))
     strcpy (buf, "- ");
@@ -6959,7 +7086,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
      history list. */
   function = Fcompleting_read (build_string (buf),
                               Vobarray, Qcommandp,
-                              Qt, Qnil, Qextended_command_history);
+                              Qt, Qnil, Qextended_command_history, Qnil);
 
   if (STRINGP (function) && XSTRING (function)->size == 0)
     error ("No command name given");
@@ -7000,24 +7127,47 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   if (!NILP (Vsuggest_key_bindings)
       && NILP (Vexecuting_macro)
       && SYMBOLP (function))
-    {
-      Lisp_Object bindings;
+    bindings = Fwhere_is_internal (function, Voverriding_local_map,
+                                  Qt, Qnil);
+  else
+    bindings = Qnil;
 
-      bindings = Fwhere_is_internal (function, Voverriding_local_map,
-                                    Qt, Qnil);
+  value = Qnil;
+  GCPRO2 (bindings, value);
+  value = Fcommand_execute (function, Qt, Qnil, Qnil);
 
-      if (!NILP (bindings))
+  /* If the command has a key binding, print it now.  */
+  if (!NILP (bindings))
+    {
+      /* But first wait, and skip the message if there is input.  */
+      if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings)
+                           ? Vsuggest_key_bindings : make_number (2)),
+                          Qnil, Qnil))
+         && ! CONSP (Vunread_command_events))
        {
-         message ("You can run the command `%s' by typing %s",
+         Lisp_Object binding;
+         char *newmessage;
+         char *oldmessage = echo_area_glyphs;
+         int oldmessage_len = echo_area_glyphs_length;
+
+         binding = Fkey_description (bindings);
+
+         newmessage
+           = (char *) alloca (XSYMBOL (function)->name->size
+                              + XSTRING (binding)->size
+                              + 100);
+         sprintf (newmessage, "You can run the command `%s' by typing %s",
                   XSYMBOL (function)->name->data,
-                  XSTRING (Fkey_description (bindings))->data);
-         Fsit_for ((NUMBERP (Vsuggest_key_bindings)
-                    ? Vsuggest_key_bindings : make_number (2)),
-                   Qnil, Qnil);
+                  XSTRING (binding)->data);
+         message1_nolog (newmessage);
+         if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings)
+                               ? Vsuggest_key_bindings : make_number (2)),
+                              Qnil, Qnil)))
+           message2_nolog (oldmessage, oldmessage_len);
        }
     }
 
-  return Fcommand_execute (function, Qt, Qnil, Qnil);
+  RETURN_UNGCPRO (value);
 }
 
 /* Find the set of keymaps now active.
@@ -7071,8 +7221,7 @@ detect_input_pending ()
   return input_pending;
 }
 
-/* Return nonzero if input events are pending.
-   Execute timers immediately; don't make events for them.  */
+/* Return nonzero if input events are pending, and run any pending timers.  */
 
 detect_input_pending_run_timers (do_display)
      int do_display;
@@ -7096,6 +7245,18 @@ clear_input_pending ()
   input_pending = 0;
 }
 
+/* Return nonzero if there are pending requeued events.
+   This isn't used yet.  The hope is to make wait_reading_process_input
+   call it, and return return if it runs Lisp code that unreads something.
+   The problem is, kbd_buffer_get_event needs to be fixed to know what
+   to do in that case.  It isn't trivial.  */
+
+requeued_events_pending_p ()
+{
+  return (!NILP (Vunread_command_events) || unread_command_char != -1);
+}
+
+
 DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 0, 0,
   "T if command input is currently available with no waiting.\n\
 Actually, the value is nil only if we can be sure that no input is available.")
@@ -7291,7 +7452,7 @@ stuff_buffered_input (stuffstring)
      Lisp_Object stuffstring;
 {
 /* stuff_char works only in BSD, versions 4.2 and up.  */
-#ifdef BSD
+#ifdef BSD_SYSTEM
 #ifndef BSD4_1
   register unsigned char *p;
 
@@ -7321,7 +7482,7 @@ stuff_buffered_input (stuffstring)
     }
   input_pending = 0;
 #endif
-#endif /* BSD and not BSD4_1 */
+#endif /* BSD_SYSTEM and not BSD4_1 */
 }
 \f
 set_waiting_for_input (time_to_clear)
@@ -7365,7 +7526,7 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
   /* Must preserve main program's value of errno.  */
   int old_errno = errno;
 
-#if defined(USG) && !defined(POSIX_SIGNALS)
+#if defined (USG) && !defined (POSIX_SIGNALS)
   if (!read_socket_hook && NILP (Vwindow_system))
     {
       /* USG systems forget handlers when they are used;
@@ -7377,11 +7538,17 @@ interrupt_signal (signalnum)    /* If we don't have an argument, */
 
   cancel_echoing ();
 
-  if (!NILP (Vquit_flag) && FRAME_TERMCAP_P (selected_frame))
+  if (!NILP (Vquit_flag)
+      && (FRAME_TERMCAP_P (selected_frame) || FRAME_MSDOS_P (selected_frame)))
     {
+      /* If SIGINT isn't blocked, don't let us be interrupted by
+        another SIGINT, it might be harmful due to non-reentrancy
+        in I/O functions.  */
+      sigblock (sigmask (SIGINT));
+
       fflush (stdout);
       reset_sys_modes ();
-      sigfree ();
+
 #ifdef SIGTSTP                 /* Support possible in later USG versions */
 /*
  * On systems which can suspend the current process and return to the original
@@ -7460,6 +7627,7 @@ interrupt_signal (signalnum)      /* If we don't have an argument, */
 #endif /* not MSDOS */
       fflush (stdout);
       init_sys_modes ();
+      sigfree ();
     }
   else
     {
@@ -7505,12 +7673,10 @@ quit_throw_to_read_char ()
     abort ();
 #endif
 #endif
-#ifdef MULTI_FRAME
   if (FRAMEP (internal_last_event_frame)
       && XFRAME (internal_last_event_frame) != selected_frame)
     do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
                     Qnil, 0);
-#endif
 
   _longjmp (getcjmp, 1);
 }
@@ -7687,12 +7853,10 @@ init_keyboard ()
 #endif
   input_pending = 0;
 
-#ifdef MULTI_FRAME
   /* This means that command_loop_1 won't try to select anything the first
      time through.  */
   internal_last_event_frame = Qnil;
   Vlast_event_frame = internal_last_event_frame;
-#endif
 
 #ifdef MULTI_KBOARD
   current_kboard = initial_kboard;
@@ -7765,6 +7929,9 @@ struct event_head head_table[] = {
 
 syms_of_keyboard ()
 {
+  Qtimer_event_handler = intern ("timer-event-handler");
+  staticpro (&Qtimer_event_handler);
+
   Qdisabled_command_hook = intern ("disabled-command-hook");
   staticpro (&Qdisabled_command_hook);
 
@@ -7802,8 +7969,6 @@ syms_of_keyboard ()
   staticpro (&Qfunction_key);
   Qmouse_click = intern ("mouse-click");
   staticpro (&Qmouse_click);
-  Qtimer_event = intern ("timer-event");
-  staticpro (&Qtimer_event);
 
   Qmenu_enable = intern ("menu-enable");
   staticpro (&Qmenu_enable);
@@ -7899,6 +8064,12 @@ syms_of_keyboard ()
   unread_switch_frame = Qnil;
   staticpro (&unread_switch_frame);
 
+  internal_last_event_frame = Qnil;
+  staticpro (&internal_last_event_frame);
+
+  read_key_sequence_cmd = Qnil;
+  staticpro (&read_key_sequence_cmd);
+
   defsubr (&Sevent_convert_list);
   defsubr (&Sread_key_sequence);
   defsubr (&Srecursive_edit);
@@ -8005,14 +8176,25 @@ by position only.");
   inhibit_local_menu_bar_menus = 0;
 
   DEFVAR_INT ("num-input-keys", &num_input_keys,
-    "Number of complete keys read from the keyboard so far.");
+    "Number of complete key sequences read as input so far.\n\
+This includes key sequences read from keyboard macros.\n\
+The number is effectively the number of interactive command invocations.");
   num_input_keys = 0;
 
+  DEFVAR_INT ("num-nonmacro-input-events", &num_nonmacro_input_events,
+    "Number of input events read from the keyboard so far.\n\
+This does not include events generated by keyboard macros.");
+  num_nonmacro_input_events = 0;
+
   DEFVAR_LISP ("last-event-frame", &Vlast_event_frame,
     "The frame in which the most recently read event occurred.\n\
 If the last event came from a keyboard macro, this is set to `macro'.");
   Vlast_event_frame = Qnil;
 
+  /* This variable is set up in sysdep.c.  */
+  DEFVAR_LISP ("tty-erase-char", &Vtty_erase_char,
+    "The ERASE character as set by the user with stty.");
+
   DEFVAR_LISP ("help-char", &Vhelp_char,
     "Character to recognize as meaning Help.\n\
 When it is read, do `(eval help-form)', and display result if it's a string.\n\
@@ -8115,6 +8297,13 @@ This feature is obsolete; use idle timers instead.  See `etc/NEWS'.");
 This is measured in microseconds.");
   post_command_idle_delay = 100000;
 
+#if 0
+  DEFVAR_LISP ("echo-area-clear-hook", ...,
+    "Normal hook run when clearing the echo area.");
+#endif
+  Qecho_area_clear_hook = intern ("echo-area-clear-hook");
+  XSYMBOL (Qecho_area_clear_hook)->value = Qnil;
+
   DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
     "t means menu bar, specified Lucid style, needs to be recomputed.");
   Vlucid_menu_bar_dirty_flag = Qnil;
@@ -8126,9 +8315,11 @@ The elements of the list are event types that may have menu bar bindings.");
 
   DEFVAR_KBOARD ("overriding-terminal-local-map",
                 Voverriding_terminal_local_map,
-    "Keymap that overrides all other local keymaps.\n\
+    "Per-terminal keymap that overrides all other local keymaps.\n\
 If this variable is non-nil, it is used as a keymap instead of the\n\
-buffer's local map, and the minor mode keymaps and text property keymaps.");
+buffer's local map, and the minor mode keymaps and text property keymaps.\n\
+This variable is intended to let commands such as `universal-argumemnt'\n\
+set up a different keymap for reading the next command.");
 
   DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
     "Keymap that overrides all other local keymaps.\n\
@@ -8172,10 +8363,6 @@ The value can be a length of time to show the message for.\n\
 If the value is non-nil and not a number, we wait 2 seconds.");
   Vsuggest_key_bindings = Qt;
 
-  DEFVAR_LISP ("column-number-mode", &Vcolumn_number_mode,
-    "Non-nil enables display of the current column number in the mode line.");
-  Vcolumn_number_mode = Qnil;
-
   DEFVAR_LISP ("timer-list", &Vtimer_list,
     "List of active absolute time timers in order of increasing time");
   Vtimer_list = Qnil;