]> code.delx.au - gnu-emacs/blobdiff - src/keyboard.c
(Frename_file) [WINDOWSNT]: Remove conditional code.
[gnu-emacs] / src / keyboard.c
index 6e4485b1460166a0693cddd6fa2880cb1f007885..15f8eed53cbfa5db5ad975c7b88e8f001d974683 100644 (file)
@@ -1,5 +1,5 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,89,93,94,95,96 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 /* Allow config.h to undefine symbols found here.  */
 #include <signal.h>
@@ -56,6 +57,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "xterm.h"
 #endif
 
+#ifdef HAVE_NTGUI
+#include "w32term.h"
+#endif /* HAVE_NTGUI */
+
 /* Include systime.h after xterm.h to avoid double inclusion of time.h. */
 #include "systime.h"
 
@@ -74,7 +79,7 @@ int interrupt_input_pending;
 /* File descriptor to use for input.  */
 extern int input_fd;
 
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
 /* Make all keyboard buffers much bigger when using X windows.  */
 #define KBD_BUFFER_SIZE 4096
 #else  /* No X-windows, character input */
@@ -120,6 +125,18 @@ Lisp_Object recent_keys; /* A vector, holding the last 100 keystrokes */
 Lisp_Object this_command_keys;
 int this_command_key_count;
 
+/* Record values of this_command_key_count and echo_length ()
+   before this command was read.  */
+static int before_command_key_count;
+static int before_command_echo_length;
+/* Values of before_command_key_count and before_command_echo_length
+   saved by reset-this-command-lengths.  */
+static int before_command_key_count_1;
+static int before_command_echo_length_1;
+/* Flag set by reset-this-command-lengths,
+   saying to reset the lengths when add_command_key is called.  */
+static int before_command_restore_flag;
+
 extern int minbuf_level;
 
 extern struct backtrace *backtrace_list;
@@ -139,6 +156,10 @@ int waiting_for_input;
 /* True while displaying for echoing.   Delays C-g throwing.  */
 static int echoing;
 
+/* True means we can start echoing at the next input pause
+   even though there is something in the echo area.  */
+static char *ok_to_echo_at_next_pause;
+
 /* Nonzero means disregard local maps for the menu bar.  */
 static int inhibit_local_menu_bar_menus;
 
@@ -160,6 +181,12 @@ Lisp_Object Vprefix_help_command;
 /* List of items that should move to the end of the menu bar.  */
 Lisp_Object Vmenu_bar_final_items;
 
+/* Non-nil means show the equivalent key-binding for
+   any M-x command that has one.
+   The value can be a length of time to show the message for.
+   If the value is non-nil and not a number, we wait 2 seconds.  */
+Lisp_Object Vsuggest_key_bindings;
+
 /* Character that causes a quit.  Normally C-g.
 
    If we are running on an ordinary terminal, this must be an ordinary
@@ -187,6 +214,10 @@ Lisp_Object Voverriding_local_map;
 /* If non-nil, Voverriding_local_map applies to the menu bar.  */
 Lisp_Object Voverriding_local_map_menu_flag;
 
+/* Keymap that defines special misc events that should
+   be processed immediately at a low level.  */
+Lisp_Object Vspecial_event_map;
+
 /* Current depth in recursive edits.  */
 int command_loop_level;
 
@@ -294,8 +325,9 @@ Lisp_Object Vkeyboard_translate_table;
 /* Keymap mapping ASCII function key sequences onto their preferred forms.  */
 extern Lisp_Object Vfunction_key_map;
 
-/* Keymap mapping ASCII function key sequences onto their preferred forms.  */
-Lisp_Object Vkey_translation_map;
+/* Another keymap that maps key sequences into key sequences.
+   This one takes precedence over ordinary definitions.  */
+extern Lisp_Object Vkey_translation_map;
 
 /* Non-nil means deactivate the mark at end of this command.  */
 Lisp_Object Vdeactivate_mark;
@@ -306,9 +338,14 @@ Lisp_Object Vlucid_menu_bar_dirty_flag;
 Lisp_Object Qrecompute_lucid_menubar, Qactivate_menubar_hook;
 
 /* Hooks to run before and after each command.  */
-Lisp_Object Qpre_command_hook, Qpost_command_hook;
-Lisp_Object Vpre_command_hook, Vpost_command_hook;
+Lisp_Object Qpre_command_hook, Vpre_command_hook;
+Lisp_Object Qpost_command_hook, Vpost_command_hook;
 Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal;
+/* Hook run after a command if there's no more input soon.  */
+Lisp_Object Qpost_command_idle_hook, Vpost_command_idle_hook;
+
+/* Delay time in microseconds before running post-command-idle-hook.  */
+int post_command_idle_delay;
 
 /* List of deferred actions to be performed at a later time.
    The precise format isn't relevant here; we just check whether it is nil.  */
@@ -382,20 +419,11 @@ static volatile struct input_event *kbd_store_ptr;
    dequeuing functions?  Such a flag could be screwed up by interrupts
    at inopportune times.  */
 
-/* If this flag is a frame, we check mouse_moved to see when the
+/* If this flag is non-nil, we check mouse_moved to see when the
    mouse moves, and motion events will appear in the input stream.
    Otherwise, mouse motion is ignored.  */
 static Lisp_Object do_mouse_tracking;
 
-#ifdef HAVE_MOUSE
-/* The window system handling code should set this if the mouse has
-   moved since the last call to the mouse_position_hook.  Calling that
-   hook should clear this.  Code assumes that if this is set, it can
-   call mouse_position_hook to get the promised position, so don't set
-   it unless you're prepared to substantiate the claim!  */
-int mouse_moved;
-#endif /* HAVE_MOUSE */
-
 /* Symbols to head events.  */
 Lisp_Object Qmouse_movement;
 Lisp_Object Qscroll_bar_movement;
@@ -407,6 +435,7 @@ 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.  */
@@ -439,9 +468,21 @@ extern Lisp_Object Qmenu_enable;
 Lisp_Object recursive_edit_unwind (), command_loop ();
 Lisp_Object Fthis_command_keys ();
 Lisp_Object Qextended_command_history;
+EMACS_TIME timer_check ();
+
+extern char *x_get_keysym_name ();
 
 Lisp_Object Qpolling_period;
 
+/* List of absolute timers.  Appears in order of next scheduled event.  */
+Lisp_Object Vtimer_list;
+
+/* List of idle time timers.  Appears in order of next scheduled event.  */
+Lisp_Object Vtimer_idle_list;
+
+/* Incremented whenever a timer is run.  */
+int timers_run;
+
 extern Lisp_Object Vprint_level, Vprint_length;
 
 /* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
@@ -455,7 +496,7 @@ int interrupt_input;
 /* Nonzero while interrupts are temporarily deferred during redisplay.  */
 int interrupts_deferred;
 
-/* nonzero means use ^S/^Q for flow control.  */
+/* Nonzero means use ^S/^Q for flow control.  */
 int flow_control;
 
 /* Allow m- file to inhibit use of FIONREAD.  */
@@ -471,11 +512,14 @@ int flow_control;
 #endif
 #endif
 
-/* If we support X Windows, turn on the code to poll periodically
+/* If we support a window system, turn on the code to poll periodically
    to detect C-g.  It isn't actually used when doing interrupt input.  */
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
 #define POLL_FOR_INPUT
 #endif
+
+/* Non-nil enables Column Number mode.  */
+Lisp_Object Vcolumn_number_mode;
 \f
 /* Global variable declarations.  */
 
@@ -522,7 +566,7 @@ echo_prompt (str)
 
   current_kboard->echo_after_prompt = len;
 
-  echo ();
+  echo_now ();
 }
 
 /* Add C to the echo string, if echoing is going on.
@@ -570,7 +614,7 @@ echo_char (c)
       *ptr = 0;
       current_kboard->echoptr = ptr;
 
-      echo ();
+      echo_now ();
     }
 }
 
@@ -595,13 +639,13 @@ echo_dash ()
   current_kboard->echoptr[0] = '-';
   current_kboard->echoptr[1] = 0;
 
-  echo ();
+  echo_now ();
 }
 
 /* Display the current echo string, and begin echoing if not already
    doing so.  */
 
-echo ()
+echo_now ()
 {
   if (!current_kboard->immediate_echo)
     {
@@ -634,6 +678,7 @@ cancel_echoing ()
   current_kboard->immediate_echo = 0;
   current_kboard->echoptr = current_kboard->echobuf;
   current_kboard->echo_after_prompt = -1;
+  ok_to_echo_at_next_pause = 0;
 }
 
 /* Return the length of the current echo string.  */
@@ -665,6 +710,15 @@ add_command_key (key)
 {
   int size = XVECTOR (this_command_keys)->size;
 
+  /* If reset-this-command-length was called recently, obey it now.
+     See the doc string of that function for an explanation of why.  */
+  if (before_command_restore_flag)
+    {
+      this_command_key_count = before_command_key_count_1;
+      echo_truncate (before_command_echo_length_1);
+      before_command_restore_flag = 0;
+    }
+
   if (this_command_key_count >= size)
     {
       Lisp_Object new_keys;
@@ -838,8 +892,8 @@ cmd_error (data)
   /* Avoid unquittable loop if data contains a circular list.  */
   old_level = Vprint_level;
   old_length = Vprint_length;
-  XSETFASTINT(Vprint_level, 10);
-  XSETFASTINT(Vprint_length, 10);
+  XSETFASTINT (Vprint_level, 10);
+  XSETFASTINT (Vprint_length, 10);
   cmd_error_internal (data, NULL);
   Vprint_level = old_level;
   Vprint_length = old_length;
@@ -858,10 +912,7 @@ cmd_error_internal (data, context)
      Lisp_Object data;
      char *context;
 {
-  Lisp_Object errmsg, tail, errname, file_error;
   Lisp_Object stream;
-  struct gcpro gcpro1;
-  int i;
 
   Vquit_flag = Qnil;
   Vinhibit_quit = Qt;
@@ -883,49 +934,7 @@ cmd_error_internal (data, context)
   if (context != 0)
     write_string_1 (context, -1, stream);
 
-  errname = Fcar (data);
-
-  if (EQ (errname, Qerror))
-    {
-      data = Fcdr (data);
-      if (!CONSP (data)) data = Qnil;
-      errmsg = Fcar (data);
-      file_error = Qnil;
-    }
-  else
-    {
-      errmsg = Fget (errname, Qerror_message);
-      file_error = Fmemq (Qfile_error,
-                         Fget (errname, Qerror_conditions));
-    }
-
-  /* Print an error message including the data items.
-     This is done by printing it into a scratch buffer
-     and then making a copy of the text in the buffer. */
-
-  if (!CONSP (data)) data = Qnil;
-  tail = Fcdr (data);
-  GCPRO1 (tail);
-
-  /* For file-error, make error message by concatenating
-     all the data items.  They are all strings.  */
-  if (!NILP (file_error) && !NILP (tail))
-    errmsg = XCONS (tail)->car, tail = XCONS (tail)->cdr;
-
-  if (STRINGP (errmsg))
-    Fprinc (errmsg, stream);
-  else
-    write_string_1 ("peculiar error", -1, stream);
-
-  for (i = 0; CONSP (tail); tail = Fcdr (tail), i++)
-    {
-      write_string_1 (i ? ", " : ": ", 2, stream);
-      if (!NILP (file_error))
-       Fprinc (Fcar (tail), stream);
-      else
-       Fprin1 (Fcar (tail), stream);
-    }
-  UNGCPRO;
+  print_error_message (data, stream);
 
   /* If the window system or terminal frame hasn't been initialized
      yet, or we're in -batch mode, this error should cause Emacs to exit.  */
@@ -1033,7 +1042,7 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
 
 Lisp_Object Fcommand_execute ();
 static int read_key_sequence ();
-static void safe_run_hooks ();
+void safe_run_hooks ();
 
 Lisp_Object
 command_loop_1 ()
@@ -1051,6 +1060,7 @@ command_loop_1 ()
   int was_locked = single_kboard;
 #endif
 
+  current_kboard->Vprefix_arg = Qnil;
   Vdeactivate_mark = Qnil;
   waiting_for_input = 0;
   cancel_echoing ();
@@ -1063,12 +1073,20 @@ command_loop_1 ()
      throw to top level.  */
   /* Note that the value cell will never directly contain nil
      if the symbol is a local variable.  */
-  if (!NILP (XSYMBOL (Qpost_command_hook)->value) && !NILP (Vrun_hooks))
+  if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
     safe_run_hooks (Qpost_command_hook);
 
   if (!NILP (Vdeferred_action_list))
     call0 (Vdeferred_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);
+    }
+
   /* Do this after running Vpost_command_hook, for consistency.  */
   current_kboard->Vlast_command = this_command;
 
@@ -1091,7 +1109,8 @@ command_loop_1 ()
       /* If minibuffer on and echo area in use,
         wait 2 sec and redraw minibuffer.  */
 
-      if (minibuf_level && echo_area_glyphs)
+      if (minibuf_level && echo_area_glyphs
+         && EQ (minibuf_window, echo_area_window))
        {
          /* Bind inhibit-quit to t so that C-g gets read in
             rather than quitting back to the minibuffer.  */
@@ -1100,8 +1119,10 @@ command_loop_1 ()
          Fsit_for (make_number (2), Qnil, Qnil);
          unbind_to (count, Qnil);
 
-         echo_area_glyphs = 0;
-         no_direct = 1;
+         /* Clear the echo area.  */
+         message2 (0);
+
+         /* If a C-g came in before, treat it as input now.  */
          if (!NILP (Vquit_flag))
            {
              Vquit_flag = Qnil;
@@ -1131,6 +1152,11 @@ command_loop_1 ()
          && !NILP (Ffboundp (Qrecompute_lucid_menubar)))
        call0 (Qrecompute_lucid_menubar);
 
+      before_command_key_count = this_command_key_count;
+      before_command_echo_length = echo_length ();
+
+      this_command = Qnil;
+
       /* Read next key sequence; i gets its length.  */
       i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
                             Qnil, 0, 1);
@@ -1192,7 +1218,7 @@ command_loop_1 ()
       this_command = cmd;
       /* Note that the value cell will never directly contain nil
         if the symbol is a local variable.  */
-      if (!NILP (XSYMBOL (Qpre_command_hook)->value) && !NILP (Vrun_hooks))
+      if (!NILP (Vpre_command_hook) && !NILP (Vrun_hooks))
        safe_run_hooks (Qpre_command_hook);
 
       if (NILP (this_command))
@@ -1211,7 +1237,7 @@ command_loop_1 ()
                 do them directly.  */
              if (EQ (this_command, Qforward_char) && PT < ZV)
                {
-                  struct Lisp_Vector *dp
+                  struct Lisp_Char_Table *dp
                    = window_display_table (XWINDOW (selected_window));
                  lose = FETCH_CHAR (PT);
                  SET_PT (PT + 1);
@@ -1228,13 +1254,14 @@ command_loop_1 ()
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
+                     && NILP (Vcolumn_number_mode)
                      && NILP (Vexecuting_macro))
                    no_redisplay = direct_output_forward_char (1);
                  goto directly_done;
                }
              else if (EQ (this_command, Qbackward_char) && PT > BEGV)
                {
-                  struct Lisp_Vector *dp
+                  struct Lisp_Char_Table *dp
                    = window_display_table (XWINDOW (selected_window));
                  SET_PT (PT - 1);
                  lose = FETCH_CHAR (PT);
@@ -1251,6 +1278,7 @@ command_loop_1 ()
                      && !windows_or_buffers_changed
                      && EQ (current_buffer->selective_display, Qnil)
                      && !detect_input_pending ()
+                     && NILP (Vcolumn_number_mode)
                      && NILP (Vexecuting_macro))
                    no_redisplay = direct_output_forward_char (-1);
                  goto directly_done;
@@ -1280,6 +1308,7 @@ command_loop_1 ()
                          || windows_or_buffers_changed
                          || !EQ (current_buffer->selective_display, Qnil)
                          || detect_input_pending ()
+                         || !NILP (Vcolumn_number_mode)
                          || !NILP (Vexecuting_macro));
                  value = internal_self_insert (c, 0);
                  if (value)
@@ -1290,7 +1319,7 @@ command_loop_1 ()
                  if (!lose
                      && (PT == ZV || FETCH_CHAR (PT) == '\n'))
                    {
-                     struct Lisp_Vector *dp
+                     struct Lisp_Char_Table *dp
                        = window_display_table (XWINDOW (selected_window));
                      int lose = c;
 
@@ -1330,19 +1359,27 @@ command_loop_1 ()
          nonundocount = 0;
          if (NILP (current_kboard->Vprefix_arg))
            Fundo_boundary ();
-         Fcommand_execute (this_command, Qnil);
+         Fcommand_execute (this_command, Qnil, Qnil, Qnil);
 
        }
     directly_done: ;
 
       /* Note that the value cell will never directly contain nil
         if the symbol is a local variable.  */
-      if (!NILP (XSYMBOL (Qpost_command_hook)->value) && !NILP (Vrun_hooks))
+      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,
@@ -1351,8 +1388,12 @@ command_loop_1 ()
         cancel_echoing, and
         3) we want to leave this_command_key_count non-zero, so that
         read_char will realize that it is re-reading a character, and
-        not echo it a second time.  */
-      if (NILP (current_kboard->Vprefix_arg))
+        not echo it a second time.
+
+        If the command didn't actually create a prefix arg,
+        but is merely a frame event that is transparent to prefix args,
+        then the above doesn't apply.  */
+      if (NILP (current_kboard->Vprefix_arg) || CONSP (last_command_char))
        {
          current_kboard->Vlast_command = this_command;
          cancel_echoing ();
@@ -1406,7 +1447,7 @@ safe_run_hooks_error (data)
    to be nil.  Also inhibit quits, so that C-g won't cause the hook
    to mysteriously evaporate.  */
 
-static void
+void
 safe_run_hooks (hook)
      Lisp_Object hook;
 {
@@ -1414,7 +1455,7 @@ safe_run_hooks (hook)
   int count = specpdl_ptr - specpdl;
   specbind (Qinhibit_quit, hook);
 
-  internal_condition_case (safe_run_hooks_1, Qerror, safe_run_hooks_error);
+  internal_condition_case (safe_run_hooks_1, Qt, safe_run_hooks_error);
 
   unbind_to (count, Qnil);
 }
@@ -1437,11 +1478,15 @@ SIGTYPE
 input_poll_signal (signalnum)  /* If we don't have an argument, */
      int signalnum;            /* some compilers complain in signal calls. */
 {
+  /* This causes the call to start_polling at the end
+     to do its job.  It also arranges for a quit or error
+     from within read_avail_input to resume polling.  */
+  poll_suppress_count++;
   if (interrupt_input_blocked == 0
       && !waiting_for_input)
     read_avail_input (0);
-  signal (SIGALRM, input_poll_signal);
-  alarm (polling_period);
+  /* Turn on the SIGALRM handler and request another alarm.  */
+  start_polling ();
 }
 
 #endif
@@ -1614,14 +1659,27 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   jmp_buf local_getcjmp;
   jmp_buf save_jump;
   int key_already_recorded = 0;
+  Lisp_Object tem, save;
   Lisp_Object also_record;
   also_record = Qnil;
 
+  before_command_key_count = this_command_key_count;
+  before_command_echo_length = echo_length ();
+
+ retry:
+
   if (CONSP (Vunread_command_events))
     {
       c = XCONS (Vunread_command_events)->car;
       Vunread_command_events = XCONS (Vunread_command_events)->cdr;
 
+      /* Undo what read_char_x_menu_prompt did when it unread
+        additional keys returned by Fx_popup_menu.  */
+      if (CONSP (c)
+         && (SYMBOLP (XCONS (c)->car) || INTEGERP (XCONS (c)->car))
+         && NILP (XCONS (c)->cdr))
+       c = XCONS (c)->car;
+
       if (this_command_key_count == 0)
        goto reread_first;
       else
@@ -1639,6 +1697,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
        goto reread;
     }
 
+  /* If there is no function key translated before
+     reset-this-command-lengths takes effect, forget about it.  */
+  before_command_restore_flag = 0;
+
   if (!NILP (Vexecuting_macro))
     {
 #ifdef MULTI_FRAME
@@ -1690,7 +1752,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
   /* Message turns off echoing unless more keystrokes turn it on again. */
   if (echo_area_glyphs && *echo_area_glyphs
-      && echo_area_glyphs != current_kboard->echobuf)
+      && echo_area_glyphs != current_kboard->echobuf
+      && ok_to_echo_at_next_pause != echo_area_glyphs)
     cancel_echoing ();
   else
     /* If already echoing, continue.  */
@@ -1758,6 +1821,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       goto non_reread;
     }
 
+  timer_start_idle ();
+
   /* If in middle of key sequence and minibuffer not active,
      start echoing if enough time elapses.  */
 
@@ -1765,7 +1830,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       && this_command_key_count > 0
       && ! noninteractive
       && echo_keystrokes > 0
-      && (echo_area_glyphs == 0 || *echo_area_glyphs == 0))
+      && (echo_area_glyphs == 0 || *echo_area_glyphs == 0
+         || ok_to_echo_at_next_pause == echo_area_glyphs))
     {
       Lisp_Object tem0;
 
@@ -1773,7 +1839,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
         This is because we are probably about to display a menu,
         and we don't want to delay before doing so.  */
       if (EVENT_HAS_PARAMETERS (prev_event))
-       echo ();
+       echo_now ();
       else
        {
          save_getcjmp (save_jump);
@@ -1781,7 +1847,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          tem0 = sit_for (echo_keystrokes, 0, 1, 1);
          restore_getcjmp (save_jump);
          if (EQ (tem0, Qt))
-           echo ();
+           echo_now ();
        }
     }
 
@@ -1836,11 +1902,11 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
          && XINT (Vauto_save_timeout) > 0)
        {
          Lisp_Object tem0;
-         int delay = delay_level * XFASTINT (Vauto_save_timeout) / 4;
 
          save_getcjmp (save_jump);
          restore_getcjmp (local_getcjmp);
-         tem0 = sit_for (delay, 0, 1, 1);
+         tem0 = sit_for (delay_level * XFASTINT (Vauto_save_timeout) / 4,
+                         0, 1, 1);
          restore_getcjmp (save_jump);
 
          if (EQ (tem0, Qt))
@@ -1872,7 +1938,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
            = XCONS (current_kboard->kbd_queue)->cdr;
          if (NILP (current_kboard->kbd_queue))
            current_kboard->kbd_queue_has_data = 0;
-         input_pending = readable_events ();
+         input_pending = readable_events (0);
 #ifdef MULTI_FRAME
          if (EVENT_HAS_PARAMETERS (c)
              && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qswitch_frame))
@@ -1960,6 +2026,11 @@ 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.  */
+  if (! (CONSP (c) && EQ (XCONS (c)->car, Qtimer_event)))
+    timer_stop_idle ();
+
   start_polling ();
 
   if (NILP (c))
@@ -1981,6 +2052,28 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
   if (key_already_recorded)
     return c;
 
+  /* Process special events within read_char
+     and loop around to read another event.  */
+  save = Vquit_flag;
+  Vquit_flag = Qnil;
+  tem = get_keyelt (access_keymap (get_keymap_1 (Vspecial_event_map, 0, 0),
+                                  c, 0, 0), 1);
+  Vquit_flag = save;
+
+  if (!NILP (tem))
+    {
+      int was_locked = single_kboard;
+
+      last_input_char = c;
+      Fcommand_execute (tem, Qnil, Fvector (1, &last_input_char), Qt);
+
+      /* Resume allowing input from any kboard, if that was true before.  */
+      if (!was_locked)
+       any_kboard_state ();
+
+      goto retry;
+    }
+
   /* Wipe the echo area.  */
   echo_area_glyphs = 0;
 
@@ -1994,6 +2087,16 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       if (STRINGP (Vkeyboard_translate_table)
          && XSTRING (Vkeyboard_translate_table)->size > XFASTINT (c))
        XSETINT (c, XSTRING (Vkeyboard_translate_table)->data[XFASTINT (c)]);
+      else if ((VECTORP (Vkeyboard_translate_table)
+               && XVECTOR (Vkeyboard_translate_table)->size > XFASTINT (c))
+              || CHAR_TABLE_P (Vkeyboard_translate_table))
+       {
+         Lisp_Object d;
+         d = Faref (Vkeyboard_translate_table, c);
+         /* nil in keyboard-translate-table means no translation.  */
+         if (!NILP (d))
+           c = d;
+       }
     }
 
   /* If this event is a mouse click in the menu bar,
@@ -2026,6 +2129,8 @@ 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 ();
 
   /* Don't echo mouse motion events.  */
   if (echo_keystrokes
@@ -2035,6 +2140,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       echo_char (c);
       if (! NILP (also_record))
        echo_char (also_record);
+      /* Once we reread a character, echoing can happen
+        the next time we pause to read a new one.  */
+      ok_to_echo_at_next_pause = echo_area_glyphs;
     }
 
   /* Record this character as part of the current key.  */
@@ -2190,10 +2298,10 @@ tracking_off (old_value)
         input has been processed.  If the only input available was
         the sort that we have just disabled, then we need to call
         redisplay.  */
-      if (!readable_events ())
+      if (!readable_events (1))
        {
          redisplay_preserve_echo_area ();
-         get_input_pending (&input_pending);
+         get_input_pending (&input_pending, 1);
        }
     }
 }
@@ -2211,29 +2319,46 @@ Normally, mouse motion is ignored.")
 
   record_unwind_protect (tracking_off, do_mouse_tracking);
 
-  XSETFRAME (do_mouse_tracking, selected_frame);
+  do_mouse_tracking = Qt;
 
   val = Fprogn (args);
   return unbind_to (count, val);
 }
 
+/* If mouse has moved on some frame, return one of those frames.
+   Return 0 otherwise.  */
+
+static FRAME_PTR
+some_mouse_moved ()
+{
+  Lisp_Object tail, frame;
+
+  FOR_EACH_FRAME (tail, frame)
+    {
+      if (XFRAME (frame)->mouse_moved)
+       return XFRAME (frame);
+    }
+
+  return 0;
+}
+
 #endif /* HAVE_MOUSE */
 \f
 /* Low level keyboard/mouse input.
    kbd_buffer_store_event places events in kbd_buffer, and
-   kbd_buffer_get_event retrieves them.
-   mouse_moved indicates when the mouse has moved again, and
-   *mouse_position_hook provides the mouse position.  */
+   kbd_buffer_get_event retrieves them.  */
 
 /* Return true iff there are any events in the queue that read-char
    would return.  If this returns false, a read-char would block.  */
 static int
-readable_events ()
+readable_events (do_timers_now)
+     int do_timers_now;
 {
+  timer_check (do_timers_now);
   if (kbd_fetch_ptr != kbd_store_ptr)
     return 1;
 #ifdef HAVE_MOUSE
-  if (FRAMEP (do_mouse_tracking) && mouse_moved)
+  if (!NILP (do_mouse_tracking) && some_mouse_moved ())
     return 1;
 #endif
   if (single_kboard)
@@ -2353,6 +2478,12 @@ kbd_buffer_store_event (event)
          return;
        }
     }
+  /* Don't insert two buffer_switch_event's in a row.
+     Just ignore the second one.  */
+  else if (event->kind == buffer_switch_event
+          && kbd_fetch_ptr != kbd_store_ptr
+          && kbd_store_ptr->kind == buffer_switch_event)
+    return;
 
   if (kbd_store_ptr - kbd_buffer == KBD_BUFFER_SIZE)
     kbd_store_ptr = kbd_buffer;
@@ -2403,6 +2534,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
 {
   register int c;
   Lisp_Object obj;
+  EMACS_TIME next_timer_delay;
 
   if (noninteractive)
     {
@@ -2418,7 +2550,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       if (kbd_fetch_ptr != kbd_store_ptr)
        break;
 #ifdef HAVE_MOUSE
-      if (FRAMEP (do_mouse_tracking) && mouse_moved)
+      if (!NILP (do_mouse_tracking) && some_mouse_moved ())
        break;
 #endif
 
@@ -2440,7 +2572,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       if (kbd_fetch_ptr != kbd_store_ptr)
        break;
 #ifdef HAVE_MOUSE
-      if (FRAMEP (do_mouse_tracking) && mouse_moved)
+      if (!NILP (do_mouse_tracking) && some_mouse_moved ())
        break;
 #endif
       {
@@ -2492,6 +2624,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
             and process it again.  */
          copy = *event;
          kbd_fetch_ptr = event + 1;
+         input_pending = readable_events (0);
          x_handle_selection_request (&copy);
 #else
          /* We're getting selection request events, but we don't have
@@ -2503,15 +2636,20 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
       else if (event->kind == selection_clear_event)
        {
 #ifdef HAVE_X11
-         x_handle_selection_clear (event);
+         struct input_event copy;
+
+         /* Remove it from the buffer before processing it.  */
+         copy = *event;
          kbd_fetch_ptr = event + 1;
+         input_pending = readable_events (0);
+         x_handle_selection_clear (&copy);
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
          abort ();
 #endif
        }
-#ifdef HAVE_X11
+#if defined (HAVE_X11) || defined (HAVE_NTGUI)
       else if (event->kind == delete_window_event)
        {
          /* Make an event (delete-frame (FRAME)).  */
@@ -2540,6 +2678,14 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          XSETBUFFER (obj, current_buffer);
          kbd_fetch_ptr = event + 1;
        }
+#ifdef USE_X_TOOLKIT
+      else if (event->kind == menu_bar_activate_event)
+       {
+         kbd_fetch_ptr = event + 1;
+         input_pending = readable_events (0);
+         x_activate_menubar (XFRAME (event->frame_or_window));
+       }
+#endif
       /* Just discard these, by returning nil.
         With MULTI_KBOARD, these events are used as placeholders
         when we need to randomly delete events from the queue.
@@ -2579,7 +2725,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
          if (NILP (obj))
            {
              obj = make_lispy_event (event);
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
              /* If this was a menu selection, then set the flag to inhibit
                 writing to last_nonmenu_event.  Don't do this if the event
                 we're returning is (menu-bar), though; that indicates the
@@ -2601,9 +2747,9 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
     }
 #ifdef HAVE_MOUSE
   /* Try generating a mouse motion event.  */
-  else if (FRAMEP (do_mouse_tracking) && mouse_moved)
+  else if (!NILP (do_mouse_tracking) && some_mouse_moved ())
     {
-      FRAME_PTR f = XFRAME (do_mouse_tracking);
+      FRAME_PTR f = some_mouse_moved ();
       Lisp_Object bar_window;
       enum scroll_bar_part part;
       Lisp_Object x, y;
@@ -2648,7 +2794,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
        something for us to read!  */
     abort ();
 
-  input_pending = readable_events ();
+  input_pending = readable_events (0);
 
 #ifdef MULTI_FRAME
   Vlast_event_frame = internal_last_event_frame;
@@ -2661,8 +2807,11 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
    then return, without reading any user-visible events.  */
 
 void
-swallow_events ()
+swallow_events (do_display)
+     int do_display;
 {
+  int old_timers_run;
+
   while (kbd_fetch_ptr != kbd_store_ptr)
     {
       struct input_event *event;
@@ -2679,8 +2828,13 @@ swallow_events ()
        {
 #ifdef HAVE_X11
          struct input_event copy;
+
+         /* Remove it from the buffer before processing it,
+            since otherwise swallow_events called recursively could see it
+            and process it again.  */
          copy = *event;
          kbd_fetch_ptr = event + 1;
+         input_pending = readable_events (0);
          x_handle_selection_request (&copy);
 #else
          /* We're getting selection request events, but we don't have
@@ -2692,24 +2846,321 @@ swallow_events ()
       else if (event->kind == selection_clear_event)
        {
 #ifdef HAVE_X11
-         x_handle_selection_clear (event);
+         struct input_event copy;
+
+         /* Remove it from the buffer before processing it,  */
+         copy = *event;
+
          kbd_fetch_ptr = event + 1;
+         input_pending = readable_events (0);
+         x_handle_selection_clear (&copy);
 #else
          /* We're getting selection request events, but we don't have
              a window system.  */
          abort ();
 #endif
        }
+      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;
     }
 
-  get_input_pending (&input_pending);
+  old_timers_run = timers_run;
+  get_input_pending (&input_pending, 1);
+
+  if (timers_run != old_timers_run && do_display)
+    redisplay_preserve_echo_area ();
+}
+\f
+static EMACS_TIME timer_idleness_start_time;
+
+/* Record the start of when Emacs is idle,
+   for the sake of running idle-time timers.  */
+
+timer_start_idle ()
+{
+  Lisp_Object timers;
+
+  /* If we are already in the idle state, do nothing.  */
+  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+    return;
+
+  EMACS_GET_TIME (timer_idleness_start_time);
+
+  /* Mark all idle-time timers as once again candidates for running.  */
+  for (timers = Vtimer_idle_list; CONSP (timers); timers = XCONS (timers)->cdr)
+    {
+      Lisp_Object timer;
+
+      timer = XCONS (timers)->car;
+
+      if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+       continue;
+      XVECTOR (timer)->contents[0] = Qnil;
+    }
+}
+
+/* Record that Emacs is no longer idle, so stop running idle-time timers.  */
+
+timer_stop_idle ()
+{
+  EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
+}
+
+/* This is only for debugging.  */
+struct input_event last_timer_event;
+
+/* Check whether a timer has fired.  To prevent larger problems we simply
+   disregard elements that are not proper timers.  Do not make a circular
+   timer list for the time being.
+
+   Returns the number of seconds to wait until the next timer fires.  If a
+   timer is triggering now, return zero seconds.
+   If no timer is active, return -1 seconds.
+
+   If a timer is ripe now, either queue a timer-event,
+   or call the timer's handler function here if DO_IT_NOW is nonzero.  */
+
+EMACS_TIME
+timer_check (do_it_now)
+     int 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);
+  EMACS_SET_USECS (nexttime, -1);
+
+  /* Always consider the ordinary timers.  */
+  timers = Vtimer_list;
+  /* Consider the idle timers only if Emacs is idle.  */
+  if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+    idle_timers = Vtimer_idle_list;
+  else
+    idle_timers = Qnil;
+  chosen_timer = Qnil;
+  GCPRO3 (timers, idle_timers, chosen_timer);
+
+  if (CONSP (timers) || CONSP (idle_timers))
+    {
+      EMACS_GET_TIME (now);
+      if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+       EMACS_SUB_TIME (idleness_now, now, timer_idleness_start_time);
+    }
+
+  while (CONSP (timers) || CONSP (idle_timers))
+    {
+      int triggertime = EMACS_SECS (now);
+      Lisp_Object *vector;
+      Lisp_Object timer, idle_timer;
+      EMACS_TIME timer_time, idle_timer_time;
+      EMACS_TIME difference, timer_difference, idle_timer_difference;
+
+      /* Skip past invalid timers and timers already handled.  */
+      if (!NILP (timers))
+       {
+         timer = XCONS (timers)->car;
+         if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+           {
+             timers = XCONS (timers)->cdr;
+             continue;
+           }
+         vector = XVECTOR (timer)->contents;
+
+         if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
+             || !INTEGERP (vector[3])
+             || ! NILP (vector[0]))
+           {
+             timers = XCONS (timers)->cdr;
+             continue;
+           }
+       }
+      if (!NILP (idle_timers))
+       {
+         timer = XCONS (idle_timers)->car;
+         if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+           {
+             idle_timers = XCONS (idle_timers)->cdr;
+             continue;
+           }
+         vector = XVECTOR (timer)->contents;
+
+         if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
+             || !INTEGERP (vector[3])
+             || ! NILP (vector[0]))
+           {
+             idle_timers = XCONS (idle_timers)->cdr;
+             continue;
+           }
+       }
+
+      /* Set TIMER, TIMER_TIME and TIMER_DIFFERENCE
+        based on the next ordinary timer.
+        TIMER_DIFFERENCE is the distance in time from NOW to when
+        this timer becomes ripe (negative if it's already ripe).  */
+      if (!NILP (timers))
+       {
+         timer = XCONS (timers)->car;
+         vector = XVECTOR (timer)->contents;
+         EMACS_SET_SECS (timer_time,
+                         (XINT (vector[1]) << 16) | (XINT (vector[2])));
+         EMACS_SET_USECS (timer_time, XINT (vector[3]));
+         EMACS_SUB_TIME (timer_difference, timer_time, now);
+       }
+
+      /* Set IDLE_TIMER, IDLE_TIMER_TIME and IDLE_TIMER_DIFFERENCE
+        based on the next idle timer.  */
+      if (!NILP (idle_timers))
+       {
+         idle_timer = XCONS (idle_timers)->car;
+         vector = XVECTOR (idle_timer)->contents;
+         EMACS_SET_SECS (idle_timer_time,
+                         (XINT (vector[1]) << 16) | (XINT (vector[2])));
+         EMACS_SET_USECS (idle_timer_time, XINT (vector[3]));
+         EMACS_SUB_TIME (idle_timer_difference, idle_timer_time, idleness_now);
+       }
+
+      /* Decide which timer is the next timer,
+        and set CHOSEN_TIMER, VECTOR and DIFFERENCE accordingly.
+        Also step down the list where we found that timer.  */
+
+      if (! NILP (timers) && ! NILP (idle_timers))
+       {
+         EMACS_TIME temp;
+         EMACS_SUB_TIME (temp, timer_difference, idle_timer_difference);
+         if (EMACS_TIME_NEG_P (temp))
+           {
+             chosen_timer = timer;
+             timers = XCONS (timers)->cdr;
+             difference = timer_difference;
+           }
+         else
+           {
+             chosen_timer = idle_timer;
+             idle_timers = XCONS (idle_timers)->cdr;
+             difference = idle_timer_difference;
+           }
+       }
+      else if (! NILP (timers))
+       {
+         chosen_timer = timer;
+         timers = XCONS (timers)->cdr;
+         difference = timer_difference;
+       }
+      else
+       {
+         chosen_timer = idle_timer;
+         idle_timers = XCONS (idle_timers)->cdr;
+         difference = idle_timer_difference;
+       }
+      vector = XVECTOR (chosen_timer)->contents;
+       
+      /* If timer is rupe, run it if it hasn't been run.  */
+      if (EMACS_TIME_NEG_P (difference)
+         || (EMACS_SECS (difference) == 0
+             && EMACS_USECS (difference) == 0))
+       {
+         if (NILP (vector[0]))
+           {
+             /* 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 (do_it_now)
+               {
+                 Lisp_Object tem, 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);
+                 event = Fcons (Qtimer_event, Fcons (chosen_timer, Qnil));
+                 Fcommand_execute (tem, Qnil, Fvector (1, &event), Qt);
+                 timers_run++;
+
+                 /* 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.  */
+               }
+             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;
+               }
+           }
+       }
+      else
+       /* When we encounter a timer that is still waiting,
+          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;
+       }
+    }
+
+  /* No timers are pending in the future.  */
+  /* Return 0 if we generated an event, and -1 if not.  */
+  UNGCPRO;
+  return nexttime;
 }
 \f
 /* Caches for modify_event_symbol.  */
 static Lisp_Object accent_key_syms;
-static Lisp_Object system_key_syms;
 static Lisp_Object func_key_syms;
 static Lisp_Object mouse_syms;
 
@@ -2805,6 +3256,171 @@ static char *lispy_accent_keys[] =
   "dead-abovedot",
 };
 
+#ifdef HAVE_NTGUI
+#define FUNCTION_KEY_OFFSET 0x0
+
+char *lispy_function_keys[] =
+  {
+    0,                /* 0                      */
+    
+    0,                /* VK_LBUTTON        0x01 */
+    0,                /* VK_RBUTTON        0x02 */
+    "cancel",         /* VK_CANCEL         0x03 */
+    0,                /* VK_MBUTTON        0x04 */
+    
+    0, 0, 0,          /*    0x05 .. 0x07        */
+    
+    "backspace",      /* VK_BACK           0x08 */
+    "tab",            /* VK_TAB            0x09 */
+    
+    0, 0,             /*    0x0A .. 0x0B        */
+    
+    "clear",          /* VK_CLEAR          0x0C */
+    "return",         /* VK_RETURN         0x0D */
+    
+    0, 0,             /*    0x0E .. 0x0F        */
+  
+    "shift",          /* VK_SHIFT          0x10 */
+    "control",        /* VK_CONTROL        0x11 */
+    "menu",           /* VK_MENU           0x12 */
+    "pause",          /* VK_PAUSE          0x13 */
+    "capital",        /* VK_CAPITAL        0x14 */
+    
+    0, 0, 0, 0, 0, 0, /*    0x15 .. 0x1A        */
+    
+    0,                /* VK_ESCAPE         0x1B */
+    
+    0, 0, 0, 0,       /*    0x1C .. 0x1F        */
+    
+    0,                /* VK_SPACE          0x20 */
+    "prior",          /* VK_PRIOR          0x21 */
+    "next",           /* VK_NEXT           0x22 */
+    "end",            /* VK_END            0x23 */
+    "home",           /* VK_HOME           0x24 */
+    "left",           /* VK_LEFT           0x25 */
+    "up",             /* VK_UP             0x26 */
+    "right",          /* VK_RIGHT          0x27 */
+    "down",           /* VK_DOWN           0x28 */
+    "select",         /* VK_SELECT         0x29 */
+    "print",          /* VK_PRINT          0x2A */
+    "execute",        /* VK_EXECUTE        0x2B */
+    "snapshot",       /* VK_SNAPSHOT       0x2C */
+    "insert",         /* VK_INSERT         0x2D */
+    "delete",         /* VK_DELETE         0x2E */
+    "help",           /* VK_HELP           0x2F */
+  
+    /* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
+    
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    
+    0, 0, 0, 0, 0, 0, 0, /* 0x3A .. 0x40       */
+    
+    /* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
+    
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0,
+    
+    "lwindow",       /* VK_LWIN           0x5B */
+    "rwindow",       /* VK_RWIN           0x5C */
+    "apps",          /* VK_APPS           0x5D */
+    
+    0, 0,            /*    0x5E .. 0x5F        */
+    
+    "kp-0",          /* VK_NUMPAD0        0x60 */
+    "kp-1",          /* VK_NUMPAD1        0x61 */
+    "kp-2",          /* VK_NUMPAD2        0x62 */
+    "kp-3",          /* VK_NUMPAD3        0x63 */
+    "kp-4",          /* VK_NUMPAD4        0x64 */
+    "kp-5",          /* VK_NUMPAD5        0x65 */
+    "kp-6",          /* VK_NUMPAD6        0x66 */
+    "kp-7",          /* VK_NUMPAD7        0x67 */
+    "kp-8",          /* VK_NUMPAD8        0x68 */
+    "kp-9",          /* VK_NUMPAD9        0x69 */
+    "kp-multiply",   /* VK_MULTIPLY       0x6A */
+    "kp-add",        /* VK_ADD            0x6B */
+    "kp-separator",  /* VK_SEPARATOR      0x6C */
+    "kp-subtract",   /* VK_SUBTRACT       0x6D */
+    "kp-decimal",    /* VK_DECIMAL        0x6E */
+    "kp-divide",     /* VK_DIVIDE         0x6F */
+    "f1",            /* VK_F1             0x70 */
+    "f2",            /* VK_F2             0x71 */
+    "f3",            /* VK_F3             0x72 */
+    "f4",            /* VK_F4             0x73 */
+    "f5",            /* VK_F5             0x74 */
+    "f6",            /* VK_F6             0x75 */
+    "f7",            /* VK_F7             0x76 */
+    "f8",            /* VK_F8             0x77 */
+    "f9",            /* VK_F9             0x78 */
+    "f10",           /* VK_F10            0x79 */
+    "f11",           /* VK_F11            0x7A */
+    "f12",           /* VK_F12            0x7B */
+    "f13",           /* VK_F13            0x7C */
+    "f14",           /* VK_F14            0x7D */
+    "f15",           /* VK_F15            0x7E */
+    "f16",           /* VK_F16            0x7F */
+    "f17",           /* VK_F17            0x80 */
+    "f18",           /* VK_F18            0x81 */
+    "f19",           /* VK_F19            0x82 */
+    "f20",           /* VK_F20            0x83 */
+    "f21",           /* VK_F21            0x84 */
+    "f22",           /* VK_F22            0x85 */
+    "f23",           /* VK_F23            0x86 */
+    "f24",           /* VK_F24            0x87 */
+    
+    0, 0, 0, 0,      /*    0x88 .. 0x8B        */
+    0, 0, 0, 0,      /*    0x8C .. 0x8F        */
+    
+    "kp-numlock",    /* VK_NUMLOCK        0x90 */
+    "scroll",        /* VK_SCROLL         0x91 */
+    
+    "kp-space",             /* VK_NUMPAD_CLEAR   0x92 */
+    "kp-enter",             /* VK_NUMPAD_ENTER   0x93 */
+    "kp-prior",             /* VK_NUMPAD_PRIOR   0x94 */
+    "kp-next",      /* VK_NUMPAD_NEXT    0x95 */
+    "kp-end",       /* VK_NUMPAD_END     0x96 */
+    "kp-home",      /* VK_NUMPAD_HOME    0x97 */
+    "kp-left",      /* VK_NUMPAD_LEFT    0x98 */
+    "kp-up",        /* VK_NUMPAD_UP      0x99 */
+    "kp-right",             /* VK_NUMPAD_RIGHT   0x9A */
+    "kp-down",      /* VK_NUMPAD_DOWN    0x9B */
+    "kp-insert",     /* VK_NUMPAD_INSERT  0x9C */
+    "kp-delete",     /* VK_NUMPAD_DELETE  0x9D */
+
+    0, 0,           /*    0x9E .. 0x9F        */
+
+    /*
+     * VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
+     * Used only as parameters to GetAsyncKeyState() and GetKeyState().
+     * No other API or message will distinguish left and right keys this way.
+     */
+    /* 0xA0 .. 0xEF */
+    
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    
+    /* 0xF0 .. 0xF5 */
+    
+    0, 0, 0, 0, 0, 0,
+    
+    "attn",          /* VK_ATTN           0xF6 */
+    "crsel",         /* VK_CRSEL          0xF7 */
+    "exsel",         /* VK_EXSEL          0xF8 */
+    "ereof",         /* VK_EREOF          0xF9 */
+    "play",          /* VK_PLAY           0xFA */
+    "zoom",          /* VK_ZOOM           0xFB */
+    "noname",        /* VK_NONAME         0xFC */
+    "pa1",           /* VK_PA1            0xFD */
+    "oem_clear",     /* VK_OEM_CLEAR      0xFE */
+  };
+
+#else
+
+#define FUNCTION_KEY_OFFSET 0xff00
+
 /* You'll notice that this table is arranged to be conveniently
    indexed by X Windows keysym values.  */
 static char *lispy_function_keys[] =
@@ -2901,6 +3517,8 @@ static char *lispy_function_keys[] =
     0, 0, 0, 0, 0, 0, 0, "delete"
     };
 
+#endif /* HAVE_NTGUI */
+
 static char *lispy_mouse_names[] =
 {
   "mouse-1", "mouse-2", "mouse-3", "mouse-4", "mouse-5"
@@ -3001,16 +3619,17 @@ make_lispy_event (event)
        {
          /* We need to use an alist rather than a vector as the cache
             since we can't make a vector long enuf.  */
-         if (NILP (system_key_syms))
-           system_key_syms = Fcons (Qnil, Qnil);
-         return modify_event_symbol (event->code & 0xffffff,
+         if (NILP (current_kboard->system_key_syms))
+           current_kboard->system_key_syms = Fcons (Qnil, Qnil);
+         return modify_event_symbol (event->code,
                                      event->modifiers,
                                      Qfunction_key,
                                      current_kboard->Vsystem_key_alist,
-                                     0, &system_key_syms, 0xffffff);
+                                     0, &current_kboard->system_key_syms,
+                                     (unsigned)-1);
        }
 
-      return modify_event_symbol (event->code - 0xff00,
+      return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
                                  event->modifiers,
                                  Qfunction_key, Qnil,
                                  lispy_function_keys, &func_key_syms,
@@ -3018,6 +3637,9 @@ make_lispy_event (event)
                                   / sizeof (lispy_function_keys[0])));
       break;
 
+    case timer_event:
+      return Fcons (Qtimer_event, Fcons (Fcdr (event->frame_or_window), Qnil));
+
 #ifdef HAVE_MOUSE
       /* A mouse click.  Figure out where it is, decide whether it's
          a press, click or drag, and build the appropriate structure.  */
@@ -3058,17 +3680,20 @@ make_lispy_event (event)
               (In the toolkit version, the toolkit handles the menu bar
               and Emacs doesn't know about it until after the user
               makes a selection.)  */
-           if (row >= 0 && row < FRAME_MENU_BAR_LINES (f))
+           if (row >= 0 && row < FRAME_MENU_BAR_LINES (f)
+               && (event->modifiers & down_modifier))
              {
                Lisp_Object items, item;
                int hpos;
                int i;
 
+#if 0
                /* Activate the menu bar on the down event.  If the
                   up event comes in before the menu code can deal with it,
                   just ignore it.  */
                if (! (event->modifiers & down_modifier))
                  return Qnil;
+#endif
 
                item = Qnil;
                items = FRAME_MENU_BAR_ITEMS (f);
@@ -3260,7 +3885,7 @@ make_lispy_event (event)
       }
 #endif /* HAVE_MOUSE */
 
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
     case menu_bar_event:
       /* The event value is in the cdr of the frame_or_window slot.  */
       if (!CONSP (event->frame_or_window))
@@ -3525,7 +4150,7 @@ apply_modifiers_uncached (modifiers, base, base_len)
 static char *modifier_names[] =
 {
   "up", "down", "drag", "click", "double", "triple", 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   0, 0, "alt", "super", "hyper", "shift", "control", "meta"
 };
 #define NUM_MOD_NAMES (sizeof (modifier_names) / sizeof (modifier_names[0]))
@@ -3722,12 +4347,13 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
      Lisp_Object name_alist;
      char **name_table;
      Lisp_Object *symbol_table;
-     int table_size;
+     unsigned int table_size;
 {
   Lisp_Object value;
   Lisp_Object symbol_int;
 
-  XSETINT (symbol_int, symbol_num);
+  /* Get rid of the "vendor-specific" bit here.  */
+  XSETINT (symbol_int, symbol_num & 0xffffff);
 
   /* Is this a request for a valid symbol?  */
   if (symbol_num < 0 || symbol_num >= table_size)
@@ -3763,6 +4389,15 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
       else if (name_table[symbol_num])
        value = intern (name_table[symbol_num]);
 
+#ifdef HAVE_WINDOW_SYSTEM
+      if (NILP (value))
+       {
+         char *name = x_get_keysym_name (symbol_num);
+         if (name)
+           value = intern (name);
+       }
+#endif
+
       if (NILP (value))
        {
          char buf[20];
@@ -3791,21 +4426,21 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
    event type as a number or a symbol.  */
 
 DEFUN ("event-convert-list", Fevent_convert_list, Sevent_convert_list, 1, 1, 0,
-  "Convert the event description LIST to an event type.\n\
-LIST should contain one base event type (a character or symbol)\n\
+  "Convert the event description list EVENT-DESC to an event type.\n\
+EVENT-DESC should contain one base event type (a character or symbol)\n\
 and zero or more modifier names (control, meta, hyper, super, shift, alt,\n\
 drag, down, double or triple).\n\
 The return value is an event type (a character or symbol) which\n\
 has the same base event type and all the specified modifiers.")
-  (event)
-     Lisp_Object event;
+  (event_desc)
+     Lisp_Object event_desc;
 {
   Lisp_Object base;
   int modifiers = 0;
   Lisp_Object rest;
 
   base = Qnil;
-  rest = event;
+  rest = event_desc;
   while (CONSP (rest))
     {
       Lisp_Object elt;
@@ -3961,14 +4596,17 @@ lucid_event_type_list_p (object)
 /* Store into *addr a value nonzero if terminal input chars are available.
    Serves the purpose of ioctl (0, FIONREAD, addr)
    but works even if FIONREAD does not exist.
-   (In fact, this may actually read some input.)  */
+   (In fact, this may actually read some input.)
+
+   If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.  */
 
 static void
-get_input_pending (addr)
+get_input_pending (addr, do_timers_now)
      int *addr;
+     int do_timers_now;
 {
   /* First of all, have we already counted some input?  */
-  *addr = !NILP (Vquit_flag) || readable_events ();
+  *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
 
   /* If input is being read as it arrives, and we have none, there is none.  */
   if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
@@ -3976,7 +4614,7 @@ get_input_pending (addr)
 
   /* Try to read some input and see how much we get.  */
   gobble_input (0);
-  *addr = !NILP (Vquit_flag) || readable_events ();
+  *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
 }
 
 /* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary.  */
@@ -4110,7 +4748,7 @@ read_avail_input (expected)
       if (n_to_read > sizeof cbuf)
        n_to_read = sizeof cbuf;
 #else /* no FIONREAD */
-#if defined(USG) || defined(DGUX)
+#if defined (USG) || defined (DGUX)
       /* Read some input if available, but don't wait.  */
       n_to_read = sizeof cbuf;
       fcntl (input_fd, F_SETFL, O_NDELAY);
@@ -4126,7 +4764,7 @@ read_avail_input (expected)
       do
        {
 #ifdef MSDOS
-         cbuf[0] = dos_keyread();
+         cbuf[0] = dos_keyread ();
          nread = 1;
 #else
          nread = read (input_fd, cbuf, n_to_read);
@@ -4255,7 +4893,7 @@ void
 reinvoke_input_signal ()
 {
 #ifdef SIGIO
-  kill (0, SIGIO);
+  kill (getpid (), SIGIO);
 #endif
 }
 
@@ -4343,36 +4981,30 @@ menu_bar_items (old)
   {
     Lisp_Object *tmaps;
 
-    /* Should overriding-local-map apply, here?  */
+    /* Should overriding-terminal-local-map and overriding-local-map apply?  */
     if (!NILP (Voverriding_local_map_menu_flag))
       {
-       if (NILP (Voverriding_local_map))
-         {
-           /* Yes, and it is nil.  Use just global map.  */
-           nmaps = 1;
-           maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
-         }
-       else
-         {
-           /* Yes, and it is non-nil.  Use it and the global map.  */
-           nmaps = 2;
-           maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
-           maps[0] = Voverriding_local_map;
-         }
+       /* Yes, use them (if non-nil) as well as the global map.  */
+       maps = (Lisp_Object *) alloca (3 * sizeof (maps[0]));
+       nmaps = 0;
+       if (!NILP (current_kboard->Voverriding_terminal_local_map))
+         maps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
+       if (!NILP (Voverriding_local_map))
+         maps[nmaps++] = Voverriding_local_map;
       }
     else
       {
        /* No, so use major and minor mode keymaps.  */
-       nmaps = current_minor_maps (NULL, &tmaps) + 2;
-       maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
-       bcopy (tmaps, maps, (nmaps - 2) * sizeof (maps[0]));
+       nmaps = current_minor_maps (NULL, &tmaps);
+       maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0]));
+       bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
 #ifdef USE_TEXT_PROPERTIES
-       maps[nmaps-2] = get_local_map (PT, current_buffer);
+       maps[nmaps++] = get_local_map (PT, current_buffer);
 #else
-       maps[nmaps-2] = current_buffer->keymap;
+       maps[nmaps++] = current_buffer->keymap;
 #endif
       }
-    maps[nmaps-1] = current_global_map;
+    maps[nmaps++] = current_global_map;
   }
 
   /* Look up in each map the dummy prefix key `menu-bar'.  */
@@ -4640,7 +5272,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
   if (mapno >= nmaps)
     return Qnil;
 
-#if (defined (HAVE_X_WINDOWS) && defined (HAVE_X_MENU)) || defined (MSDOS)
+#ifdef HAVE_MENUS
   /* If we got to this point via a mouse click,
      use a real menu for mouse selection.  */
   if (EVENT_HAS_PARAMETERS (prev_event)
@@ -4660,6 +5292,23 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
       value = Fx_popup_menu (prev_event, Flist (nmaps1, realmaps));
       if (CONSP (value))
        {
+         Lisp_Object tem;
+
+         /* If we got multiple events, unread all but
+            the first.
+            There is no way to prevent those unread events
+            from showing up later in last_nonmenu_event.
+            So turn symbol and integer events into lists,
+            to indicate that they came from a mouse menu,
+            so that when present in last_nonmenu_event
+            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);
+
          /* If we got more than one event, put all but the first
             onto this list to be read later.
             Return just the first event now.  */
@@ -4673,10 +5322,16 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
        *used_mouse_menu = 1;
       return value;
     }
-#endif /* (HAVE_X_WINDOWS && HAVE_X_MENU) || MSDOS */
+#endif /* HAVE_MENUS */
   return Qnil ;
 }
 
+/* Buffer in use so far for the minibuf prompts for menu keymaps.
+   We make this bigger when necessary, and never free it.  */
+static char *read_char_minibuf_menu_text;
+/* Size of that buffer.  */
+static int read_char_minibuf_menu_width;
+
 static Lisp_Object
 read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
      int commandflag ;
@@ -4687,14 +5342,28 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
   register Lisp_Object name;
   int nlength;
   int width = FRAME_WIDTH (selected_frame) - 4;
-  char *menu = (char *) alloca (width + 4);
   int idx = -1;
   int nobindings = 1;
   Lisp_Object rest, vector;
+  char *menu;
 
   if (! menu_prompting)
     return Qnil;
 
+  /* Make sure we have a big enough buffer for the menu text.  */
+  if (read_char_minibuf_menu_text == 0)
+    {
+      read_char_minibuf_menu_width = width + 4;
+      read_char_minibuf_menu_text = (char *) xmalloc (width + 4);
+    }
+  else if (width + 4 > read_char_minibuf_menu_width)
+    {
+      read_char_minibuf_menu_width = width + 4;
+      read_char_minibuf_menu_text
+       = (char *) xrealloc (read_char_minibuf_menu_text, width + 4);
+    }
+  menu = read_char_minibuf_menu_text;
+
   /* Get the menu name from the first map that has one (a prompt string).  */
   for (mapno = 0; mapno < nmaps; mapno++)
     {
@@ -4763,43 +5432,81 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
          else
            {
              /* An ordinary element.  */
-             if ( idx < 0 )
-               s = Fcar_safe (Fcdr_safe (elt));        /* alist */
+             Lisp_Object event;
+
+             if (idx < 0)
+               {
+                 s = Fcar_safe (Fcdr_safe (elt));      /* alist */
+                 event = Fcar_safe (elt);
+               }
              else
-               s = Fcar_safe(elt);                     /* vector */
-             if (!STRINGP (s))
-               /* Ignore the element if it has no prompt string.  */
-               ;
-             /* If we have room for the prompt string, add it to this line.
-                If this is the first on the line, always add it.  */
-             else if (XSTRING (s)->size + i + 2 < width
-                      || !notfirst)
                {
-                 int thiswidth;
+                 s = Fcar_safe (elt);                  /* vector */
+                 XSETINT (event, idx);
+               }
 
-                 /* Punctuate between strings.  */
-                 if (notfirst)
+             /* Ignore the element if it has no prompt string.  */
+             if (STRINGP (s) && INTEGERP (event))
+               {
+                 /* 1 if the char to type matches the string.  */
+                 int char_matches;
+                 Lisp_Object upcased_event, downcased_event;
+                 Lisp_Object desc;
+
+                 upcased_event = Fupcase (event);
+                 downcased_event = Fdowncase (event);
+                 char_matches = (XINT (upcased_event) == XSTRING (s)->data[0]
+                                 || XINT (downcased_event) == XSTRING (s)->data[0]);
+                 if (! char_matches)
+                   desc = Fsingle_key_description (event);
+
+                 /* If we have room for the prompt string, add it to this line.
+                    If this is the first on the line, always add it.  */
+                 if ((XSTRING (s)->size + i + 2
+                      + (char_matches ? 0 : XSTRING (desc)->size + 3))
+                     < width
+                     || !notfirst)
                    {
-                     strcpy (menu + i, ", ");
-                     i += 2;
+                     int thiswidth;
+
+                     /* Punctuate between strings.  */
+                     if (notfirst)
+                       {
+                         strcpy (menu + i, ", ");
+                         i += 2;
+                       }
+                     notfirst = 1;
+                     nobindings = 0 ;
+
+                     /* If the char to type doesn't match the string's
+                        first char, explicitly show what char to type.  */
+                     if (! char_matches)
+                       {
+                         /* Add as much of string as fits.  */
+                         thiswidth = XSTRING (desc)->size;
+                         if (thiswidth + i > width)
+                           thiswidth = width - i;
+                         bcopy (XSTRING (desc)->data, menu + i, thiswidth);
+                         i += thiswidth;
+                         strcpy (menu + i, " = ");
+                         i += 3;
+                       }
+
+                     /* Add as much of string as fits.  */
+                     thiswidth = XSTRING (s)->size;
+                     if (thiswidth + i > width)
+                       thiswidth = width - i;
+                     bcopy (XSTRING (s)->data, menu + i, thiswidth);
+                     i += thiswidth;
+                     menu[i] = 0;
+                   }
+                 else
+                   {
+                     /* If this element does not fit, end the line now,
+                        and save the element for the next line.  */
+                     strcpy (menu + i, "...");
+                     break;
                    }
-                 notfirst = 1;
-                 nobindings = 0 ;
-
-                 /* Add as much of string as fits.  */
-                 thiswidth = XSTRING (s)->size;
-                 if (thiswidth + i > width)
-                   thiswidth = width - i;
-                 bcopy (XSTRING (s)->data, menu + i, thiswidth);
-                 i += thiswidth;
-                 menu[i] = 0;
-               }
-             else
-               {
-                 /* If this element does not fit, end the line now,
-                    and save the element for the next line.  */
-                 strcpy (menu + i, "...");
-                 break;
                }
 
              /* Move past this element.  */
@@ -4859,7 +5566,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
    If KEY has no bindings in any of the CURRENT maps, NEXT is left
    unmodified.
 
-   NEXT may == CURRENT.  */
+   NEXT may be the same array as CURRENT.  */
 
 static int
 follow_key (key, nmaps, current, defs, next)
@@ -4868,26 +5575,30 @@ follow_key (key, nmaps, current, defs, next)
      int nmaps;
 {
   int i, first_binding;
+  int did_meta = 0;
 
   /* If KEY is a meta ASCII character, treat it like meta-prefix-char
-     followed by the corresponding non-meta character.  */
+     followed by the corresponding non-meta character.
+     Put the results into DEFS, since we are going to alter that anyway.
+     Do not alter CURRENT or NEXT.  */
   if (INTEGERP (key) && (XINT (key) & CHAR_META))
     {
       for (i = 0; i < nmaps; i++)
        if (! NILP (current[i]))
          {
-           next[i] =
-             get_keyelt (access_keymap (current[i], meta_prefix_char, 1, 0));
+           Lisp_Object def;
+           def = get_keyelt (access_keymap (current[i],
+                                            meta_prefix_char, 1, 0));
 
            /* Note that since we pass the resulting bindings through
               get_keymap_1, non-prefix bindings for meta-prefix-char
               disappear.  */
-           next[i] = get_keymap_1 (next[i], 0, 1);
+           defs[i] = get_keymap_1 (def, 0, 1);
          }
        else
-         next[i] = Qnil;
+         defs[i] = Qnil;
 
-      current = next;
+      did_meta = 1;
       XSETINT (key, XFASTINT (key) & ~CHAR_META);
     }
 
@@ -4896,7 +5607,13 @@ follow_key (key, nmaps, current, defs, next)
     {
       if (! NILP (current[i]))
        {
-         defs[i] = get_keyelt (access_keymap (current[i], key, 1, 0));
+         Lisp_Object map;
+         if (did_meta)
+           map = defs[i];
+         else
+           map = current[i];
+
+         defs[i] = get_keyelt (access_keymap (map, key, 1, 0));
          if (! NILP (defs[i]))
            first_binding = i;
        }
@@ -5042,6 +5759,16 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   int function_key_possible = 0;
   int key_translation_possible = 0;
 
+  /* 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;
+
+  Lisp_Object prev_keytran_map;
+  Lisp_Object prev_keytran_start;
+  Lisp_Object prev_keytran_end;
+
   int junk;
 
   last_nonmenu_event = Qnil;
@@ -5104,34 +5831,38 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   {
     Lisp_Object *maps;
 
-    if (!NILP (Voverriding_local_map))
+    if (!NILP (current_kboard->Voverriding_terminal_local_map)
+       || !NILP (Voverriding_local_map))
       {
-       nmaps = 2;
-       if (nmaps > nmaps_allocated)
+       if (3 > nmaps_allocated)
          {
-           submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
-           defs    = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
-           nmaps_allocated = nmaps;
+           submaps = (Lisp_Object *) alloca (3 * sizeof (submaps[0]));
+           defs    = (Lisp_Object *) alloca (3 * sizeof (defs[0]));
+           nmaps_allocated = 3;
          }
-       submaps[0] = Voverriding_local_map;
+       nmaps = 0;
+       if (!NILP (current_kboard->Voverriding_terminal_local_map))
+         submaps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
+       if (!NILP (Voverriding_local_map))
+         submaps[nmaps++] = Voverriding_local_map;
       }
     else
       {
-       nmaps = current_minor_maps (0, &maps) + 2;
-       if (nmaps > nmaps_allocated)
+       nmaps = current_minor_maps (0, &maps);
+       if (nmaps + 2 > nmaps_allocated)
          {
-           submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
-           defs    = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
-           nmaps_allocated = nmaps;
+           submaps = (Lisp_Object *) alloca ((nmaps+2) * sizeof (submaps[0]));
+           defs    = (Lisp_Object *) alloca ((nmaps+2) * sizeof (defs[0]));
+           nmaps_allocated = nmaps + 2;
          }
-       bcopy (maps, submaps, (nmaps - 2) * sizeof (submaps[0]));
+       bcopy (maps, submaps, nmaps * sizeof (submaps[0]));
 #ifdef USE_TEXT_PROPERTIES
-       submaps[nmaps-2] = orig_local_map;
+       submaps[nmaps++] = orig_local_map;
 #else
-       submaps[nmaps-2] = current_buffer->keymap;
+       submaps[nmaps++] = current_buffer->keymap;
 #endif
       }
-    submaps[nmaps-1] = current_global_map;
+    submaps[nmaps++] = current_global_map;
   }
 
   /* Find an accurate initial value for first_binding.  */
@@ -5182,7 +5913,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       int echo_local_start, keys_local_start, local_first_binding;
 
       if (t >= bufsize)
-       error ("key sequence too long");
+       error ("Key sequence too long");
 
       if (INTERACTIVE)
        echo_local_start = echo_length ();
@@ -5371,7 +6102,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
                  if (CONSP (start) && CONSP (XCONS (start)->cdr))
                    {
                      pos = POSN_BUFFER_POSN (start);
-                     if (INTEGERP (pos))
+                     if (INTEGERP (pos)
+                         && XINT (pos) >= BEG && XINT (pos) <= Z)
                        {
                          map_here = get_local_map (XINT (pos), current_buffer);
                          if (!EQ (map_here, orig_local_map))
@@ -5391,7 +6123,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              if (SYMBOLP (posn))
                {
                  if (t + 1 >= bufsize)
-                   error ("key sequence too long");
+                   error ("Key sequence too long");
                  keybuf[t] = posn;
                  keybuf[t+1] = key;
                  mock_input = t + 2;
@@ -5426,7 +6158,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
              if (EQ (posn, Qmenu_bar))
                {
                  if (t + 1 >= bufsize)
-                   error ("key sequence too long");
+                   error ("Key sequence too long");
                  keybuf[t] = posn;
                  keybuf[t+1] = key;
 
@@ -5464,7 +6196,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          Lisp_Object head;
 
          head = EVENT_HEAD (key);
-         if (help_char_p (head))
+         if (help_char_p (head) && t > 0)
            {
              read_key_sequence_cmd = Vprefix_help_command;
              keybuf[t++] = key;
@@ -5585,6 +6317,14 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       if (!used_mouse_menu)
        last_nonmenu_event = key;
 
+      prev_fkey_map = fkey_map;
+      prev_fkey_start = fkey_start;
+      prev_fkey_end = fkey_end;
+
+      prev_keytran_map = keytran_map;
+      prev_keytran_start = keytran_start;
+      prev_keytran_end = keytran_end;
+
       /* If the sequence is unbound, see if we can hang a function key
         off the end of it.  We only want to scan real keyboard input
         for function key sequences, so if mock_input says that we're
@@ -5661,7 +6401,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                  t = fkey_start + len;
                  if (t >= bufsize)
-                   error ("key sequence too long");
+                   error ("Key sequence too long");
 
                  if (VECTORP (fkey_next))
                    bcopy (XVECTOR (fkey_next)->contents,
@@ -5761,7 +6501,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
 
                t = keytran_start + len;
                if (t >= bufsize)
-                 error ("key sequence too long");
+                 error ("Key sequence too long");
 
                if (VECTORP (keytran_next))
                  bcopy (XVECTOR (keytran_next)->contents,
@@ -5813,17 +6553,31 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
               && UPPERCASEP (XINT (key) & 0x3ffff))
              || (XINT (key) & shift_modifier)))
        {
+         Lisp_Object new_key;
+
          original_uppercase = key;
          original_uppercase_position = t - 1;
 
-         if (XINT (key) & shift_modifier)
-           XSETINT (key, XINT (key) & ~shift_modifier);
+         if (XINT (new_key) & shift_modifier)
+           XSETINT (new_key, XINT (key) & ~shift_modifier);
          else
-           XSETINT (key, (DOWNCASE (XINT (key) & 0x3ffff)
-                          | (XINT (key) & ~0x3ffff)));
+           XSETINT (new_key, (DOWNCASE (XINT (key) & 0x3ffff)
+                              | (XINT (key) & ~0x3ffff)));
 
-         keybuf[t - 1] = key;
+         /* We have to do this unconditionally, regardless of whether
+            the lower-case char is defined in the keymaps, because they
+            might get translated through function-key-map.  */
+         keybuf[t - 1] = new_key;
          mock_input = t;
+
+         fkey_map = prev_fkey_map;
+         fkey_start = prev_fkey_start;
+         fkey_end = prev_fkey_end;
+
+         keytran_map = prev_keytran_map;
+         keytran_start = prev_keytran_start;
+         keytran_end = prev_keytran_end;
+
          goto replay_sequence;
        }
       /* If KEY is not defined in any of the keymaps,
@@ -5837,19 +6591,30 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          Lisp_Object breakdown;
          int modifiers;
 
-         original_uppercase = key;
-         original_uppercase_position = t - 1;
-
          breakdown = parse_modifiers (key);
          modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
          if (modifiers & shift_modifier)
            {
+             Lisp_Object new_key;
+
+             original_uppercase = key;
+             original_uppercase_position = t - 1;
+
              modifiers &= ~shift_modifier;
-             key = apply_modifiers (modifiers,
-                                    XCONS (breakdown)->car);
+             new_key = apply_modifiers (modifiers,
+                                        XCONS (breakdown)->car);
 
-             keybuf[t - 1] = key;
+             keybuf[t - 1] = new_key;
              mock_input = t;
+
+             fkey_map = prev_fkey_map;
+             fkey_start = prev_fkey_start;
+             fkey_end = prev_fkey_end;
+
+             keytran_map = prev_keytran_map;
+             keytran_start = prev_keytran_start;
+             keytran_end = prev_keytran_end;
+
              goto replay_sequence;
            }
        }
@@ -5863,7 +6628,10 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   unread_switch_frame = delayed_switch_frame;
   unbind_to (count, Qnil);
 
-  if (dont_downcase_last && t - 1 == original_uppercase_position)
+  /* Don't downcase the last character if the caller says don't.
+     Don't downcase it if the result is undefined, either.  */
+  if ((dont_downcase_last || first_binding >= nmaps)
+      && t - 1 == original_uppercase_position)
     keybuf[t - 1] = original_uppercase;
 
   /* Occasionally we fabricate events, perhaps by expanding something
@@ -5966,14 +6734,18 @@ DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
   return make_event_array (i, keybuf);
 }
 \f
-DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 2, 0,
+DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0,
  "Execute CMD as an editor command.\n\
 CMD must be a symbol that satisfies the `commandp' predicate.\n\
 Optional second arg RECORD-FLAG non-nil\n\
 means unconditionally put this command in `command-history'.\n\
-Otherwise, that is done only if an arg is read using the minibuffer.")
-     (cmd, record)
-     Lisp_Object cmd, record;
+Otherwise, that is done only if an arg is read using the minibuffer.\n\
+The argument KEYS specifies the value to use instead of (this-command-keys)\n\
+when reading the arguments; if it is nil, (this_command_key_count) is used.\n\
+The argument SPECIAL, if non-nil, means that this command is executing\n\
+a special event, so ignore the prefix argument and don't clear it.")
+     (cmd, record_flag, keys, special)
+     Lisp_Object cmd, record_flag, keys, special;
 {
   register Lisp_Object final;
   register Lisp_Object tem;
@@ -5981,16 +6753,26 @@ Otherwise, that is done only if an arg is read using the minibuffer.")
   struct backtrace backtrace;
   extern int debug_on_next_call;
 
-  prefixarg = current_kboard->Vprefix_arg;
-  current_kboard->Vprefix_arg = Qnil;
-  Vcurrent_prefix_arg = prefixarg;
   debug_on_next_call = 0;
 
+  if (NILP (special))
+    {
+      prefixarg = current_kboard->Vprefix_arg;
+      Vcurrent_prefix_arg = prefixarg;
+      current_kboard->Vprefix_arg = Qnil;
+    }
+  else
+    prefixarg = Qnil;
+
   if (SYMBOLP (cmd))
     {
       tem = Fget (cmd, Qdisabled);
       if (!NILP (tem) && !NILP (Vrun_hooks))
-       return call1 (Vrun_hooks, Qdisabled_command_hook);
+       {
+         tem = Fsymbol_value (Qdisabled_command_hook);
+         if (!NILP (tem))
+           return call1 (Vrun_hooks, Qdisabled_command_hook);
+       }
     }
 
   while (1)
@@ -6008,7 +6790,7 @@ Otherwise, that is done only if an arg is read using the minibuffer.")
       /* If requested, place the macro in the command history.  For
         other sorts of commands, call-interactively takes care of
         this.  */
-      if (!NILP (record))
+      if (!NILP (record_flag))
        Vcommand_history
          = Fcons (Fcons (Qexecute_kbd_macro,
                          Fcons (final, Fcons (prefixarg, Qnil))),
@@ -6025,7 +6807,7 @@ Otherwise, that is done only if an arg is read using the minibuffer.")
       backtrace.nargs = 1;
       backtrace.evalargs = 0;
 
-      tem = Fcall_interactively (cmd, record);
+      tem = Fcall_interactively (cmd, record_flag, keys);
 
       backtrace_list = backtrace.next;
       return tem;
@@ -6085,6 +6867,9 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
                               Vobarray, Qcommandp,
                               Qt, Qnil, Qextended_command_history);
 
+  if (STRINGP (function) && XSTRING (function)->size == 0)
+    error ("No command name given");
+
   /* Set this_command_keys to the concatenation of saved_keys and
      function, followed by a RET.  */
   {
@@ -6116,14 +6901,93 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
   current_kboard->Vprefix_arg = prefixarg;
   this_command = function;
 
-  return Fcommand_execute (function, Qt);
+  /* If enabled, show which key runs this command.  */
+  if (!NILP (Vsuggest_key_bindings)
+      && SYMBOLP (function))
+    {
+      Lisp_Object bindings;
+
+      bindings = Fwhere_is_internal (function, Voverriding_local_map,
+                                    Qt, Qnil);
+
+      if (!NILP (bindings))
+       {
+         message ("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);
+       }
+    }
+
+  return Fcommand_execute (function, Qt, Qnil, Qnil);
+}
+
+/* Find the set of keymaps now active.
+   Store into *MAPS_P a vector holding the various maps
+   and return the number of them.  The vector was malloc'd
+   and the caller should free it.  */
+
+int
+current_active_maps (maps_p)
+     Lisp_Object **maps_p;
+{
+  Lisp_Object *tmaps, *maps;
+  int nmaps;
+
+  /* Should overriding-terminal-local-map and overriding-local-map apply?  */
+  if (!NILP (Voverriding_local_map_menu_flag))
+    {
+      /* Yes, use them (if non-nil) as well as the global map.  */
+      maps = (Lisp_Object *) xmalloc (3 * sizeof (maps[0]));
+      nmaps = 0;
+      if (!NILP (current_kboard->Voverriding_terminal_local_map))
+       maps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
+      if (!NILP (Voverriding_local_map))
+       maps[nmaps++] = Voverriding_local_map;
+    }
+  else
+    {
+      /* No, so use major and minor mode keymaps.  */
+      nmaps = current_minor_maps (NULL, &tmaps);
+      maps = (Lisp_Object *) xmalloc ((nmaps + 2) * sizeof (maps[0]));
+      bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
+#ifdef USE_TEXT_PROPERTIES
+      maps[nmaps++] = get_local_map (PT, current_buffer);
+#else
+      maps[nmaps++] = current_buffer->keymap;
+#endif
+    }
+  maps[nmaps++] = current_global_map;
+
+  *maps_p = maps;
+  return nmaps;
 }
 \f
+/* Return nonzero if input events are pending.  */
 
 detect_input_pending ()
 {
   if (!input_pending)
-    get_input_pending (&input_pending);
+    get_input_pending (&input_pending, 0);
+
+  return input_pending;
+}
+
+/* Return nonzero if input events are pending.
+   Execute timers immediately; don't make events for them.  */
+
+detect_input_pending_run_timers (do_display)
+     int do_display;
+{
+  int old_timers_run = timers_run;
+
+  if (!input_pending)
+    get_input_pending (&input_pending, 1);
+
+  if (old_timers_run != timers_run && do_display)
+    redisplay_preserve_echo_area ();
 
   return input_pending;
 }
@@ -6144,7 +7008,8 @@ Actually, the value is nil only if we can be sure that no input is available.")
   if (!NILP (Vunread_command_events) || unread_command_char != -1)
     return (Qt);
 
-  return detect_input_pending () ? Qt : Qnil;
+  get_input_pending (&input_pending, 1);
+  return input_pending > 0 ? Qt : Qnil;
 }
 
 DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
@@ -6178,6 +7043,26 @@ The value is a string or a vector.")
                           XVECTOR (this_command_keys)->contents);
 }
 
+DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
+  Sreset_this_command_lengths, 0, 0, 0,
+  "Used for complicated reasons in `universal-argument-other-key'.\n\
+\n\
+`universal-argument-other-key' rereads the event just typed.\n\
+It then gets translated through `function-key-map'.\n\
+The translated event gets included in the echo area and in\n\
+the value of `this-command-keys' in addition to the raw original event.\n\
+That is not right.\n\
+\n\
+Calling this function directs the translated event to replace\n\
+the original event, so that only one version of the event actually\n\
+appears in the echo area and in the value of `this-command-keys.'.")
+  ()
+{
+  before_command_restore_flag = 1;
+  before_command_key_count_1 = before_command_key_count;
+  before_command_echo_length_1 = before_command_echo_length;
+}
+
 DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
   "Return the current depth in recursive edits.")
   ()
@@ -6194,18 +7079,17 @@ If FILE is nil, close any open dribble file.")
   (file)
      Lisp_Object file;
 {
-  if (NILP (file))
+  if (dribble)
     {
-      if (dribble)
-       {
-         fclose (dribble);
-         dribble = 0;
-       }
+      fclose (dribble);
+      dribble = 0;
     }
-  else
+  if (!NILP (file))
     {
       file = Fexpand_file_name (file, Qnil);
       dribble = fopen (XSTRING (file)->data, "w");
+      if (dribble == 0)
+       report_file_error ("Opening dribble", Fcons (file, Qnil));
     }
   return Qnil;
 }
@@ -6417,18 +7301,35 @@ interrupt_signal (signalnum)    /* If we don't have an argument, */
         is used.  Note that [Enter] is not echoed by dos.  */
       cursor_to (0, 0);
 #endif
-      printf ("Auto-save? (y or n) ");
-      fflush (stdout);
-      if (((c = getchar ()) & ~040) == 'Y')
+      /* It doesn't work to autosave while GC is in progress;
+        the code used for auto-saving doesn't cope with the mark bit.  */
+      if (!gc_in_progress)
        {
-         Fdo_auto_save (Qt, Qnil);
+         printf ("Auto-save? (y or n) ");
+         fflush (stdout);
+         if (((c = getchar ()) & ~040) == 'Y')
+           {
+             Fdo_auto_save (Qt, Qnil);
 #ifdef MSDOS
-         printf ("\r\nAuto-save done");
+             printf ("\r\nAuto-save done");
 #else /* not MSDOS */
-         printf ("Auto-save done\n");
+             printf ("Auto-save done\n");
 #endif /* not MSDOS */
+           }
+         while (c != '\n') c = getchar ();
        }
-      while (c != '\n') c = getchar ();
+      else 
+       {
+         /* During GC, it must be safe to reenable quitting again.  */
+         Vinhibit_quit = Qnil;
+#ifdef MSDOS
+         printf ("\r\n");
+#endif /* not MSDOS */
+         printf ("Garbage collection in progress; cannot auto-save now\r\n");
+         printf ("but will instead do a real quit after garbage collection ends\r\n");
+         fflush (stdout);
+       }
+
 #ifdef MSDOS
       printf ("\r\nAbort?  (y or n) ");
 #else /* not MSDOS */
@@ -6485,15 +7386,20 @@ quit_throw_to_read_char ()
   Vunread_command_events = Qnil;
   unread_command_char = -1;
 
+#if 0 /* Currently, sit_for is called from read_char without turning
+        off polling.  And that can call set_waiting_for_input.
+        It seems to be harmless.  */
 #ifdef POLL_FOR_INPUT
   /* May be > 1 if in recursive minibuffer.  */
   if (poll_suppress_count == 0)
     abort ();
 #endif
+#endif
 #ifdef MULTI_FRAME
   if (FRAMEP (internal_last_event_frame)
       && XFRAME (internal_last_event_frame) != selected_frame)
-    Fhandle_switch_frame (make_lispy_switch_frame (internal_last_event_frame));
+    do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
+                    Qnil, 0);
 #endif
 
   _longjmp (getcjmp, 1);
@@ -6521,7 +7427,11 @@ See also `current-input-mode'.")
   stop_polling ();
 #endif
 
+#ifndef MSDOS
+  /* this causes startup screen to be restored and messes with the mouse */
   reset_sys_modes ();
+#endif
+
 #ifdef SIGIO
 /* Note SIGIO has been undef'd if FIONREAD is missing.  */
   if (read_socket_hook)
@@ -6556,7 +7466,9 @@ See also `current-input-mode'.")
     /* Don't let this value be out of range.  */
     quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
 
+#ifndef MSDOS
   init_sys_modes ();
+#endif
 
 #ifdef POLL_FOR_INPUT
   poll_suppress_count = 1;
@@ -6599,6 +7511,7 @@ void
 init_kboard (kb)
      KBOARD *kb;
 {
+  kb->Voverriding_terminal_local_map = Qnil;
   kb->Vlast_command = Qnil;
   kb->Vprefix_arg = Qnil;
   kb->kbd_queue = Qnil;
@@ -6612,12 +7525,13 @@ init_kboard (kb)
   kb->Vlast_kbd_macro = Qnil;
   kb->reference_count = 0;
   kb->Vsystem_key_alist = Qnil;
+  kb->system_key_syms = Qnil;
   kb->Vdefault_minibuffer_frame = Qnil;
 }
 
 /*
  * Destroy the contents of a kboard object, but not the object itself.
- * We use this just before deleteing it, or if we're going to initialize
+ * We use this just before deleting it, or if we're going to initialize
  * it a second time.
  */
 static void
@@ -6651,6 +7565,7 @@ init_keyboard ()
   quit_char = Ctl ('g');
   Vunread_command_events = Qnil;
   unread_command_char = -1;
+  EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
   total_keys = 0;
   recent_keys_index = 0;
   kbd_fetch_ptr = kbd_buffer;
@@ -6764,6 +7679,9 @@ syms_of_keyboard ()
   Qpost_command_hook = intern ("post-command-hook");
   staticpro (&Qpost_command_hook);
 
+  Qpost_command_idle_hook = intern ("post-command-idle-hook");
+  staticpro (&Qpost_command_idle_hook);
+
   Qdeferred_action_function = intern ("deferred-action-function");
   staticpro (&Qdeferred_action_function);
 
@@ -6774,6 +7692,8 @@ 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);
@@ -6859,9 +7779,6 @@ syms_of_keyboard ()
   func_key_syms = Qnil;
   staticpro (&func_key_syms);
 
-  system_key_syms = Qnil;
-  staticpro (&system_key_syms);
-
   mouse_syms = Qnil;
   staticpro (&mouse_syms);
 
@@ -6878,6 +7795,7 @@ syms_of_keyboard ()
   defsubr (&Scommand_execute);
   defsubr (&Srecent_keys);
   defsubr (&Sthis_command_keys);
+  defsubr (&Sreset_this_command_lengths);
   defsubr (&Ssuspend_emacs);
   defsubr (&Sabort_recursive_edit);
   defsubr (&Sexit_recursive_edit);
@@ -7009,17 +7927,14 @@ Useful to set before you dump a modified Emacs.");
   Vtop_level = Qnil;
 
   DEFVAR_LISP ("keyboard-translate-table", &Vkeyboard_translate_table,
-    "String used as translate table for keyboard input, or nil.\n\
+    "Translate table for keyboard input, or nil.\n\
 Each character is looked up in this string and the contents used instead.\n\
-If string is of length N, character codes N and up are untranslated.");
+The value may be a string, a vector, or a char-table.\n\
+If it is a string or vector of length N,\n\
+character codes N and up are untranslated.\n\
+In a vector or a char-table, an element which is nil means \"no translation\".");
   Vkeyboard_translate_table = Qnil;
 
-  DEFVAR_LISP ("key-translation-map", &Vkey_translation_map,
-    "Keymap of key translations that can override keymaps.\n\
-This keymap works like `function-key-map', but comes after that,\n\
-and applies even for keys that have ordinary bindings.");
-  Vkey_translation_map = Qnil;
-
   DEFVAR_BOOL ("cannot-suspend", &cannot_suspend,
     "Non-nil means to always spawn a subshell instead of suspending,\n\
 even if the operating system has support for stopping a process.");
@@ -7066,22 +7981,24 @@ Buffer modification stores t in this variable.");
 
   DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
     "Normal hook run before each command is executed.\n\
-While the hook is run, its value is temporarily set to nil\n\
-to avoid an unbreakable infinite loop if a hook function gets an error.\n\
-As a result, a hook function cannot straightforwardly alter the value of\n\
-`pre-command-hook'.  See the Emacs Lisp manual for a way of\n\
-implementing hook functions that alter the set of hook functions.");
+Errors running the hook are caught and ignored.");
   Vpre_command_hook = Qnil;
 
   DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
     "Normal hook run after each command is executed.\n\
-While the hook is run, its value is temporarily set to nil\n\
-to avoid an unbreakable infinite loop if a hook function gets an error.\n\
-As a result, a hook function cannot straightforwardly alter the value of\n\
-`post-command-hook'.  See the Emacs Lisp manual for a way of\n\
-implementing hook functions that alter the set of hook functions.");
+Errors running the hook are caught and ignored.");
   Vpost_command_hook = Qnil;
 
+  DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
+    "Normal hook run after each command is executed, if idle.\n\
+Errors running the hook are caught and ignored.");
+  Vpost_command_idle_hook = Qnil;
+
+  DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay,
+    "Delay time before running `post-command-idle-hook'.\n\
+This is measured in microseconds.");
+  post_command_idle_delay = 100000;
+
   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;
@@ -7091,6 +8008,12 @@ implementing hook functions that alter the set of hook functions.");
 The elements of the list are event types that may have menu bar bindings.");
   Vmenu_bar_final_items = Qnil;
 
+  DEFVAR_KBOARD ("overriding-terminal-local-map",
+                Voverriding_terminal_local_map,
+    "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.");
+
   DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
     "Keymap that overrides all other local keymaps.\n\
 If this variable is non-nil, it is used as a keymap instead of the\n\
@@ -7103,6 +8026,10 @@ Otherwise, the menu bar continues to reflect the buffer's local map\n\
 and the minor mode maps regardless of `overriding-local-map'.");
   Voverriding_local_map_menu_flag = Qnil;
 
+  DEFVAR_LISP ("special-event-map", &Vspecial_event_map,
+    "Keymap defining bindings for special events to execute at low level.");
+  Vspecial_event_map = Fcons (intern ("keymap"), Qnil);
+
   DEFVAR_LISP ("track-mouse", &do_mouse_tracking,
     "*Non-nil means generate motion events for mouse motion.");
 
@@ -7122,6 +8049,24 @@ The precise format isn't relevant here; we just check whether it is nil.");
 This function is called with no arguments after each command\n\
 whenever `deferred-action-list' is non-nil.");
   Vdeferred_action_function = Qnil;
+
+  DEFVAR_LISP ("suggest-key-bindings", &Vsuggest_key_bindings,
+    "Non-nil means show the equivalent key-binding when M-x command has one.\n\
+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;
+
+  DEFVAR_LISP ("timer-idle-list", &Vtimer_idle_list,
+    "List of active idle-time timers in order of increasing time");
+  Vtimer_idle_list = Qnil;
 }
 
 keys_of_keyboard ()
@@ -7131,4 +8076,11 @@ keys_of_keyboard ()
   initial_define_key (meta_map, Ctl ('C'), "exit-recursive-edit");
   initial_define_key (global_map, Ctl (']'), "abort-recursive-edit");
   initial_define_key (meta_map, 'x', "execute-extended-command");
+
+  initial_define_lispy_key (Vspecial_event_map, "delete-frame",
+                           "handle-delete-frame");
+  initial_define_lispy_key (Vspecial_event_map, "iconify-frame",
+                           "ignore-event");
+  initial_define_lispy_key (Vspecial_event_map, "make-frame-visible",
+                           "ignore-event");
 }