changeset 518:3a316f923456

Initial revision
author Jim Blandy <jimb@redhat.com>
date Tue, 28 Jan 1992 17:22:57 +0000
parents 2f2206ac3dba
children dad03690e241
files src/keyboard.c src/keyboard.h
diffstat 2 files changed, 3772 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/keyboard.c	Tue Jan 28 17:22:57 1992 +0000
@@ -0,0 +1,3704 @@
+/* Keyboard and mouse input; editor command loop.
+   Copyright (C) 1985, 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+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.  */
+
+/* Allow config.h to undefine symbols found here.  */
+#include <signal.h>
+
+#include "config.h"
+#include <stdio.h>
+#undef NULL
+#include "termchar.h"
+#include "termopts.h"
+#include "lisp.h"
+#include "termhooks.h"
+#include "macros.h"
+#include "screen.h"
+#include "window.h"
+#include "commands.h"
+#include "buffer.h"
+#include "disptab.h"
+#include "keyboard.h"
+#include <setjmp.h>
+#include <errno.h>
+
+#include "emacssignal.h"
+
+extern int errno;
+
+/* Get FIONREAD, if it is available.  */
+#ifdef USG
+#include <termio.h>
+#include <fcntl.h>
+#else /* not USG */
+#ifndef VMS
+#include <sys/ioctl.h>
+#endif /* not VMS */
+#endif /* not USG */
+
+/* UNIPLUS systems may have FIONREAD.  */
+#ifdef UNIPLUS
+#include <sys.ioctl.h>
+#endif
+
+#ifdef HAVE_X_WINDOWS
+extern Lisp_Object Vmouse_grabbed;
+
+/* Make all keyboard buffers much bigger when using X windows.  */
+#define KBD_BUFFER_SIZE 4096
+#else	/* No X-windows, character input */
+#define KBD_BUFFER_SIZE 256
+#endif	/* No X-windows */
+
+/* Following definition copied from eval.c */
+
+struct backtrace
+  {
+    struct backtrace *next;
+    Lisp_Object *function;
+    Lisp_Object *args;	/* Points to vector of args. */
+    int nargs;		/* length of vector.  If nargs is UNEVALLED,
+			   args points to slot holding list of
+			   unevalled args */
+    char evalargs;
+  };
+
+/* Non-nil disable property on a command means
+   do not execute it; call disabled-command-hook's value instead.  */
+Lisp_Object Qdisabled, Vdisabled_command_hook;
+
+#define NUM_RECENT_KEYS (100)
+int recent_keys_index;	/* Index for storing next element into recent_keys */
+int total_keys;		/* Total number of elements stored into recent_keys */
+Lisp_Object recent_keys[NUM_RECENT_KEYS]; /* Holds last 100 keystrokes */
+
+/* Buffer holding the key that invoked the current command.  */
+Lisp_Object *this_command_keys;
+int this_command_key_count;	/* Size in use.  */
+int this_command_keys_size;	/* Size allocated.  */
+
+extern int minbuf_level;
+
+extern struct backtrace *backtrace_list;
+
+/* Nonzero means do menu prompting.  */
+static int menu_prompting;
+
+/* Character to see next line of menu prompt.  */
+static Lisp_Object menu_prompt_more_char;
+
+/* For longjmp to where kbd input is being done.  */
+static jmp_buf getcjmp;
+
+/* True while doing kbd input.  */
+int waiting_for_input;
+
+/* True while displaying for echoing.   Delays C-g throwing.  */
+static int echoing;
+
+/* Nonzero means C-G should cause immediate error-signal.  */
+int immediate_quit;
+
+/* Character to recognize as the help char.  */
+Lisp_Object help_char;
+
+/* Form to execute when help char is typed.  */
+Lisp_Object Vhelp_form;
+
+/* Character that causes a quit.  Normally C-g.
+
+   If we are running on an ordinary terminal, this must be an ordinary
+   ASCII char, since we want to make it our interrupt character.
+
+   If we are not running on an ordinary terminal, it still needs to be
+   an ordinary ASCII char.  This character needs to be recognized in
+   the input interrupt handler.  At this point, the keystroke is
+   represented as a struct input_event, while the desired quit
+   character is specified as a lispy event.  The mapping from struct
+   input_events to lispy events cannot run in an interrupt handler,
+   and the reverse mapping is difficult for anything but ASCII
+   keystrokes.
+
+   FOR THESE ELABORATE AND UNSATISFYING REASONS, quit_char must be an
+   ASCII character.  */
+int quit_char;
+
+extern Lisp_Object current_global_map;
+extern int minibuf_level;
+
+/* Current depth in recursive edits.  */
+int command_loop_level;
+
+/* Total number of times command_loop has read a key sequence.  */
+int num_input_keys;
+
+/* Last input character read as a command.  */
+Lisp_Object last_command_char;
+
+/* Last input character read for any purpose.  */
+Lisp_Object last_input_char;
+
+/* If not Qnil, an object to be read as the next command input.  */
+Lisp_Object unread_command_char;
+
+/* Char to use as prefix when a meta character is typed in.
+   This is bound on entry to minibuffer in case ESC is changed there.  */
+
+Lisp_Object meta_prefix_char;
+
+/* Last size recorded for a current buffer which is not a minibuffer.  */
+static int last_non_minibuf_size;
+
+/* Number of idle seconds before an auto-save.  */
+static Lisp_Object Vauto_save_timeout;
+
+/* Total number of times read_char has returned.  */
+int num_input_chars;
+
+/* Auto-save automatically when this many characters have been typed
+   since the last time.  */
+
+static int auto_save_interval;
+
+/* Value of num_input_chars as of last auto save.  */
+
+int last_auto_save;
+
+/* Last command executed by the editor command loop, not counting
+   commands that set the prefix argument.  */
+
+Lisp_Object last_command;
+
+/* The command being executed by the command loop.
+   Commands may set this, and the value set will be copied into last_command
+   instead of the actual command.  */
+Lisp_Object this_command;
+
+#ifndef HAVE_X11
+/* Window of last mouse click.  */
+extern Lisp_Object Vmouse_window;
+
+/* List containing details of last mouse click.  */
+extern Lisp_Object Vmouse_event;
+#endif /* defined HAVE_X11 */
+
+/* Hook to call on each mouse event after running its definition.  */
+Lisp_Object Vmouse_event_function;
+
+/* Hook to call when mouse leaves screen.  */
+Lisp_Object Vmouse_left_hook;
+
+/* Hook to call when a screen is mapped.  */
+Lisp_Object Vmap_screen_hook;
+
+/* Hook to call when a screen is unmapped.  */
+Lisp_Object Vunmap_screen_hook;
+
+/* Handler for non-grabbed (no keys depressed) mouse motion.  */
+Lisp_Object Vmouse_motion_handler;
+
+/* The screen in which the last input event occurred.
+   command_loop_1 will select this screen before running the
+   command bound to an event sequence, and read_key_sequence will
+   toss the existing prefix if the user starts typing at a
+   new screen.  */
+Lisp_Object Vlast_event_screen;
+
+/* X Windows wants this for selection ownership.  */
+unsigned long last_event_timestamp;
+
+Lisp_Object Qself_insert_command;
+Lisp_Object Qforward_char;
+Lisp_Object Qbackward_char;
+
+/* read_key_sequence stores here the command definition of the
+   key sequence that it reads.  */
+Lisp_Object read_key_sequence_cmd;
+
+/* Form to evaluate (if non-nil) when Emacs is started.  */
+Lisp_Object Vtop_level;
+
+/* User-supplied string to translate input characters through.  */
+Lisp_Object Vkeyboard_translate_table;
+
+/* Keymap mapping ASCII function key sequences onto their preferred forms.  */
+extern Lisp_Object Vfunction_key_map;
+
+/* File in which we write all commands we read.  */
+FILE *dribble;
+
+/* Nonzero if input is available.  */
+int input_pending;
+
+/* Nonzero if should obey 0200 bit in input chars as "Meta".  */
+int meta_key;
+
+extern char *pending_malloc_warning;
+
+/* Circular buffer for pre-read keyboard input.  */
+static struct input_event kbd_buffer[KBD_BUFFER_SIZE];
+
+/* Pointer to next available character in kbd_buffer.
+   If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty.
+   This may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the the
+   next available char is in kbd_buffer[0].  */
+static struct input_event *kbd_fetch_ptr;
+
+/* Pointer to next place to store character in kbd_buffer.  This
+   may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the next
+   character should go in kbd_buffer[0].  */
+static struct input_event *kbd_store_ptr;
+
+/* The above pair of variables forms a "queue empty" flag.  When we
+   enqueue a non-hook event, we increment kbd_write_count.  When we
+   dequeue a non-hook event, we increment kbd_read_count.  We say that
+   there is input available iff the two counters are equal.
+
+   Why not just have a flag set and cleared by the enqueuing and
+   dequeuing functions?  Such a flag could be screwed up by interrupts
+   at inopportune times.  */
+
+/* If this flag is non-zero, mouse movement events will appear in the
+   input stream.  If is zero, mouse movement will be ignored.  */
+int do_mouse_tracking;
+
+/* 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;
+
+/* True iff there is an event in kbd_buffer, or if mouse tracking is
+   enabled and there is a new mouse position in the mouse movement
+   buffer.  Note that if this is false, that doesn't mean that there
+   is readable input; all the events in the queue might be button-up
+   events, and do_mouse_tracking might be off.  */
+#define EVENT_QUEUES_EMPTY \
+  ((kbd_fetch_ptr == kbd_store_ptr) && (!do_mouse_tracking || !mouse_moved))
+
+
+/* Symbols to head events.  */
+Lisp_Object Qmouse_movement;
+
+Lisp_Object Qvscrollbar_part;
+Lisp_Object Qvslider_part;
+Lisp_Object Qvthumbup_part;
+Lisp_Object Qvthumbdown_part;
+
+Lisp_Object Qhscrollbar_part;
+Lisp_Object Qhslider_part;
+Lisp_Object Qhthumbleft_part;
+Lisp_Object Qhthumbright_part;
+
+/* Symbols to denote kinds of events.  */
+Lisp_Object Qfunction_key;
+Lisp_Object Qmouse_click;
+/* Lisp_Object Qmouse_movement; - also an event header */
+Lisp_Object Qscrollbar_click;
+
+/* Properties of event headers.  */
+Lisp_Object Qevent_kind;
+Lisp_Object Qevent_unmodified;
+
+/* Symbols to use for non-text mouse positions.  */
+Lisp_Object Qmode_line;
+Lisp_Object Qvertical_split;
+
+
+/* Address (if not 0) of word to zero out if a SIGIO interrupt happens.  */
+long *input_available_clear_word;
+
+/* Nonzero means use SIGIO interrupts; zero means use CBREAK mode.
+   Default is 1 if INTERRUPT_INPUT is defined.  */
+int interrupt_input;
+
+/* Nonzero while interrupts are temporarily deferred during redisplay.  */
+int interrupts_deferred;
+
+/* nonzero means use ^S/^Q for flow control.  */
+int flow_control;
+
+#ifndef BSD4_1
+#define sigfree() sigsetmask (SIGEMPTYMASK)
+#define sigholdx(sig) sigsetmask (sigmask (sig))
+#define sigblockx(sig) sigblock (sigmask (sig))
+#define sigunblockx(sig) sigblock (SIGEMPTYMASK)
+#define sigpausex(sig) sigpause (0)
+#endif /* not BSD4_1 */
+
+#ifdef BSD4_1
+#define SIGIO SIGTINT
+/* sigfree and sigholdx are in sysdep.c */
+#define sigblockx(sig) sighold (sig)
+#define sigunblockx(sig) sigrelse (sig)
+#define sigpausex(sig) sigpause (sig)
+#endif /* BSD4_1 */
+
+/* Allow m- file to inhibit use of FIONREAD.  */
+#ifdef BROKEN_FIONREAD
+#undef FIONREAD
+#endif
+
+/* We are unable to use interrupts if FIONREAD is not available,
+   so flush SIGIO so we won't try.  */
+#ifndef FIONREAD
+#ifdef SIGIO
+#undef SIGIO
+#endif
+#endif
+
+/* If we support X Windows, and won't get an interrupt when input
+   arrives from the server, poll periodically so we can detect C-g.  */
+#ifdef HAVE_X_WINDOWS
+#ifndef SIGIO
+#define POLL_FOR_INPUT
+#endif
+#endif
+
+/* Global variable declarations.  */
+
+/* Function for init_keyboard to call with no args (if nonzero).  */
+void (*keyboard_init_hook) ();
+
+static int read_avail_input ();
+static void get_input_pending ();
+
+/* > 0 if we are to echo keystrokes.  */
+static int echo_keystrokes;
+
+/* Nonzero means echo each character as typed.  */
+static int immediate_echo;
+
+/* The text we're echoing in the modeline - partial key sequences,
+   usually.  '\0'-terminated.  */
+static char echobuf[100];
+
+/* Where to append more text to echobuf if we want to.  */
+static char *echoptr;
+
+#define	min(a,b)	((a)<(b)?(a):(b))
+#define	max(a,b)	((a)>(b)?(a):(b))
+
+/* Install the string STR as the beginning of the string of echoing,
+   so that it serves as a prompt for the next character.
+   Also start echoing.  */
+
+echo_prompt (str)
+     char *str;
+{
+  int len = strlen (str);
+  if (len > sizeof echobuf - 4)
+    len = sizeof echobuf - 4;
+  bcopy (str, echobuf, len + 1);
+  echoptr = echobuf + len;
+
+  echo ();
+}
+
+/* Add C to the echo string, if echoing is going on.  
+   C can be a character, which is printed prettily ("M-C-x" and all that
+   jazz), or a symbol, whose name is printed.  */
+
+echo_char (c)
+     Lisp_Object c;
+{
+  extern char *push_key_description ();
+
+  if (immediate_echo)
+    {
+      char *ptr = echoptr;
+      
+      if (ptr != echobuf)
+	*ptr++ = ' ';
+
+      /* If someone has passed us a composite event, use its head symbol.  */
+      if (EVENT_HAS_PARAMETERS (c))
+	c = EVENT_HEAD (c);
+
+      if (XTYPE (c) == Lisp_Int)
+	{
+	  if (ptr - echobuf > sizeof echobuf - 6)
+	    return;
+
+	  ptr = push_key_description (c, ptr);
+	}
+      else if (XTYPE (c) == Lisp_Symbol)
+	{
+	  struct Lisp_String *name = XSYMBOL (c)->name;
+	  if (((ptr - echobuf) + name->size + 4) > sizeof echobuf)
+	    return;
+	  bcopy (name->data, ptr, name->size);
+	  ptr += name->size;
+	}
+
+      if (echoptr == echobuf && c == help_char)
+	{
+	  strcpy (ptr, " (Type ? for further options)");
+	  ptr += strlen (ptr);
+	}
+
+      *ptr = 0;
+      echoptr = ptr;
+
+      echo ();
+    }
+}
+
+/* Temporarily add a dash to the end of the echo string if it's not
+   empty, so that it serves as a mini-prompt for the very next character.  */
+
+echo_dash ()
+{
+  if (!immediate_echo && echoptr == echobuf)
+    return;
+
+  /* Put a dash at the end of the buffer temporarily,
+     but make it go away when the next character is added.  */
+  echoptr[0] = '-';
+  echoptr[1] = 0;
+
+  echo ();
+}
+
+/* Display the current echo string, and begin echoing if not already
+   doing so.  */
+
+echo ()
+{
+  if (!immediate_echo)
+    {
+      int i;
+      immediate_echo = 1;
+
+      for (i = 0; i < this_command_key_count; i++)
+	echo_char (this_command_keys[i]);
+      echo_dash ();
+    }
+
+  echoing = 1;
+  message1 (echobuf);
+  echoing = 0;
+
+  if (waiting_for_input && !NILP (Vquit_flag))
+    quit_throw_to_read_char ();
+}
+
+/* Turn off echoing, for the start of a new command.  */
+
+cancel_echoing ()
+{
+  immediate_echo = 0;
+  echoptr = echobuf;
+}
+
+/* Return the length of the current echo string.  */
+
+static int
+echo_length ()
+{
+  return echoptr - echobuf;
+}
+
+/* Truncate the current echo message to its first LEN chars.
+   This and echo_char get used by read_key_sequence when the user
+   switches screens while entering a key sequence.  */
+
+static void
+echo_truncate (len)
+     int len;
+{
+  echobuf[len] = '\0';
+  echoptr = echobuf + strlen (echobuf);
+}
+
+
+/* Functions for manipulating this_command_keys.  */
+static void
+add_command_key (key)
+     Lisp_Object key;
+{
+  if (this_command_key_count == this_command_keys_size)
+    {
+      this_command_keys_size *= 2;
+      this_command_keys
+	= (Lisp_Object *) xrealloc (this_command_keys,
+				    (this_command_keys_size
+				     * sizeof (Lisp_Object)));
+    }
+  this_command_keys[this_command_key_count++] = key;
+}
+
+Lisp_Object
+recursive_edit_1 ()
+{
+  int count = specpdl_ptr - specpdl;
+  Lisp_Object val;
+
+  if (command_loop_level > 0)
+    {
+      specbind (Qstandard_output, Qt);
+      specbind (Qstandard_input, Qt);
+    }
+
+  val = command_loop ();
+  if (EQ (val, Qt))
+    Fsignal (Qquit, Qnil);
+
+  unbind_to (count);
+  return Qnil;
+}
+
+/* When an auto-save happens, record the "time", and don't do again soon.  */
+record_auto_save ()
+{
+  last_auto_save = num_input_chars;
+}
+
+Lisp_Object recursive_edit_unwind (), command_loop ();
+
+DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "",
+  "Invoke the editor command loop recursively.\n\
+To get out of the recursive edit, a command can do `(throw 'exit nil)';\n\
+that tells this function to return.\n\
+Alternately, `(throw 'exit t)' makes this function signal an error.\n\
+This function is called by the editor initialization to begin editing.")
+  ()
+{
+  int count = specpdl_ptr - specpdl;
+  Lisp_Object val;
+
+  command_loop_level++;
+  update_mode_lines = 1;
+
+  record_unwind_protect (recursive_edit_unwind,
+			 (command_loop_level
+			  && current_buffer != XBUFFER (XWINDOW (selected_window)->buffer))
+			 ? Fcurrent_buffer ()
+			 : Qnil);
+  recursive_edit_1 ();
+  return unbind_to (count, Qnil);
+}
+
+Lisp_Object
+recursive_edit_unwind (buffer)
+     Lisp_Object buffer;
+{
+  if (!NILP (buffer))
+    Fset_buffer (buffer);
+
+  command_loop_level--;
+  update_mode_lines = 1;
+  return Qnil;
+}
+
+Lisp_Object
+cmd_error (data)
+     Lisp_Object data;
+{
+  Lisp_Object errmsg, tail, errname, file_error;
+  Lisp_Object stream;
+  struct gcpro gcpro1;
+  int i;
+
+  Vquit_flag = Qnil;
+  Vinhibit_quit = Qt;
+  Vstandard_output = Qt;
+  Vstandard_input = Qt;
+  Vexecuting_macro = Qnil;
+  echo_area_glyphs = 0;
+
+  /* If the window system or terminal screen hasn't been initialized
+     yet, or we're not interactive, it's best to dump this message out
+     to stderr and exit.  */
+  if (! SCREEN_MESSAGE_BUF (selected_screen)
+      || noninteractive)
+    stream = Qexternal_debugging_output;
+  else
+    {
+      Fdiscard_input ();
+      bitch_at_user ();
+      stream = Qt;
+    }
+
+  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 (XTYPE (errmsg) == Lisp_String)
+    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;
+
+  /* If the window system or terminal screen hasn't been initialized
+     yet, or we're in -batch mode, this error should cause Emacs to exit.  */
+  if (! SCREEN_MESSAGE_BUF (selected_screen)
+      || noninteractive)
+    {
+      Fterpri (stream);
+      Fkill_emacs (make_number (-1));
+    }
+
+  Vquit_flag = Qnil;
+
+  Vinhibit_quit = Qnil;
+  return make_number (0);
+}
+
+Lisp_Object command_loop_1 ();
+Lisp_Object command_loop_2 ();
+Lisp_Object top_level_1 ();
+
+/* Entry to editor-command-loop.
+   This level has the catches for exiting/returning to editor command loop.
+   It returns nil to exit recursive edit, t to abort it.  */
+
+Lisp_Object
+command_loop ()
+{
+  if (command_loop_level > 0 || minibuf_level > 0)
+    {
+      return internal_catch (Qexit, command_loop_2, Qnil);
+    }
+  else
+    while (1)
+      {
+	internal_catch (Qtop_level, top_level_1, Qnil);
+	internal_catch (Qtop_level, command_loop_2, Qnil);
+	
+	/* End of file in -batch run causes exit here.  */
+	if (noninteractive)
+	  Fkill_emacs (Qt);
+      }
+}
+
+/* Here we catch errors in execution of commands within the
+   editing loop, and reenter the editing loop.
+   When there is an error, cmd_error runs and returns a non-nil
+   value to us.  A value of nil means that cmd_loop_1 itself
+   returned due to end of file (or end of kbd macro).  */
+
+Lisp_Object
+command_loop_2 ()
+{
+  register Lisp_Object val;
+
+  do
+    val = internal_condition_case (command_loop_1, Qerror, cmd_error);
+  while (!NILP (val));
+
+  return Qnil;
+}
+
+Lisp_Object
+top_level_2 ()
+{
+  return Feval (Vtop_level);
+}
+
+Lisp_Object
+top_level_1 ()
+{
+  /* On entry to the outer level, run the startup file */
+  if (!NILP (Vtop_level))
+    internal_condition_case (top_level_2, Qerror, cmd_error);
+  else if (!NILP (Vpurify_flag))
+    message ("Bare impure Emacs (standard Lisp code not loaded)");
+  else
+    message ("Bare Emacs (standard Lisp code not loaded)");
+  return Qnil;
+}
+
+DEFUN ("top-level", Ftop_level, Stop_level, 0, 0, "",
+  "Exit all recursive editing levels.")
+  ()
+{
+  Fthrow (Qtop_level, Qnil);
+}
+
+DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0, "",
+  "Exit from the innermost recursive edit or minibuffer.")
+  ()
+{
+  if (command_loop_level > 0 || minibuf_level > 0)
+    Fthrow (Qexit, Qnil);
+
+  error ("No recursive edit is in progress");
+}
+
+DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, 0, "",
+  "Abort the command that requested this recursive edit or minibuffer input.")
+  ()
+{
+  if (command_loop_level > 0 || minibuf_level > 0)
+    Fthrow (Qexit, Qt);
+
+  error ("No recursive edit is in progress");
+}
+
+/* This is the actual command reading loop,
+   sans error-handling encapsulation.  */
+
+Lisp_Object Fcommand_execute ();
+static int read_key_sequence ();
+
+Lisp_Object
+command_loop_1 ()
+{
+  Lisp_Object cmd;
+  int lose;
+  int nonundocount;
+  Lisp_Object keybuf[30];
+  int i;
+  int no_redisplay;
+  int no_direct;
+
+  Vprefix_arg = Qnil;
+  waiting_for_input = 0;
+  cancel_echoing ();
+
+  /* Don't clear out last_command at the beginning of a macro.  */
+  if (XTYPE (Vexecuting_macro) != Lisp_String)
+    last_command = Qt;
+
+  nonundocount = 0;
+  no_redisplay = 0;
+  this_command_key_count = 0;
+
+  while (1)
+    {
+      /* Install chars successfully executed in kbd macro.  */
+
+      if (defining_kbd_macro && NILP (Vprefix_arg))
+	finalize_kbd_macro_chars ();
+
+      /* Make sure the current window's buffer is selected.  */
+      if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+	set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
+
+      /* Display any malloc warning that just came out.  Use while because
+	 displaying one warning can cause another.  */
+
+      while (pending_malloc_warning)
+	display_malloc_warning ();
+
+      no_direct = 0;
+
+      /* If minibuffer on and echo area in use,
+	 wait 2 sec and redraw minibufer.  */
+
+      if (minibuf_level && echo_area_glyphs)
+	{
+	  Fsit_for (make_number (2), Qnil, Qnil);
+	  echo_area_glyphs = 0;
+	  no_direct = 1;
+	  if (!NILP (Vquit_flag))
+	    {
+	      Vquit_flag = Qnil;
+	      unread_command_char = make_number (quit_char);
+	    }
+	}
+
+#ifdef C_ALLOCA
+	  alloca (0);		/* Cause a garbage collection now */
+				/* Since we can free the most stuff here.  */
+#endif /* C_ALLOCA */
+
+      /* Read next key sequence; i gets its length.  */
+      i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])), 0);
+
+      ++num_input_keys;
+
+#ifdef MULTI_SCREEN
+      /* Select the screen that the key sequence came from.  */
+      if (XTYPE (Vlast_event_screen) == Lisp_Screen
+	  && XSCREEN (Vlast_event_screen) != selected_screen)
+	Fselect_screen (Vlast_event_screen, Qnil);
+#endif
+
+      /* Now we have read a key sequence of length I,
+	 or else I is 0 and we found end of file.  */
+
+      if (i == 0)		/* End of file -- happens only in */
+	return Qnil;		/* a kbd macro, at the end.  */
+
+#if 0
+#ifdef HAVE_X_WINDOWS
+      if (SCREEN_IS_X (selected_screen))
+	{
+	  if (i == -1)		/* Mouse event */
+	    {
+	      nonundocount = 0;
+	      if (NILP (Vprefix_arg) && NILP (Vexecuting_macro) &&
+		  !EQ (minibuf_window, selected_window))
+		Fundo_boundary ();
+
+	      if (defining_kbd_macro)
+		{
+		  /* Be nice if this worked...  */
+		}
+	      Fexecute_mouse_event (read_key_sequence_cmd);
+	      no_redisplay = 0;
+	      goto directly_done;
+	    }
+
+	  if (i == -2)		/* Lisp Symbol */
+	    {
+	      nonundocount = 0;
+	      if (NILP (Vprefix_arg) && NILP (Vexecuting_macro) &&
+		  !EQ (minibuf_window, selected_window))
+		Fundo_boundary ();
+ 
+	      goto directly_done;
+	    }
+	}
+#endif /* HAVE_X_WINDOWS */
+#endif
+
+      last_command_char = keybuf[i - 1];
+
+      cmd = read_key_sequence_cmd;
+      if (!NILP (Vexecuting_macro))
+	{
+	  if (!NILP (Vquit_flag))
+	    {
+	      Vexecuting_macro = Qt;
+	      QUIT;		/* Make some noise. */
+				/* Will return since macro now empty. */
+	    }
+	}
+
+      /* Do redisplay processing after this command except in special
+	 cases identified below that set no_redisplay to 1.  */
+      no_redisplay = 0;
+
+      /* Execute the command.  */
+
+      if (NILP (cmd))
+	{
+	  /* nil means key is undefined.  */
+	  bitch_at_user ();
+	  defining_kbd_macro = 0;
+	  update_mode_lines = 1;
+	  Vprefix_arg = Qnil;
+	}
+      else
+	{
+	  this_command = cmd;
+	  if (NILP (Vprefix_arg) && ! no_direct)
+	    {
+	      /* Recognize some common commands in common situations and
+		 do them directly.  */
+	      if (EQ (cmd, Qforward_char) && point < ZV)
+		{
+                  struct Lisp_Vector *dp
+		    = window_display_table (XWINDOW (selected_window));
+		  lose = FETCH_CHAR (point);
+		  SET_PT (point + 1);
+		  if (((dp == 0 && lose >= 040 && lose < 0177)
+		       ||
+		       (dp && (XTYPE (dp->contents[lose]) != Lisp_String
+			       || XSTRING (dp->contents[lose])->size == sizeof (GLYPH))))
+		      && (SCREEN_CURSOR_X (selected_screen)
+			  != SCREEN_WIDTH (selected_screen) - 1)
+		      && (XFASTINT (XWINDOW (selected_window)->last_modified)
+			  >= MODIFF)
+		      && (XFASTINT (XWINDOW (selected_window)->last_point)
+			  == point - 1)
+		      && !windows_or_buffers_changed
+		      && EQ (current_buffer->selective_display, Qnil)
+		      && !detect_input_pending ()
+		      && NILP (Vexecuting_macro))
+		    no_redisplay = direct_output_forward_char (1);
+		  goto directly_done;
+		}
+	      else if (EQ (cmd, Qbackward_char) && point > BEGV)
+		{
+                  struct Lisp_Vector *dp
+		    = window_display_table (XWINDOW (selected_window));
+		  SET_PT (point - 1);
+		  lose = FETCH_CHAR (point);
+		  if (((dp == 0 && lose >= 040 && lose < 0177)
+		       ||
+		       (dp && (XTYPE (dp->contents[lose]) != Lisp_String
+			       || XSTRING (dp->contents[lose])->size == sizeof (GLYPH))))
+		      && (SCREEN_CURSOR_X (selected_screen) != 0)
+		      && (XFASTINT (XWINDOW (selected_window)->last_modified)
+			  >= MODIFF)
+		      && (XFASTINT (XWINDOW (selected_window)->last_point)
+			  == point + 1)
+		      && !windows_or_buffers_changed
+		      && EQ (current_buffer->selective_display, Qnil)
+		      && !detect_input_pending ()
+		      && NILP (Vexecuting_macro))
+		    no_redisplay = direct_output_forward_char (-1);
+		  goto directly_done;
+		}
+	      else if (EQ (cmd, Qself_insert_command)
+		       /* Try this optimization only on ascii keystrokes.  */
+		       && XTYPE (last_command_char) == Lisp_Int)
+		{
+		  unsigned char c = XINT (last_command_char);
+
+		  if (NILP (Vexecuting_macro) &&
+		      !EQ (minibuf_window, selected_window))
+		    {
+		      if (!nonundocount || nonundocount >= 20)
+			{
+			  Fundo_boundary ();
+			  nonundocount = 0;
+			}
+		      nonundocount++;
+		    }
+		  lose = (XFASTINT (XWINDOW (selected_window)->last_modified)
+			  < MODIFF)
+		    || (XFASTINT (XWINDOW (selected_window)->last_point)
+			  != point)
+		    || MODIFF <= current_buffer->save_modified
+		    || windows_or_buffers_changed
+		    || !EQ (current_buffer->selective_display, Qnil)
+		    || detect_input_pending ()
+		    || !NILP (Vexecuting_macro);
+		  if (internal_self_insert (c, 0))
+		    {
+		      lose = 1;
+		      nonundocount = 0;
+		    }
+		  if (!lose &&
+		      (point == ZV || FETCH_CHAR (point) == '\n'))
+		    {
+		      struct Lisp_Vector *dp
+			= window_display_table (XWINDOW (selected_window));
+
+		      if (dp == 0 || XTYPE (dp->contents[c]) != Lisp_String)
+			no_redisplay = direct_output_for_insert (c);
+		      else if (XSTRING (dp->contents[c])->size
+			       == sizeof (GLYPH))
+		        no_redisplay =
+			  direct_output_for_insert (*(GLYPH *)XSTRING (dp->contents[c])->data);
+		    }
+		  goto directly_done;
+		}
+	    }
+
+	  /* Here for a command that isn't executed directly */
+
+	  nonundocount = 0;
+	  if (NILP (Vprefix_arg))
+	    Fundo_boundary ();
+	  Fcommand_execute (cmd, Qnil);
+
+	directly_done: ;
+	}
+
+      /* If there is a prefix argument,
+	 1) We don't want last_command to be ``universal-argument''
+	 (that would be dumb), so don't set last_command,
+	 2) we want to leave echoing on so that the prefix will be
+	 echoed as part of this key sequence, so don't call
+	 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 (Vprefix_arg))
+	{
+	  last_command = this_command;
+	  cancel_echoing ();
+	  this_command_key_count = 0;
+	}
+    }
+}
+
+/* Number of seconds between polling for input.  */
+int polling_period;
+
+/* Nonzero means polling for input is temporarily suppresed.  */
+int poll_suppress_count;
+
+#ifdef POLL_FOR_INPUT
+int polling_for_input;
+
+/* Handle an alarm once each second and read pending input
+   so as to handle a C-g if it comces in.  */
+
+SIGTYPE
+input_poll_signal ()
+{
+#ifdef HAVE_X_WINDOWS
+  extern int x_input_blocked;
+  if (x_input_blocked == 0)
+#endif
+    if (!waiting_for_input)
+      read_avail_input (0);
+  signal (SIGALRM, input_poll_signal);
+  alarm (polling_period);
+}
+
+#endif
+
+/* Begin signals to poll for input, if they are appropriate.
+   This function is called unconditionally from various places.  */
+
+start_polling ()
+{
+#ifdef POLL_FOR_INPUT
+  if (read_socket_hook)
+    {
+      poll_suppress_count--;
+      if (poll_suppress_count == 0)
+	{
+	  signal (SIGALRM, input_poll_signal);
+	  polling_for_input = 1;
+	  alarm (polling_period);
+	}
+    }
+#endif
+}
+
+/* Turn off polling.  */
+
+stop_polling ()
+{
+#ifdef POLL_FOR_INPUT
+  if (read_socket_hook)
+    {
+      if (poll_suppress_count == 0)
+	{
+	  polling_for_input = 0;
+	  alarm (0);
+	}
+      poll_suppress_count++;
+    }
+#endif
+}
+
+/* Input of single characters from keyboard */
+
+Lisp_Object print_help ();
+static Lisp_Object kbd_buffer_get_event ();
+
+/* read a character from the keyboard; call the redisplay if needed */
+/* commandflag 0 means do not do auto-saving, but do do redisplay.
+   -1 means do not do redisplay, but do do autosaving.
+   1 means do both.  */
+
+Lisp_Object
+read_char (commandflag)
+     int commandflag;
+{
+  register Lisp_Object c;
+  int count;
+  jmp_buf save_jump;
+
+  if (!NILP (unread_command_char))
+    {
+      c = unread_command_char;
+      unread_command_char = Qnil;
+
+#if 0       /* We're not handling mouse keys specially anymore. */
+      if (!EQ (XTYPE (obj), Lisp_Int)) /* Mouse thing */
+	{
+	  num_input_chars++;
+	  last_input_char = 0;
+	  return obj;
+	}
+#endif
+
+      if (this_command_key_count == 0)
+	goto reread_first;
+      else
+	goto reread;
+    }
+
+  if (!NILP (Vexecuting_macro))
+    {
+      if (executing_macro_index >= Flength (Vexecuting_macro))
+	{
+	  XSET (c, Lisp_Int, -1);
+	  return c;
+	}
+      
+      c = Faref (Vexecuting_macro, make_number (executing_macro_index));
+      executing_macro_index++;
+
+      goto from_macro;
+    }
+
+  /* Save outer setjmp data, in case called recursively.  */
+  bcopy (getcjmp, save_jump, sizeof getcjmp);
+
+  stop_polling ();
+
+  if (commandflag >= 0 && !input_pending && !detect_input_pending ())
+    redisplay ();
+
+  if (_setjmp (getcjmp))
+    {
+      XSET (c, Lisp_Int, quit_char);
+
+      /* Returning quit_char from this function represents a
+	 resolution to the quit request, so clear the quit flag.
+	 This prevents us from returning quit_char many times
+	 for the same quit request.  */
+      Vquit_flag = Qnil;
+
+      waiting_for_input = 0;
+      input_available_clear_word = 0;
+
+      goto non_reread;
+    }
+
+  /* Message turns off echoing unless more keystrokes turn it on again. */
+  if (echo_area_glyphs && *echo_area_glyphs && echo_area_glyphs != echobuf)
+    cancel_echoing ();
+  else
+    /* If already echoing, continue.  */
+    echo_dash ();
+
+  /* If in middle of key sequence and minibuffer not active,
+     start echoing if enough time elapses.  */
+  if (minibuf_level == 0 && !immediate_echo && this_command_key_count > 0
+      && echo_keystrokes > 0
+      && (echo_area_glyphs == 0 || *echo_area_glyphs == 0))
+    {
+      Lisp_Object tem0;
+
+      tem0 = Fsit_for (make_number (echo_keystrokes), Qnil, Qt);
+      if (EQ (tem0, Qt))
+	echo ();
+    }
+
+  /* Maybe auto save due to number of keystrokes or idle time.  */
+
+  if (commandflag != 0
+      && auto_save_interval > 0
+      && num_input_chars - last_auto_save > max (auto_save_interval, 20)
+      && !detect_input_pending ())
+    {
+      jmp_buf temp;
+      save_getcjmp (temp);
+      Fdo_auto_save (Qnil, Qnil);
+      restore_getcjmp (temp);
+    }
+
+  /* Slow down auto saves logarithmically in size of current buffer,
+     and garbage collect while we're at it.  */
+  {
+    int delay_level, buffer_size;
+
+    if (! MINI_WINDOW_P (XWINDOW (selected_window)))
+      last_non_minibuf_size = Z - BEG;
+    buffer_size = (last_non_minibuf_size >> 8) + 1;
+    delay_level = 0;
+    while (buffer_size > 64)
+      delay_level++, buffer_size -= buffer_size >> 2;
+    if (delay_level < 4) delay_level = 4;
+    /* delay_level is 4 for files under around 50k, 7 at 100k,
+       9 at 200k, 11 at 300k, and 12 at 500k.  It is 15 at 1 meg.  */
+
+    /* Auto save if enough time goes by without input.  */
+    if (commandflag != 0
+	&& num_input_chars > last_auto_save
+	&& XTYPE (Vauto_save_timeout) == Lisp_Int
+	&& XINT (Vauto_save_timeout) > 0)
+      {
+	Lisp_Object tem0;
+	int delay = delay_level * XFASTINT (Vauto_save_timeout) / 4;
+	tem0 = Fsit_for (make_number (delay), Qnil, Qt);
+	if (EQ (tem0, Qt))
+	  {
+	    jmp_buf temp;
+	    save_getcjmp (temp);
+	    Fdo_auto_save (Qnil, Qnil);
+	    restore_getcjmp (temp);
+
+	    /* If we have auto-saved and there is still no input
+	       available, garbage collect if there has been enough
+	       consing going on to make it worthwhile.  */
+	    if (!detect_input_pending ()
+		&& consing_since_gc > gc_cons_threshold / 2)
+	      Fgarbage_collect ();
+	  }
+      }
+  }
+
+  /* Actually read a character, waiting if necessary.  */
+  c = kbd_buffer_get_event ();
+
+  if (NILP (c))
+    abort ();			/* Don't think this can happen. */
+
+#if 0 /* I think that all the different kinds of events should be
+	 handled together now... */
+  if (XTYPE (c) != Lisp_Int)
+    {
+      start_polling ();
+      return c;
+    }
+  c = XINT (obj);
+#endif
+
+  /* Terminate Emacs in batch mode if at eof.  */
+  if (noninteractive && c < 0)
+    Fkill_emacs (make_number (1));
+
+ non_reread:
+
+  bcopy (save_jump, getcjmp, sizeof getcjmp);
+
+  start_polling ();
+
+  echo_area_glyphs = 0;
+
+  /* Handle things that only apply to characters.  */
+  if (XTYPE (c) == Lisp_Int)
+    {
+      /* If kbd_buffer_get_event gave us an EOF, return that.  */
+      if (XINT (c) < 0)
+	return c;
+
+      /* Strip the high bits, and maybe the meta bit too.  */
+      XSETINT (c, c & (meta_key ? 0377 : 0177));
+
+      if (XTYPE (Vkeyboard_translate_table) == Lisp_String
+	  && XSTRING (Vkeyboard_translate_table)->size > XINT (c))
+	XSETINT (c, XSTRING (Vkeyboard_translate_table)->data[c]);
+    }
+
+  total_keys++;
+  recent_keys[recent_keys_index] = c;
+  if (++recent_keys_index >= (sizeof (recent_keys)/sizeof(recent_keys[0])))
+    recent_keys_index = 0;
+
+  /* Write c to the dribble file.  If c is a lispy event, write
+     the event's symbol to the dribble file, in <brackets>.  Bleaugh.
+     If you, dear reader, have a better idea, you've got the source.  :-) */
+  if (dribble)
+    {
+      if (XTYPE (c) == Lisp_Int)
+	putc (c, dribble);
+      else
+	{
+	  Lisp_Object dribblee = c;
+
+	  /* If it's a structured event, take the event header.  */
+	  if (EVENT_HAS_PARAMETERS (dribblee))
+	    dribblee = EVENT_HEAD (dribblee);
+
+	  if (XTYPE (c) == Lisp_Symbol)
+	    {
+	      putc ('<', dribble);
+	      fwrite (XSYMBOL (c)->name->data, sizeof (char),
+		      XSYMBOL (c)->name->size,
+		      dribble);
+	      putc ('>', dribble);
+	    }
+	}
+
+      fflush (dribble);
+    }
+
+  store_kbd_macro_char (c);
+
+ from_macro:
+ reread_first:
+  echo_char (c);
+
+  /* Record this character as part of the current key.  */
+  add_command_key (c);
+
+  /* Re-reading in the middle of a command */
+ reread:
+  last_input_char = c;
+  num_input_chars++;
+
+  /* Process the help character specially if enabled */
+  if (EQ (c, help_char) && !NILP (Vhelp_form))
+    {
+      Lisp_Object tem0;
+      count = specpdl_ptr - specpdl;
+
+      record_unwind_protect (Fset_window_configuration,
+			     Fcurrent_window_configuration (Qnil));
+
+      tem0 = Feval (Vhelp_form);
+      if (XTYPE (tem0) == Lisp_String)
+	internal_with_output_to_temp_buffer ("*Help*", print_help, tem0);
+
+      cancel_echoing ();
+      c = read_char (0);
+      /* Remove the help from the screen */
+      unbind_to (count, Qnil);
+      redisplay ();
+      if (EQ (c, make_number (040)))
+	{
+	  cancel_echoing ();
+	  c = read_char (0);
+	}
+    }
+
+  return c;
+}
+
+Lisp_Object
+print_help (object)
+     Lisp_Object object;
+{
+  Fprinc (object, Qnil);
+  return Qnil;
+}
+
+/* Copy out or in the info on where C-g should throw to.
+   This is used when running Lisp code from within get_char,
+   in case get_char is called recursively.
+   See read_process_output.  */
+
+save_getcjmp (temp)
+     jmp_buf temp;
+{
+  bcopy (getcjmp, temp, sizeof getcjmp);
+}
+
+restore_getcjmp (temp)
+     jmp_buf temp;
+{
+  bcopy (temp, getcjmp, sizeof getcjmp);
+}
+
+
+/* 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.  */
+
+/* Set this for debugging, to have a way to get out */
+int stop_character;
+
+extern int screen_garbaged;
+
+/* 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 ()
+{
+  struct input_event *ep;
+
+  if (EVENT_QUEUES_EMPTY)
+    return 0;
+
+  if (do_mouse_tracking)
+    return 1;
+
+  /* Mouse tracking is disabled, so we need to actually scan the
+     input queue to see if any events are currently readable.  */
+  for (ep = kbd_fetch_ptr; ep != kbd_store_ptr; ep++)
+    {
+      if (ep == kbd_buffer + KBD_BUFFER_SIZE)
+	ep = kbd_buffer;
+	
+      /* Skip button-up events.  */
+      if ((ep->kind == mouse_click || ep->kind == scrollbar_click)
+	  && (ep->modifiers & up_modifier))
+	continue;
+
+      return 1;
+    }
+    
+  return 0;
+}
+
+
+/* Restore mouse tracking enablement.  See Ftrack_mouse for the only use
+   of this function.  */
+static Lisp_Object
+tracking_off (old_value)
+     Lisp_Object old_value;
+{
+  if (! XFASTINT (old_value))
+    {
+      do_mouse_tracking = 0;
+
+      /* Redisplay may have been preempted because there was input
+	 available, and it assumes it will be called again after the
+	 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 ())
+	{
+	  redisplay_preserve_echo_area ();
+	  get_input_pending (&input_pending);
+	}
+    }
+}
+
+DEFUN ("track-mouse", Ftrack_mouse, Strack_mouse, 0, UNEVALLED, 0,
+  "Evaluate BODY with mouse movement and button release events enabled.\n\
+Within a track-mouse, read-event reports mouse movement and button releases;\n\
+otherwise, they are ignored.")
+  (args)
+     Lisp_Object args;
+{
+  int count = specpdl_ptr - specpdl;
+  Lisp_Object val;
+
+  XSET (val, Lisp_Int, do_mouse_tracking);
+  record_unwind_protect (tracking_off, val);
+
+  do_mouse_tracking = 1;
+  
+  val = Fprogn (args);
+  return unbind_to (count, val);
+}
+
+/* Store an event obtained at interrupt level into kbd_buffer, fifo */
+
+void
+kbd_buffer_store_event (event)
+     register struct input_event *event;
+{
+  if (event->kind == no_event)
+    abort ();
+
+  if (event->kind == ascii_keystroke)
+    {
+      register int c = XFASTINT (event->code) & 0377;
+
+      if (c == quit_char
+	  || ((c == (0200 | quit_char)) && !meta_key))
+	{
+	  /* If this results in a quit_char being returned to Emacs as
+	     input, set last-event-screen properly.  If this doesn't
+	     get returned to Emacs as an event, the next event read
+	     will set Vlast_event_screen again, so this is safe to do.  */
+	  extern SIGTYPE interrupt_signal ();
+	  XSET (Vlast_event_screen, Lisp_Screen, event->screen);
+	  last_event_timestamp = XINT (event->timestamp);
+	  interrupt_signal ();
+	  return;
+	}
+
+      if (c && c == stop_character)
+	{
+	  sys_suspend ();
+	  return;
+	}
+
+      XSET (event->code, Lisp_Int, c);
+    }
+
+  if (kbd_store_ptr - kbd_buffer == KBD_BUFFER_SIZE)
+    kbd_store_ptr = kbd_buffer;
+
+  /* Don't let the very last slot in the buffer become full,
+     since that would make the two pointers equal,
+     and that is indistinguishable from an empty buffer.
+     Discard the event if it would fill the last slot.  */
+  if (kbd_fetch_ptr - 1 != kbd_store_ptr)
+    {
+      kbd_store_ptr->kind = event->kind;
+      kbd_store_ptr->code = event->code;
+      kbd_store_ptr->part = event->part;
+      kbd_store_ptr->screen = event->screen;
+      kbd_store_ptr->modifiers = event->modifiers;
+      kbd_store_ptr->x = event->x;
+      kbd_store_ptr->y = event->y;
+      kbd_store_ptr->timestamp = event->timestamp;
+
+      kbd_store_ptr++;
+    }
+}
+
+static Lisp_Object make_lispy_event ();
+static Lisp_Object make_lispy_movement ();
+static Lisp_Object modify_event_symbol ();
+
+static Lisp_Object
+kbd_buffer_get_event ()
+{
+  register int c;
+  Lisp_Object obj;
+
+  if (noninteractive)
+    {
+      c = getchar ();
+      XSET (obj, Lisp_Int, c);
+      return obj;
+    }
+
+  /* Wait until there is input available.  */
+  for (;;)
+    {
+
+      /* Process or toss any events that we don't want to return as
+	 input.  The fact that we remove undesirable events here
+	 allows us to use EVENT_QUEUES_EMPTY in the rest of this loop.  */
+      if (! do_mouse_tracking)
+	while (kbd_fetch_ptr != kbd_store_ptr)
+	  {
+	    if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
+	      kbd_fetch_ptr = kbd_buffer;
+
+	    if (kbd_fetch_ptr->kind == mouse_click
+		|| kbd_fetch_ptr->kind == scrollbar_click)
+	      {
+		if ((kbd_fetch_ptr->modifiers & up_modifier) == 0)
+		  break;
+	      }
+	    else
+	      break;
+
+	    kbd_fetch_ptr++;
+	  }
+
+      if (!EVENT_QUEUES_EMPTY)
+	break;
+
+      /* If the quit flag is set, then read_char will return
+	 quit_char, so that counts as "available input."  */
+      if (!NILP (Vquit_flag))
+	quit_throw_to_read_char ();
+
+      /* One way or another, wait until input is available; then, if
+	 interrupt handlers have not read it, read it now.  */
+
+#ifdef OLDVMS
+      wait_for_kbd_input ();
+#else
+/* Note SIGIO has been undef'd if FIONREAD is missing.  */
+#ifdef SIGIO
+      gobble_input (0);
+#endif /* SIGIO */
+      if (EVENT_QUEUES_EMPTY)
+	{
+#ifdef subprocesses
+	  wait_reading_process_input (0, 0, -1, 1);
+#else
+/* Note SIGIO has been undef'd if FIONREAD is missing.  */
+#ifdef SIGIO
+	  if (interrupt_input)
+	    {
+	      sigblockx (SIGIO);
+	      set_waiting_for_input (0);
+	      while (EVENT_QUEUES_EMPTY)
+		sigpausex (SIGIO);
+	      clear_waiting_for_input ();
+	      sigunblockx (SIGIO);
+	    }
+#else
+	  interrupt_input = 0;
+#endif /* not SIGIO */
+#endif /* subprocesses */
+
+	  if (!interrupt_input && EVENT_QUEUES_EMPTY)
+	    {
+	      read_avail_input (0);
+	    }
+	}
+#endif /* not VMS */
+    }
+
+  /* At this point, we know that there is a readable event available
+     somewhere.  If the event queue is empty, then there must be a
+     mouse movement enabled and available.  */
+  if (kbd_fetch_ptr != kbd_store_ptr)
+    {
+      if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
+	kbd_fetch_ptr = kbd_buffer;
+      XSET (Vlast_event_screen, Lisp_Screen, kbd_fetch_ptr->screen);
+      last_event_timestamp = XINT (kbd_fetch_ptr->timestamp);
+      obj = make_lispy_event (kbd_fetch_ptr);
+      kbd_fetch_ptr->kind = no_event;
+      kbd_fetch_ptr++;
+      if (XTYPE (obj) == Lisp_Int)
+	XSET (obj, Lisp_Int, XINT (obj) & (meta_key ? 0377 : 0177));
+    }
+  else if (do_mouse_tracking && mouse_moved)
+    {
+      SCREEN_PTR screen;
+      Lisp_Object x, y, time;
+
+      (*mouse_position_hook) (&screen, &x, &y, &time);
+      XSET (Vlast_event_screen, Lisp_Screen, screen);
+
+      obj = make_lispy_movement (screen, x, y, time);
+    }
+  else
+    /* We were promised by the above while loop that there was
+       something for us to read!  */
+    abort ();
+
+  input_pending = readable_events ();
+
+  return (obj);
+}
+
+/* Caches for modify_event_symbol.  */
+static Lisp_Object func_key_syms;
+static Lisp_Object mouse_syms;
+
+/* You'll notice that this table is arranged to be conveniently
+   indexed by X Windows keysym values.  */
+static char *lispy_function_keys[] =
+  {
+    /* X Keysym value */
+
+    "home",			/* 0xff50 */	/* IsCursorKey */
+    "left",
+    "up",
+    "right",
+    "down",
+    "prior",
+    "next",
+    "end",
+    "begin",
+    0,				/* 0xff59 */
+    0, 0, 0, 0, 0, 0,
+    "select",			/* 0xff60 */	/* IsMiscFunctionKey */
+    "print",
+    "execute",
+    "insert",
+    0,		/* 0xff64 */
+    "undo",
+    "redo",
+    "menu",
+    "find",
+    "cancel",
+    "help",
+    "break",			/* 0xff6b */
+
+    /* Here are some keys found mostly on HP keyboards.  The X event
+       handling code will strip bit 29, which flags vendor-specific
+       keysyms.  */
+    "reset",			/* 0x1000ff6c */
+    "system",
+    "user",
+    "clearline",
+    "insertline",
+    "deleteline",
+    "insertchar",
+    "deletechar",
+    "backtab",
+    "kp_backtab",		/* 0x1000ff75 */
+    0,				/* 0xff76 */
+    0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 0xff7f */
+    "kp-space",			/* 0xff80 */	/* IsKeypadKey */
+    0, 0, 0, 0, 0, 0, 0, 0,
+    "kp-tab",			/* 0xff89 */
+    0, 0, 0,
+    "kp-enter",			/* 0xff8d */
+    0, 0, 0,
+    "kp-f1",			/* 0xff91 */
+    "kp-f2",
+    "kp-f3",
+    "kp-f4",
+    0,		/* 0xff95 */
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    "kp-multiply",		/* 0xffaa */
+    "kp-add",
+    "kp-separator",
+    "kp-subtract",
+    "kp-decimal",
+    "kp-divide",		/* 0xffaf */
+    "kp-0",			/* 0xffb0 */
+    "kp-1",	"kp-2",	"kp-3",	"kp-4",	"kp-5",	"kp-6",	"kp-7",	"kp-8",	"kp-9",
+    0,		/* 0xffba */
+    0, 0,
+    "kp-equal",			/* 0xffbd */
+    "f1",			/* 0xffbe */	/* IsFunctionKey */
+    "f2",	"f3",	"f4",
+    "f5",	"f6",	"f7",	"f8",	"f9",	"f10",	"f11",	"f12",
+    "f13",	"f14",	"f15",	"f16",	"f17",	"f18",	"f19",	"f20",
+    "f21",	"f22",	"f23",	"f24",	"f25",	"f26",	"f27",	"f28",
+    "f29",	"f30",	"f31",	"f32",	"f33",	"f34",	"f35"	/* 0xffe0 */
+    };
+
+static char *lispy_mouse_names[] = 
+{
+  "mouse-1", "mouse-2", "mouse-3", "mouse-4", "mouse-5"
+};
+
+/* Given a struct input_event, build the lisp event which represents
+   it.  If EVENT is 0, build a mouse movement event from the mouse
+   movement buffer, which should have a movement event in it.  */
+
+static Lisp_Object
+make_lispy_event (event)
+     struct input_event *event;
+{
+#ifdef SWITCH_ENUM_BUG
+  switch ((int) event->kind)
+#else
+  switch (event->kind)
+#endif
+    {
+
+      /* A simple keystroke.  */
+    case ascii_keystroke:
+      return event->code;
+      break;
+
+      /* A function key.  The symbol may need to have modifier prefixes
+	 tacked onto it.  */
+    case non_ascii_keystroke:
+      return modify_event_symbol (XFASTINT (event->code), event->modifiers,
+				  Qfunction_key,
+				  lispy_function_keys, &func_key_syms,
+				  (sizeof (lispy_function_keys)
+				   / sizeof (lispy_function_keys[0])));
+      break;
+
+      /* A mouse click - build a list of the relevant information.  */
+    case mouse_click:
+      {
+	int part;
+	Lisp_Object window =
+	  window_from_coordinates (event->screen,
+				   XINT (event->x), XINT (event->y),
+				   &part);
+	Lisp_Object posn;
+
+	if (XTYPE (window) != Lisp_Window)
+	  posn = Qnil;
+	else
+	  {
+	    XSETINT (event->x, (XINT (event->x)
+				- XINT (XWINDOW (window)->left)));
+	    XSETINT (event->y, (XINT (event->y)
+				- XINT (XWINDOW (window)->top)));
+
+	    if (part == 1)
+	      posn = Qmode_line;
+	    else if (part == 2)
+	      posn = Qvertical_split;
+	    else
+	      XSET (posn, Lisp_Int,
+		    buffer_posn_from_coords (XWINDOW (window),
+					     XINT (event->x),
+					     XINT (event->y)));
+	  }
+
+	return Fcons (modify_event_symbol (XFASTINT (event->code) - 1,
+					   event->modifiers,
+					   Qmouse_click,
+					   lispy_mouse_names, &mouse_syms,
+					   (sizeof (lispy_mouse_names)
+					    / sizeof (lispy_mouse_names[0]))),
+		      Fcons (window,
+			     Fcons (posn,
+				    Fcons (Fcons (event->x, event->y),
+					   Fcons (event->timestamp,
+						  Qnil)))));
+      }
+
+      /* A scrollbar click.  Build a list containing the relevant
+	 information.  */
+    case scrollbar_click:
+      {
+	Lisp_Object button
+	  = modify_event_symbol (XFASTINT (event->code) - 1,
+				 event->modifiers,
+				 Qmouse_click,
+				 lispy_mouse_names, &mouse_syms,
+				 (sizeof (lispy_mouse_names)
+				  / sizeof (lispy_mouse_names[0])));
+	return Fcons (event->part,
+		      Fcons (SCREEN_SELECTED_WINDOW (event->screen),
+			     Fcons (button,
+				    Fcons (Fcons (event->x, event->y),
+					   Fcons (event->timestamp,
+						  Qnil)))));
+      }
+
+      /* The 'kind' field of the event is something we don't recognize.  */
+    default:
+      abort();
+    }
+}
+
+static Lisp_Object
+make_lispy_movement (screen, x, y, time)
+     SCREEN_PTR screen;
+     Lisp_Object x, y;
+     Lisp_Object time;
+{
+  Lisp_Object window;
+  int ix, iy;
+  Lisp_Object posn;
+  int part;
+
+  ix = XINT (x);
+  iy = XINT (y);
+  window = (screen
+	    ? window_from_coordinates (screen, ix, iy, &part)
+	    : Qnil);
+  if (XTYPE (window) != Lisp_Window)
+    posn = Qnil;
+  else
+    {
+      ix -= XINT (XWINDOW (window)->left);
+      iy -= XINT (XWINDOW (window)->top);
+      if (part == 1)
+	posn = Qmode_line;
+      else if (part == 2)
+	posn = Qvertical_split;
+      else
+	XSET (posn, Lisp_Int, buffer_posn_from_coords (XWINDOW (window),
+						       ix, iy));
+    }
+
+  XSETINT (x, ix);
+  XSETINT (y, iy);
+  return Fcons (Qmouse_movement,
+		Fcons (window,
+		       Fcons (posn,
+			      Fcons (Fcons (x, y),
+				     Fcons (time, Qnil)))));
+}
+
+
+
+/* Place the written representation of MODIFIERS in BUF, '\0'-terminated,
+   and return its length.  */
+
+static int
+format_modifiers (modifiers, buf)
+     int modifiers;
+     char *buf;
+{
+  char *p = buf;
+
+  if (modifiers & meta_modifier) { *p++ = 'M'; *p++ = '-'; }
+  if (modifiers & ctrl_modifier) { *p++ = 'C'; *p++ = '-'; }
+  if (modifiers & shift_modifier) { *p++ = 'S'; *p++ = '-'; }
+  if (modifiers & up_modifier) { *p++ = 'U'; *p++ = '-'; }
+  *p = '\0';
+
+  return p - buf;
+}
+
+
+/* Given a symbol whose name begins with modifiers ("C-", "M-", etc),
+   return a symbol with the modifiers placed in the canonical order.
+
+   Fdefine_key calls this to make sure that (for example) C-M-foo
+   and M-C-foo end up being equivalent in the keymap.  */
+
+Lisp_Object
+reorder_modifiers (symbol)
+     Lisp_Object symbol;
+{
+  struct Lisp_String *name;
+  int i;
+  int modifiers;
+  int not_canonical;
+
+  CHECK_SYMBOL (symbol, 1);
+  
+  modifiers = 0;
+  name = XSYMBOL (symbol)->name;
+
+  /* Special case for things with only one modifier, which is
+     (hopefully) the vast majority of cases.  */
+  if (! (name->size >= 4 && name->data[1] == '-' && name->data[3] == '-'))
+    return symbol;
+
+  for (i = 0; i + 1 < name->size && name->data[i + 1] == '-'; i += 2)
+    switch (name->data[i])
+      {
+      case 'M':
+	not_canonical |= (modifiers & (meta_modifier|ctrl_modifier
+				      |shift_modifier|up_modifier));
+	modifiers |= meta_modifier;
+	break;
+
+      case 'C':
+	not_canonical |= (modifiers &
+			 (ctrl_modifier|shift_modifier|up_modifier));
+	modifiers |= ctrl_modifier;
+	break;
+
+      case 'S':
+	not_canonical |= (modifiers & (shift_modifier|up_modifier));
+	modifiers |= shift_modifier;
+	break;
+
+      case 'U':
+	not_canonical |= (modifiers & (up_modifier));
+	modifiers |= up_modifier;
+	break;
+
+      default:
+	goto no_more_modifiers;
+      }
+ no_more_modifiers:
+
+  if (!not_canonical)
+    return symbol;
+
+  /* The modifiers were out of order, so find a new symbol with the
+     mods in order.  Since the symbol name could contain nulls, we can't
+     use intern here; we have to use Fintern, which expects a genuine
+     Lisp_String, and keeps a reference to it.  */
+  {
+    char *new_mods = (char *) alloca (sizeof ("C-M-S-U-"));
+    int len = format_modifiers (modifiers, new_mods);
+    Lisp_Object new_name = make_uninit_string (len + name->size - i);
+
+    bcopy (new_mods, XSTRING (new_name)->data, len);
+    bcopy (name->data + i, XSTRING (new_name)->data + len, name->size - i);
+
+    return Fintern (new_name, Qnil);
+  }
+}
+
+
+/* For handling events, we often want to produce a symbol whose name
+   is a series of modifier key prefixes ("M-", "C-", etcetera) attached
+   to some base, like the name of a function key or mouse button.
+   modify_event_symbol produces symbols of this sort.
+
+   NAME_TABLE should point to an array of strings, such that NAME_TABLE[i]
+   is the name of the i'th symbol.  TABLE_SIZE is the number of elements
+   in the table.
+
+   SYMBOL_TABLE should be a pointer to a Lisp_Object whose value will
+   persist between calls to modify_event_symbol that it can use to
+   store a cache of the symbols it's generated for this NAME_TABLE
+   before.
+
+   SYMBOL_NUM is the number of the base name we want from NAME_TABLE.
+   
+   MODIFIERS is a set of modifier bits (as given in struct input_events)
+   whose prefixes should be applied to the symbol name.
+
+   SYMBOL_KIND is the value to be placed in the event_kind property of
+   the returned symbol.  */
+
+static Lisp_Object
+modify_event_symbol (symbol_num, modifiers, symbol_kind, name_table,
+                     symbol_table, table_size)
+     int symbol_num;
+     unsigned modifiers;
+     Lisp_Object symbol_kind;
+     char **name_table;
+     Lisp_Object *symbol_table;
+     int table_size;
+{
+  Lisp_Object *slot, *unmodified_slot;
+
+  /* Is this a request for a valid symbol?  */
+  if (symbol_num < 0 || symbol_num >= table_size
+      || modifiers >= NUM_MODIFIER_COMBOS)
+    abort ();
+
+  /* If *symbol_table is not a vector of the appropriate size,
+     set it to one.  */
+  if (XTYPE (*symbol_table) != Lisp_Vector
+      || XVECTOR (*symbol_table)->size != table_size)
+    *symbol_table = Fmake_vector (make_number (table_size), Qnil);
+
+  unmodified_slot = slot = & XVECTOR (*symbol_table)->contents[symbol_num];
+
+  /* If there are modifier keys, there had better be a vector in
+     this symbol's position of the symbol_table.  */
+  if (modifiers != 0)
+    {
+      Lisp_Object slot_contents = *slot;
+
+      /* If there isn't the right sort of vector there, put one in.  */
+      if (XTYPE (slot_contents) != Lisp_Vector
+	  || XVECTOR (slot_contents)->size != NUM_MODIFIER_COMBOS)
+	{
+	  *slot = Fmake_vector (make_number (NUM_MODIFIER_COMBOS), Qnil);
+
+	  /* Make sure that the vector has an entry for the unmodified
+	     symbol, so we can put it on the event_unmodified property.  */
+	  if (! NILP (slot_contents))
+	    XVECTOR (*slot)->contents[0] = slot_contents;
+	  else
+	    XVECTOR (*slot)->contents[0] = intern (name_table [symbol_num]);
+	}
+    }
+
+  /* If this entry has been filled in with a modified symbol vector,
+     point to the appropriate slot within that.  */
+  if (XTYPE (*slot) == Lisp_Vector)
+    {
+      unmodified_slot = & XVECTOR (*slot)->contents[0];
+      slot = & XVECTOR (*slot)->contents[modifiers];
+    }
+
+  /* Make sure we have an unmodified version of the symbol in its
+     proper place?  */
+  if (NILP (*unmodified_slot))
+    {
+      *unmodified_slot = intern (name_table [symbol_num]);
+      Fput (*unmodified_slot, Qevent_kind, symbol_kind);
+      Fput (*unmodified_slot, Qevent_unmodified, *unmodified_slot);
+    }
+
+  /* Have we already created a symbol for this combination of modifiers?  */
+  if (NILP (*slot))
+    {
+      /* No, let's create one.  */
+      char *modified_name
+	= (char *) alloca (sizeof ("C-M-S-U-")
+			   + strlen (name_table [symbol_num]));
+
+      strcpy (modified_name + format_modifiers (modifiers, modified_name),
+	      name_table [symbol_num]);
+
+      *slot = intern (modified_name);
+      Fput (*slot, Qevent_kind, symbol_kind);
+      Fput (*slot, Qevent_unmodified, *unmodified_slot);
+    }
+  
+  return *slot;
+}
+
+DEFUN ("mouse-click-p", Fmouse_click_p, Smouse_click_p, 1, 1, 0,
+  "Return non-nil iff OBJECT is a representation of a mouse event.\n\
+A mouse event is a list of five elements whose car is a symbol of the\n\
+form <MODIFIERS>mouse-<DIGIT>.  I hope this is a temporary hack.")
+  (object)
+     Lisp_Object object;
+{
+  if (EVENT_HAS_PARAMETERS (object)
+      && EQ (EVENT_HEAD_KIND (EVENT_HEAD (object)),
+	     Qmouse_click))
+    return Qt;
+  else
+    return Qnil;
+}
+
+/* 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.)  */
+
+static void
+get_input_pending (addr)
+     int *addr;
+{
+  /* First of all, have we already counted some input?  */
+  *addr = !NILP (Vquit_flag) || readable_events ();
+
+  /* If input is being read as it arrives, and we have none, there is none.  */
+  if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
+    return;
+
+  /* Try to read some input and see how much we get.  */
+  gobble_input (0);
+  *addr = !NILP (Vquit_flag) || readable_events ();
+}
+
+/* Interface to read_avail_input, blocking SIGIO if necessary.  */
+
+int
+gobble_input (expected)
+     int expected;
+{
+#ifndef VMS
+#ifdef SIGIO
+  if (interrupt_input)
+    {
+      SIGMASKTYPE mask = sigblockx (SIGIO);
+      read_avail_input (expected);
+      sigsetmask (mask);
+    }
+  else
+#endif
+    read_avail_input (expected);
+#endif
+}
+
+#ifndef VMS
+
+/* Read any terminal input already buffered up by the system
+   into the kbd_buffer, but do not wait.
+
+   EXPECTED should be nonzero if the caller knows there is some input.
+
+   Except on VMS, all input is read by this function.
+   If interrupt_input is nonzero, this function MUST be called
+   only when SIGIO is blocked.
+
+   Returns the number of keyboard chars read, or -1 meaning
+   this is a bad time to try to read input.  */
+
+static int
+read_avail_input (expected)
+     int expected;
+{
+  struct input_event buf[KBD_BUFFER_SIZE];
+  register int i;
+  int nread;
+
+  if (read_socket_hook)
+    /* No need for FIONREAD or fcntl; just say don't wait.  */
+    nread = (*read_socket_hook) (0, buf, KBD_BUFFER_SIZE, expected, expected);
+  else
+    {
+      unsigned char cbuf[KBD_BUFFER_SIZE];
+
+#ifdef FIONREAD
+      /* Find out how much input is available.  */
+      if (ioctl (0, FIONREAD, &nread) < 0)
+	/* Formerly simply reported no input, but that sometimes led to
+	   a failure of Emacs to terminate.
+	   SIGHUP seems appropriate if we can't reach the terminal.  */
+	kill (getpid (), SIGHUP);
+      if (nread == 0)
+	return 0;
+      if (nread > sizeof cbuf)
+	nread = sizeof cbuf;
+#else /* no FIONREAD */
+#ifdef USG
+      /* Read some input if available, but don't wait.  */
+      nread = sizeof cbuf;
+      fcntl (fileno (stdin), F_SETFL, O_NDELAY);
+#else
+      you lose;
+#endif
+#endif
+
+      /* Now read; for one reason or another, this will not block.  */
+      while (1)
+	{
+	  nread = read (fileno (stdin), cbuf, nread);
+#ifdef AIX
+	  /* The kernel sometimes fails to deliver SIGHUP for ptys.
+	     This looks incorrect, but it isn't, because _BSD causes
+	     O_NDELAY to be defined in fcntl.h as O_NONBLOCK,
+	     and that causes a value other than 0 when there is no input.  */
+	  if (nread == 0)
+	    kill (SIGHUP, 0);
+#endif
+	  /* Retry the read if it is interrupted.  */
+	  if (nread >= 0
+	      || ! (errno == EAGAIN || errno == EFAULT
+#ifdef EBADSLT
+		    || errno == EBADSLT
+#endif
+		    ))
+	    break;
+	}
+
+#ifndef FIONREAD
+#ifdef USG
+      fcntl (fileno (stdin), F_SETFL, 0);
+#endif /* USG */
+#endif /* no FIONREAD */
+      for (i = 0; i < nread; i++)
+	{
+	  buf[i].kind = ascii_keystroke;
+	  XSET (buf[i].code, Lisp_Int, cbuf[i]);
+	  buf[i].screen = selected_screen;
+	}
+    }
+
+  /* Scan the chars for C-g and store them in kbd_buffer.  */
+  for (i = 0; i < nread; i++)
+    {
+      kbd_buffer_store_event (&buf[i]);
+      /* Don't look at input that follows a C-g too closely.
+	 This reduces lossage due to autorepeat on C-g.  */
+      if (buf[i].kind == ascii_keystroke
+	  && XINT(buf[i].code) == quit_char)
+	break;
+    }
+
+  return nread;
+}
+#endif /* not VMS */
+
+#ifdef SIGIO   /* for entire page */
+/* Note SIGIO has been undef'd if FIONREAD is missing.  */
+
+input_available_signal (signo)
+     int signo;
+{
+  /* Must preserve main program's value of errno.  */
+  int old_errno = errno;
+#ifdef BSD4_1
+  extern int select_alarmed;
+#endif
+
+#ifdef USG
+  /* USG systems forget handlers when they are used;
+     must reestablish each time */
+  signal (signo, input_available_signal);
+#endif /* USG */
+
+#ifdef BSD4_1
+  sigisheld (SIGIO);
+#endif
+
+  if (input_available_clear_word)
+    *input_available_clear_word = 0;
+
+  while (1)
+    {
+      int nread;
+      nread = read_avail_input (1);
+      /* -1 means it's not ok to read the input now.
+	 UNBLOCK_INPUT will read it later; now, avoid infinite loop.
+	 0 means there was no keyboard input available.  */
+      if (nread <= 0)
+	break;
+
+#ifdef BSD4_1
+      select_alarmed = 1;  /* Force the select emulator back to life */
+#endif
+    }
+
+#ifdef BSD4_1
+  sigfree ();
+#endif
+  errno = old_errno;
+}
+#endif /* SIGIO */
+
+/* Return the prompt-string of a sparse keymap.
+   This is the first element which is a string.
+   Return nil if there is none.  */
+
+Lisp_Object
+map_prompt (map)
+     Lisp_Object map;
+{
+  while (CONSP (map))
+    {
+      register Lisp_Object tem;
+      tem = Fcar (map);
+      if (XTYPE (tem) == Lisp_String)
+	return tem;
+      map = Fcdr (map);
+    }
+  return Qnil;
+}
+
+static int echo_flag;
+static int echo_now;
+
+/* Read a character like read_char but optionally prompt based on maps
+   LOCAL and GLOBAL.
+
+   The prompting is done based on the prompt-string of the map
+   and the strings associated with various map elements.  */
+
+Lisp_Object
+read_char_menu_prompt (prompt, local, global)
+     int prompt;
+     Lisp_Object local, global;
+{
+  register Lisp_Object rest, name;
+  Lisp_Object hmap;
+  int nlength;
+  int width = SCREEN_WIDTH (selected_screen) - 4;
+  char *menu = (char *) alloca (width);
+
+  /* Use local over global Menu maps */
+
+  if (menu_prompting)
+    return read_char (!prompt);
+
+  /* We can't get prompt strings from dense keymaps.  */
+  if (CONSP (local)
+      && EQ (Fcar (local), Qkeymap)
+      && !(CONSP (XCONS (local)->cdr)
+	   && XTYPE (XCONS (XCONS (local)->cdr)->car) == Lisp_Vector))
+    hmap = local;
+  else if (CONSP (global)
+	   && EQ (Fcar (global), Qkeymap)
+	   && !(CONSP (XCONS (global)->cdr)
+		&& XTYPE (XCONS (XCONS (global)->cdr)->car) == Lisp_Vector))
+    hmap = global;
+  else
+    return read_char (!prompt);
+
+  /* Get the map's prompt string.  */
+  name = map_prompt (hmap);
+  if (NILP (name))
+    return read_char (!prompt);
+
+  /* Prompt string always starts with map's prompt, and a space.  */
+  strcpy (menu, XSTRING (name)->data);
+  nlength = XSTRING (name)->size;
+  menu[nlength++] = ' ';
+  menu[nlength] = 0;
+
+  /* Start prompting at start of map.  */
+  rest = hmap;			/* Current menu item */
+
+  /* Present the documented bindings, a line at a time.  */
+  while (1)
+    {
+      int notfirst = 0;
+      int i = nlength;
+      Lisp_Object obj;
+      int ch;
+
+      /* If reached end of map, start at beginning.  */
+      if (NILP (Fcdr (rest))) rest = hmap;
+
+      /* Loop over elements of map.  */
+      while (!NILP (rest) && i < width)
+	{
+	  Lisp_Object s;
+
+	  /* Look for conses whose cadrs are strings.  */
+	  s = Fcar_safe (Fcdr_safe (Fcar_safe (rest)));
+	  if (XTYPE (s) != Lisp_String)
+	    /* Ignore all other elements.  */
+	    ;
+	  /* If first such element, or enough room, add string to prompt.  */
+	  else if (XSTRING (s)->size + i < width
+		   || !notfirst)
+	    {
+	      int thiswidth;
+
+	      /* Punctuate between strings.  */
+	      if (notfirst)
+		{
+		  strcpy (menu + i, ", ");
+		  i += 2;
+		}
+	      notfirst = 1;
+
+	      /* 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;
+	    }
+	  else
+	    {
+	      /* If some elts don't fit, show there are more.  */
+	      strcpy (menu + i, "...");
+	      break;
+	    }
+
+	  /* Move past this element.  */
+	  rest = Fcdr_safe (rest);
+	}
+
+      /* Prompt with that and read response.  */
+      message1 (menu);
+      obj = read_char (1);
+
+      if (XTYPE (obj) != Lisp_Int)
+	return obj;
+      else
+	ch = XINT (obj);
+
+      if (obj != menu_prompt_more_char
+	  && (XTYPE (menu_prompt_more_char) != Lisp_Int
+	      || obj != make_number (Ctl (XINT (menu_prompt_more_char)))))
+	return obj;
+    }
+}
+
+
+/* Reading key sequences.  */
+
+/* Follow KEY in the maps in CURRENT[0..NMAPS-1], placing its bindings
+   in DEFS[0..NMAPS-1].  Set NEXT[i] to DEFS[i] if DEFS[i] is a
+   keymap, or nil otherwise.  Return the index of the first keymap in
+   which KEY has any binding, or NMAPS if no map has a binding.
+
+   If KEY is a meta ASCII character, treat it like meta-prefix-char
+   followed by the corresponding non-meta character.  Keymaps in
+   CURRENT with non-prefix bindings for meta-prefix-char become nil in
+   NEXT.
+
+   When KEY is not defined in any of the keymaps, if it is an upper
+   case letter and there are bindings for the corresponding lower-case
+   letter, return the bindings for the lower-case letter.
+
+   NEXT may == CURRENT.  */
+
+static int
+follow_key (key, nmaps, current, defs, next)
+     Lisp_Object key;
+     Lisp_Object *current, *defs, *next;
+     int nmaps;
+{
+  int i, first_binding;
+
+  /* If KEY is a meta ASCII character, treat it like meta-prefix-char
+     followed by the corresponding non-meta character.  */
+  if (XTYPE (key) == Lisp_Int
+      && XINT (key) >= 0200)
+    {
+      for (i = 0; i < nmaps; i++)
+	if (! NILP (current[i]))
+	  {
+	    next[i] = get_keyelt (access_keymap (current[i],
+						 meta_prefix_char));
+
+	    /* 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);
+	  }
+	else
+	  next[i] = Qnil;
+
+      current = next;
+      XSET (key, Lisp_Int, XFASTINT (key) & 0177);
+    }
+
+  first_binding = nmaps;
+  for (i = nmaps - 1; i >= 0; i--)
+    {
+      if (! NILP (current[i]))
+	{
+	  defs[i] = get_keyelt (access_keymap (current[i], key));
+	  if (! NILP (defs[i]))
+	    first_binding = i;
+	}
+      else
+	defs[i] = Qnil;
+    }
+
+  /* When KEY is not defined in any of the keymaps, if it is an upper
+     case letter and there are bindings for the corresponding
+     lower-case letter, return the bindings for the lower-case letter.  */
+  if (first_binding == nmaps
+      && XTYPE (key) == Lisp_Int
+      && UPPERCASEP (XINT (key)))
+    {
+      XSETINT (key, DOWNCASE (XINT (key)));
+
+      first_binding = nmaps;
+      for (i = nmaps - 1; i >= 0; i--)
+	{
+	  if (! NILP (current[i]))
+	    {
+	      defs[i] = get_keyelt (access_keymap (current[i], key));
+	      if (! NILP (defs[i]))
+		first_binding = i;
+	    }
+	  else
+	    defs[i] = Qnil;
+	}
+    }
+  
+  /* Given the set of bindings we've found, produce the next set of maps.  */
+  for (i = 0; i < nmaps; i++)
+    next[i] = NILP (defs[i]) ? Qnil : get_keymap_1 (defs[i], 0);
+
+  return first_binding;
+}
+
+/* Read a sequence of keys that ends with a non prefix character
+   according to the keymaps in KEYMAPS[0..nmaps-1].  Keymaps appearing
+   earlier in KEYMAPS take precidence over those appearing later.
+
+   Store the sequence in KEYBUF, a buffer of size BUFSIZE.  Prompt
+   with PROMPT.  Echo starting immediately unless `prompt' is 0.
+   Return the length of the key sequence stored.
+
+   If the user switches screens in the midst of a key sequence, we
+   throw away any prefix we have read so far, and start afresh.  For
+   mouse clicks, we look up the click in the keymap of the buffer
+   clicked on, throwing away any prefix if it is not the same buffer
+   we used to be reading from.  */
+
+static int
+read_key_sequence (keybuf, bufsize, prompt)
+     Lisp_Object *keybuf;
+     int bufsize;
+     Lisp_Object prompt;
+{
+  /* How many keys there are in the current key sequence.  */
+  int t;
+
+  /* The buffer that the most recently read event was typed at.  This
+     helps us read mouse clicks according to the buffer clicked in,
+     and notice when the mouse has moved from one screen to another.  */
+  struct buffer *last_event_buffer = current_buffer;
+
+  /* The length of the echo buffer when we started reading, and
+     the length of this_command_keys when we started reading.  */
+  int echo_start;
+  int keys_start = this_command_key_count;
+
+  /* The number of keymaps we're scanning right now, and the number of
+     keymaps we have allocated space for.  */
+  int nmaps;
+  int nmaps_allocated = 0;
+
+  /* current[0..nmaps-1] are the prefix definitions of KEYBUF[0..t-1]
+     in the current keymaps, or nil where it is not a prefix.  */
+  Lisp_Object *current;
+
+  /* defs[0..nmaps-1] are the definitions of KEYBUF[0..t-1] in
+     the current keymaps.  */
+  Lisp_Object *defs;
+
+  /* The lowest i such that defs[i] is non-nil.  */
+  int first_binding;
+
+  /* If mock_input > t, then KEYBUF[t] should be read as the next
+     input key.  */
+  int mock_input = 0;
+
+  /* If the sequence is unbound in current[], keymap[fkey_start..fkey_end-1]
+     is a prefix in Vfunction_key_map, and fkey_map is its binding.
+     These might be > t, indicating that all function key scanning should
+     hold off until t reaches them.  */
+  int fkey_start = 0, fkey_end = 0;
+  Lisp_Object fkey_map = Vfunction_key_map;
+
+  if (INTERACTIVE)
+    {
+      if (prompt)
+	echo_prompt (prompt);
+      else if (cursor_in_echo_area)
+	/* This doesn't put in a dash if the echo buffer is empty, so
+	   you don't always see a dash hanging out in the minibuffer.  */
+	echo_dash ();
+      echo_start = echo_length ();
+    }
+
+  /* If there is no function key map, turn of function key scanning.  */
+  if (NILP (Fkeymapp (Vfunction_key_map)))
+    fkey_start = fkey_end = bufsize + 1;
+
+ restart:
+  t = 0;
+  this_command_key_count = keys_start;
+
+  { 
+    Lisp_Object *maps;
+
+    nmaps = current_minor_maps (0, &maps) + 2;
+    if (nmaps > nmaps_allocated)
+      {
+	current = (Lisp_Object *) alloca (nmaps * sizeof (current[0]));
+	defs    = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
+	nmaps_allocated = nmaps;
+      }
+    bcopy (maps, current, (nmaps - 2) * sizeof (current[0]));
+    current[nmaps-2] = last_event_buffer->keymap;
+    current[nmaps-1] = global_map;
+  }
+
+  /* Find an accurate initial value for first_binding.  */
+  for (first_binding = 0; first_binding < nmaps; first_binding++)
+    if (! NILP (current[first_binding]))
+      break;
+
+  while ((first_binding < nmaps && ! NILP (current[first_binding]))
+	 || (first_binding >= nmaps && fkey_start < t))
+    {
+      Lisp_Object key;
+
+      if (t >= bufsize)
+	error ("key sequence too long");
+
+      /* Are we reading keys stuffed into keybuf?  */
+      if (t < mock_input)
+	{
+	  key = keybuf[t];
+	  add_command_key (key);
+	  echo_char (key);
+	}
+      /* Otherwise, we should actually read a character.  */
+      else
+	{
+	  struct buffer *buf;
+
+	  if (!prompt && INTERACTIVE)
+	    key = read_char_menu_prompt (prompt, Qnil, Qnil);
+	  else
+	    key = read_char (!prompt);
+
+	  /* The above routines return -1 at the end of a macro.
+	     Emacs 18 handles this by returning immediately with a
+	     zero, so that's what we'll do.  */
+	  if (XTYPE (key) == Lisp_Int && XINT (key) < 0)
+	    return 0;
+	  
+	  Vquit_flag = Qnil;
+
+	  /* What buffer was this event typed/moused at?  */
+	  if (XTYPE (key) == Lisp_Int || XTYPE (key) == Lisp_Symbol)
+	    buf = (XBUFFER
+		   (XWINDOW
+		    (SCREEN_SELECTED_WINDOW
+		     (XSCREEN (Vlast_event_screen)))->buffer));
+	  else if (EVENT_HAS_PARAMETERS (key))
+	    {
+	      Lisp_Object window = EVENT_WINDOW (key);
+
+	      if (NILP (window))
+		abort ();
+
+	      buf = XBUFFER (XWINDOW (window)->buffer);
+	    }
+	  else
+	    abort ();
+
+	  /* If this event came to a different buffer than the one
+	     we're currently in, switch buffers and start a new key
+	     sequence, starting with key.  */
+	  if (buf != last_event_buffer)
+	    {
+	      last_event_buffer = buf;
+	      Fselect_screen (Vlast_event_screen, Qnil);
+
+	      /* Arrange to read key as the next event.  */
+	      keybuf[0] = key;
+	      mock_input = 1;
+
+	      /* Truncate the key sequence in the echo area.  */
+	      if (INTERACTIVE)
+		echo_truncate (echo_start);
+
+	      goto restart;
+	    }
+	}
+
+      first_binding = (follow_key (key,
+				   nmaps   - first_binding,
+				   current + first_binding,
+				   defs    + first_binding,
+				   current + first_binding)
+		       + first_binding);
+      keybuf[t++] = key;
+
+      /* If the sequence is unbound, see if we can hang a function key
+	 off the end of it.  Don't reread the expansion of a function key.  */
+      if (first_binding >= nmaps
+	  && t > mock_input)
+	{
+	  Lisp_Object fkey_next;
+
+	  /* Scan from fkey_end until we find a bound suffix.  */
+	  while (fkey_end < t)
+	    {
+	      fkey_next =
+		get_keyelt (access_keymap (fkey_map, keybuf[fkey_end++]));
+
+	      /* If keybuf[fkey_start..fkey_next] is bound in the
+		 function key map and it's a suffix, replace it with
+		 the binding and restart.  */
+	      if (XTYPE (fkey_next) == Lisp_Vector
+		  && fkey_end == t)
+		{
+		  t = fkey_start + XVECTOR (fkey_next)->size;
+		  if (t >= bufsize)
+		    error ("key sequence too long");
+
+		  bcopy (XVECTOR (fkey_next)->contents,
+			 keybuf + fkey_start,
+			 (t - fkey_start) * sizeof (keybuf[0]));
+		  
+		  mock_input = t;
+		  fkey_start = fkey_end = t;
+
+		  /* Truncate the key sequence in the echo area.  */
+		  if (INTERACTIVE)
+		    echo_truncate (echo_start);
+
+		  goto restart;
+		}
+	      
+	      fkey_map = get_keymap_1 (fkey_next, 0);
+
+	      /* If we no longer have a bound suffix, advance 
+		 the start of the function key suffix and continue
+		 scanning from there.  */
+	      if (NILP (fkey_map))
+		{
+		  fkey_end = ++fkey_start;
+		  fkey_map = Vfunction_key_map;
+		}
+	    }
+	}
+    }
+
+  read_key_sequence_cmd = (first_binding < nmaps
+			   ? defs[first_binding]
+			   : Qnil);
+
+  return t;
+}
+
+DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 1, 0,
+  "Read a sequence of keystrokes and return as a string or vector.\n\
+The sequence is sufficient to specify a non-prefix command in the\n\
+current local and global maps.\n\
+\n\
+Arg PROMPT is a prompt string.  If nil, do not prompt specially.\n\
+\n\
+If Emacs is running on multiple screens, switching between screens in\n\
+the midst of a keystroke will toss any prefix typed so far.  A C-g\n\
+typed while in this function is treated like any other character, and\n\
+`quit-flag' is not set.")
+  (prompt)
+     Lisp_Object prompt;
+{
+  Lisp_Object keybuf[30];
+  register int i;
+  struct gcpro gcpro1, gcpro2;
+
+  if (!NILP (prompt))
+    CHECK_STRING (prompt, 0);
+  QUIT;
+
+  bzero (keybuf, sizeof keybuf);
+  GCPRO1 (keybuf[0]);
+  gcpro1.nvars = (sizeof keybuf/sizeof (keybuf[0]));
+
+  this_command_key_count = 0;
+  i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
+			 NILP (prompt)  ? 0 : XSTRING (prompt)->data);
+
+  UNGCPRO;
+  return make_array (i, keybuf);
+}
+
+DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 2, 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;
+{
+  register Lisp_Object final;
+  register Lisp_Object tem;
+  Lisp_Object prefixarg;
+  struct backtrace backtrace;
+  extern int debug_on_next_call;
+
+  prefixarg = Vprefix_arg, Vprefix_arg = Qnil;
+  Vcurrent_prefix_arg = prefixarg;
+  debug_on_next_call = 0;
+
+  if (XTYPE (cmd) == Lisp_Symbol)
+    {
+      tem = Fget (cmd, Qdisabled);
+      if (!NILP (tem))
+	return call1 (Vrun_hooks, Vdisabled_command_hook);
+    }
+
+  while (1)
+    {
+      final = cmd;
+      while (XTYPE (final) == Lisp_Symbol)
+	{
+	  if (EQ (Qunbound, XSYMBOL (final)->function))
+	    Fsymbol_function (final);    /* Get an error! */
+	  final = XSYMBOL (final)->function;
+	}
+
+      if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload)))
+	do_autoload (final, cmd);
+      else
+	break;
+    }
+
+  if (XTYPE (final) == Lisp_String
+      || XTYPE (final) == Lisp_Vector)
+    {
+      /* If requested, place the macro in the command history.  For
+	 other sorts of commands, call-interactively takes care of
+	 this.  */
+      if (!NILP (record))
+	Vcommand_history
+	  = Fcons (Fcons (Qexecute_kbd_macro,
+			  Fcons (final, Fcons (prefixarg, Qnil))),
+		   Vcommand_history);
+
+      return Fexecute_kbd_macro (final, prefixarg);
+    }
+  if (CONSP (final) || XTYPE (final) == Lisp_Subr
+      || XTYPE (final) == Lisp_Compiled)
+    {
+      backtrace.next = backtrace_list;
+      backtrace_list = &backtrace;
+      backtrace.function = &Qcall_interactively;
+      backtrace.args = &cmd;
+      backtrace.nargs = 1;
+      backtrace.evalargs = 0;
+
+      tem = Fcall_interactively (cmd, record);
+
+      backtrace_list = backtrace.next;
+      return tem;
+    }
+  return Qnil;
+}
+
+#if 0
+DEFUN ("execute-mouse-event", Fexecute_mouse_event, Sexecute_mouse_event,
+  1, 1, 0,
+  "Execute the definition of the mouse-click event EVENT.\n\
+The handler function is found by looking the event's key sequence up\n\
+in the buffer's local mouse map and in `global-mouse-map'.\n\
+\n\
+After running the handler, call the value of `mouse-event-function'\n\
+with EVENT as arg.")
+  (event)
+     Lisp_Object event;
+{
+  Lisp_Object tem;
+  Lisp_Object mouse_cmd;
+  Lisp_Object keyseq, window, screen_part, pos, time;
+
+#ifndef HAVE_X11
+  Vmouse_event = event;
+#endif
+
+  if (EQ (event, Qnil))
+    {
+      bitch_at_user ();
+      return Qnil;
+    }
+
+  CHECK_CONS (event, 0);
+  pos = Fcar (event);
+  window = Fcar (Fcdr (event));
+  screen_part = Fcar (Fcdr (Fcdr (event)));
+  keyseq = Fcar (Fcdr (Fcdr (Fcdr (event))));
+  time = Fcar (Fcdr (Fcdr (Fcdr (Fcdr (event)))));
+  CHECK_STRING (keyseq, 0);
+  CHECK_WINDOW (window, 0);
+
+  /* Look up KEYSEQ in the buffer's local mouse map, then in global one.  */
+
+  mouse_cmd = Qnil;
+
+  if (!NILP (XWINDOW (window)->buffer))
+    {
+      Lisp_Object local_map;
+
+      local_map = XBUFFER (XWINDOW (window)->buffer)->mouse_map;
+      tem = Fkeymapp (local_map);
+      if (!NILP (tem))
+	mouse_cmd = Flookup_key (local_map, keyseq);
+      /* A number as value means the key is too long; treat as undefined.  */
+      if (XTYPE (mouse_cmd) == Lisp_Int)
+	mouse_cmd = Qnil;
+    }
+
+  tem = Fkeymapp (Vglobal_mouse_map);
+  if (NILP (mouse_cmd) && !NILP (tem))
+    mouse_cmd = Flookup_key (Vglobal_mouse_map, keyseq);
+  if (XTYPE (mouse_cmd) == Lisp_Int)
+    mouse_cmd = Qnil;
+
+  if (NILP (mouse_cmd))
+    {
+      /* This button/shift combination is not defined.
+	 If it is a button-down event, ring the bell.  */
+#ifdef HAVE_X11
+      if (XSTRING (keyseq)->data[XSTRING (keyseq)->size - 1] & 0x18 == 0)
+#else
+      if (XSTRING (keyseq)->data[XSTRING (keyseq)->size - 1] & 4 == 0)
+#endif
+	bitch_at_user ();
+    }
+  else
+    {
+      SCREEN_PTR s = XSCREEN (WINDOW_SCREEN (XWINDOW (window)));
+
+#ifndef HAVE_X11
+      Vmouse_window = s->selected_window;
+#endif	/* HAVE_X11 */
+      /* It's defined; call the definition.  */
+      Vprefix_arg = Qnil;
+      if (!NILP (screen_part))
+	{
+	  /* For a scroll-bar click, set the prefix arg
+	     to the number of lines down from the top the click was.
+	     Many scroll commands want to scroll by this many lines.  */
+	  Lisp_Object position;
+	  Lisp_Object length;
+	  Lisp_Object offset;
+
+	  position = Fcar (pos);
+	  length = Fcar (Fcdr (pos));
+	  offset = Fcar (Fcdr (Fcdr (pos)));
+
+	  if (XINT (length) != 0)
+	    XSET (Vprefix_arg, Lisp_Int,
+		  (SCREEN_HEIGHT (s) * (XINT (position) + XINT (offset))
+		   / (XINT (length) + 2 * XINT (offset))));
+	}
+      Fcommand_execute (mouse_cmd, Qnil);
+    }
+
+  if (!NILP (Vmouse_event_function))  /* Not `event' so no need for GCPRO */
+    call1 (Vmouse_event_function, Vmouse_event);
+  return Qnil;
+}
+#endif
+
+DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_command,
+  1, 1, "P",
+  "Read function name, then read its arguments and call it.")
+  (prefixarg)
+     Lisp_Object prefixarg;
+{
+  Lisp_Object function;
+  char buf[40];
+  Lisp_Object saved_keys;
+  struct gcpro gcpro1;
+
+  saved_keys = Fthis_command_keys ();
+  buf[0] = 0;
+  GCPRO1 (saved_keys);
+
+  if (EQ (prefixarg, Qminus))
+    strcpy (buf, "- ");
+  else if (CONSP (prefixarg) && XINT (XCONS (prefixarg)->car) == 4)
+    strcpy (buf, "C-u ");
+  else if (CONSP (prefixarg) && XTYPE (XCONS (prefixarg)->car) == Lisp_Int)
+    sprintf (buf, "%d ", XINT (XCONS (prefixarg)->car));
+  else if (XTYPE (prefixarg) == Lisp_Int)
+    sprintf (buf, "%d ", XINT (prefixarg));
+
+  /* This isn't strictly correct if execute-extended-command
+     is bound to anything else.  Perhaps it should use
+     this_command_keys?  */
+  strcat (buf, "M-x ");
+
+  /* Prompt with buf, and then read a string, completing from and
+     restricting to the set of all defined commands.  Don't provide
+     any initial input.  The last Qnil says not to perform a 
+     peculiar hack on the initial input.  */
+  function = Fcompleting_read (build_string (buf),
+			       Vobarray, Qcommandp,
+			       Qt, Qnil, Qnil);
+
+  /* Add the text read to this_command_keys.  */
+  {
+    struct Lisp_String *func_str = XSTRING (function);
+    int i;
+    Lisp_Object tem;
+
+    for (i = 0; i < func_str->size; i++)
+      {
+	XSET (tem, Lisp_Int, func_str->data[i]);
+	add_command_key (tem);
+      }
+  }
+
+  UNGCPRO;
+
+  function = Fintern (function, Vobarray);
+  Vprefix_arg = prefixarg;
+  this_command = function;
+
+  return Fcommand_execute (function, Qt);
+}
+
+
+detect_input_pending ()
+{
+  if (!input_pending)
+    get_input_pending (&input_pending);
+
+  return input_pending;
+}
+
+DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 0, 0,
+  "T if command input is currently available with no waiting.\n\
+Actually, the value is nil only if we can be sure that no input is available.")
+  ()
+{
+  if (!NILP (unread_command_char))
+    return (Qt);
+
+  return detect_input_pending () ? Qt : Qnil;
+}
+
+DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
+  "Return vector of last 100 chars read from terminal.")
+  ()
+{
+  Lisp_Object val;
+
+  if (total_keys < NUM_RECENT_KEYS)
+    return Fvector (total_keys, recent_keys);
+  else
+    {
+      val = Fvector (NUM_RECENT_KEYS, recent_keys);
+      bcopy (recent_keys + recent_keys_index,
+	     XVECTOR (val)->contents,
+	     (NUM_RECENT_KEYS - recent_keys_index) * sizeof (Lisp_Object));
+      bcopy (recent_keys,
+	     XVECTOR (val)->contents + NUM_RECENT_KEYS - recent_keys_index,
+	     recent_keys_index * sizeof (Lisp_Object));
+      return val;
+    }
+}
+
+DEFUN ("this-command-keys", Fthis_command_keys, Sthis_command_keys, 0, 0, 0,
+  "Return string of the keystrokes that invoked this command.")
+  ()
+{
+  return make_array (this_command_key_count, this_command_keys);
+}
+
+DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
+  "Return the current depth in recursive edits.")
+  ()
+{
+  Lisp_Object temp;
+  XFASTINT (temp) = command_loop_level + minibuf_level;
+  return temp;
+}
+
+DEFUN ("open-dribble-file", Fopen_dribble_file, Sopen_dribble_file, 1, 1,
+  "FOpen dribble file: ",
+  "Start writing all keyboard characters to FILE.")
+  (file)
+     Lisp_Object file;
+{
+  if (NILP (file))
+    {
+      fclose (dribble);
+      dribble = 0;
+    }
+  else
+    {
+      file = Fexpand_file_name (file, Qnil);
+      dribble = fopen (XSTRING (file)->data, "w");
+    }
+  return Qnil;
+}
+
+DEFUN ("discard-input", Fdiscard_input, Sdiscard_input, 0, 0, 0,
+  "Discard the contents of the terminal input buffer.\n\
+Also cancel any kbd macro being defined.")
+  ()
+{
+  defining_kbd_macro = 0;
+  update_mode_lines++;
+
+#if 0
+  unread_command_char = make_number (-1);
+#endif
+  unread_command_char = Qnil;
+
+  discard_tty_input ();
+
+  kbd_fetch_ptr = kbd_store_ptr;
+  input_pending = 0;
+
+  return Qnil;
+}
+
+DEFUN ("suspend-emacs", Fsuspend_emacs, Ssuspend_emacs, 0, 1, "",
+  "Stop Emacs and return to superior process.  You can resume later.\n\
+On systems that don't have job control, run a subshell instead.\n\n\
+If optional arg STUFFSTRING is non-nil, its characters are stuffed\n\
+to be read as terminal input by Emacs's superior shell.\n\
+Before suspending, if `suspend-hook' is bound and value is non-nil\n\
+call the value as a function of no args.  Don't suspend if it returns non-nil.\n\
+Otherwise, suspend normally and after resumption call\n\
+`suspend-resume-hook' if that is bound and non-nil.\n\
+\n\
+Some operating systems cannot stop the Emacs process and resume it later.\n\
+On such systems, Emacs will start a subshell and wait for it to exit.")
+  (stuffstring)
+     Lisp_Object stuffstring;
+{
+  register Lisp_Object tem;
+  int count = specpdl_ptr - specpdl;
+  int old_height, old_width;
+  int width, height;
+  struct gcpro gcpro1;
+  extern init_sys_modes ();
+
+  if (!NILP (stuffstring))
+    CHECK_STRING (stuffstring, 0);
+  GCPRO1 (stuffstring);
+
+  /* Call value of suspend-hook
+     if it is bound and value is non-nil.  */
+  if (!NILP (Vrun_hooks))
+    {
+      tem = call1 (Vrun_hooks, intern ("suspend-hook"));
+      if (!EQ (tem, Qnil)) return Qnil;
+    }
+
+  get_screen_size (&old_width, &old_height);
+  reset_sys_modes ();
+  /* sys_suspend can get an error if it tries to fork a subshell
+     and the system resources aren't available for that.  */
+  record_unwind_protect (init_sys_modes, 0);
+  stuff_buffered_input (stuffstring);
+  sys_suspend ();
+  unbind_to (count, Qnil);
+
+  /* Check if terminal/window size has changed.
+     Note that this is not useful when we are running directly
+     with a window system; but suspend should be disabled in that case.  */
+  get_screen_size (&width, &height);
+  if (width != old_width || height != old_height)
+    change_screen_size (height, width, 0);
+
+  /* Call value of suspend-resume-hook
+     if it is bound and value is non-nil.  */
+  if (!NILP (Vrun_hooks))
+    call1 (Vrun_hooks, intern ("suspend-resume-hook"));
+  
+  UNGCPRO;
+  return Qnil;
+}
+
+/* If STUFFSTRING is a string, stuff its contents as pending terminal input.
+   Then in any case stuff anthing Emacs has read ahead and not used.  */
+
+stuff_buffered_input (stuffstring)
+     Lisp_Object stuffstring;
+{
+  register unsigned char *p;
+
+/* stuff_char works only in BSD, versions 4.2 and up.  */
+#ifdef BSD
+#ifndef BSD4_1
+  if (XTYPE (stuffstring) == Lisp_String)
+    {
+      register int count;
+
+      p = XSTRING (stuffstring)->data;
+      count = XSTRING (stuffstring)->size;
+      while (count-- > 0)
+	stuff_char (*p++);
+      stuff_char ('\n');
+    }
+  /* Anything we have read ahead, put back for the shell to read.  */
+  while (kbd_fetch_ptr != kbd_store_ptr)
+    {
+      if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
+	kbd_fetch_ptr = kbd_buffer;
+      if (kbd_fetch_ptr->kind == ascii_keystroke)
+	stuff_char (XINT (kbd_fetch_ptr->code));
+      kbd_fetch_ptr++;
+    }
+  input_pending = 0;
+#endif
+#endif /* BSD and not BSD4_1 */
+}
+
+set_waiting_for_input (word_to_clear)
+     long *word_to_clear;
+{
+  input_available_clear_word = word_to_clear;
+
+  /* Tell interrupt_signal to throw back to read_char,  */
+  waiting_for_input = 1;
+
+  /* If interrupt_signal was called before and buffered a C-g,
+     make it run again now, to avoid timing error. */
+  if (!NILP (Vquit_flag))
+    quit_throw_to_read_char ();
+
+  /* If alarm has gone off already, echo now.  */
+  if (echo_flag)
+    {
+      echo ();
+      echo_flag = 0;
+    }
+}
+
+clear_waiting_for_input ()
+{
+  /* Tell interrupt_signal not to throw back to read_char,  */
+  waiting_for_input = 0;
+  input_available_clear_word = 0;
+}
+
+/* This routine is called at interrupt level in response to C-G.
+ If interrupt_input, this is the handler for SIGINT.
+ Otherwise, it is called from kbd_buffer_store_event,
+ in handling SIGIO or SIGTINT.
+
+ If `waiting_for_input' is non zero, then unless `echoing' is nonzero,
+ immediately throw back to read_char.
+
+ Otherwise it sets the Lisp variable  quit-flag  not-nil.
+ This causes  eval  to throw, when it gets a chance.
+ If  quit-flag  is already non-nil, it stops the job right away.  */
+
+SIGTYPE
+interrupt_signal ()
+{
+  char c;
+  /* Must preserve main program's value of errno.  */
+  int old_errno = errno;
+  extern Lisp_Object Vwindow_system;
+
+#ifdef USG
+  /* USG systems forget handlers when they are used;
+     must reestablish each time */
+  signal (SIGINT, interrupt_signal);
+  signal (SIGQUIT, interrupt_signal);
+#endif /* USG */
+
+  cancel_echoing ();
+
+  if (!NILP (Vquit_flag) && SCREEN_IS_TERMCAP (selected_screen))
+    {
+      fflush (stdout);
+      reset_sys_modes ();
+      sigfree ();
+#ifdef SIGTSTP			/* Support possible in later USG versions */
+/*
+ * On systems which can suspend the current process and return to the original
+ * shell, this command causes the user to end up back at the shell.
+ * The "Auto-save" and "Abort" questions are not asked until
+ * the user elects to return to emacs, at which point he can save the current
+ * job and either dump core or continue.
+ */
+      sys_suspend ();
+#else
+#ifdef VMS
+      if (sys_suspend () == -1)
+	{
+	  printf ("Not running as a subprocess;\n");
+	  printf ("you can continue or abort.\n");
+	}
+#else /* not VMS */
+      /* Perhaps should really fork an inferior shell?
+	 But that would not provide any way to get back
+	 to the original shell, ever.  */
+      printf ("No support for stopping a process on this operating system;\n");
+      printf ("you can continue or abort.\n");
+#endif /* not VMS */
+#endif /* not SIGTSTP */
+      printf ("Auto-save? (y or n) ");
+      fflush (stdout);
+      if (((c = getchar ()) & ~040) == 'Y')
+	Fdo_auto_save (Qnil, Qnil);
+      while (c != '\n') c = getchar ();
+#ifdef VMS
+      printf ("Abort (and enter debugger)? (y or n) ");
+#else /* not VMS */
+      printf ("Abort (and dump core)? (y or n) ");
+#endif /* not VMS */
+      fflush (stdout);
+      if (((c = getchar ()) & ~040) == 'Y')
+	abort ();
+      while (c != '\n') c = getchar ();
+      printf ("Continuing...\n");
+      fflush (stdout);
+      init_sys_modes ();
+    }
+  else
+    {
+      /* If executing a function that wants to be interrupted out of
+	 and the user has not deferred quitting by binding `inhibit-quit'
+	 then quit right away.  */
+      if (immediate_quit && NILP (Vinhibit_quit))
+	{
+	  immediate_quit = 0;
+          sigfree ();
+	  Fsignal (Qquit, Qnil);
+	}
+      else
+	/* Else request quit when it's safe */
+	Vquit_flag = Qt;
+    }
+
+  if (waiting_for_input && !echoing)
+    quit_throw_to_read_char ();
+
+  errno = old_errno;
+}
+
+/* Handle a C-g by making read_char return C-g.  */
+
+quit_throw_to_read_char ()
+{
+  quit_error_check ();
+  sigfree ();
+  /* Prevent another signal from doing this before we finish.  */
+  waiting_for_input = 0;
+  input_pending = 0;
+
+#if 0
+  unread_command_char = make_number (-1);
+#endif
+  unread_command_char = Qnil;
+
+  _longjmp (getcjmp, 1);
+}
+
+DEFUN ("set-input-mode", Fset_input_mode, Sset_input_mode, 3, 4, 0,
+  "Set mode of reading keyboard input.\n\
+First arg non-nil means use input interrupts; nil means use CBREAK mode.\n\
+Second arg non-nil means use ^S/^Q flow control for output to terminal\n\
+ (no effect except in CBREAK mode).\n\
+Third arg non-nil means accept 8-bit input (for a Meta key).\n\
+ Otherwise, the top bit is ignored, on the assumption it is parity.\n\
+Optional fourth arg non-nil specifies character to use for quitting.")
+  (interrupt, flow, meta, quit)
+     Lisp_Object interrupt, flow, meta, quit;
+{
+  if (!NILP (quit)
+      && (XTYPE (quit) != Lisp_Int
+	  || XINT (quit) < 0 || XINT (quit) > 0400))
+    error ("set-input-mode: QUIT must be an ASCII character.");
+
+  reset_sys_modes ();
+#ifdef SIGIO
+/* Note SIGIO has been undef'd if FIONREAD is missing.  */
+#ifdef NO_SOCK_SIGIO
+  if (read_socket_hook)
+    interrupt_input = 0;	/* No interrupts if reading from a socket.  */
+  else
+#endif /* NO_SOCK_SIGIO */
+    interrupt_input = !NILP (interrupt);
+#else /* not SIGIO */
+  interrupt_input = 0;
+#endif /* not SIGIO */
+/* Our VMS input only works by interrupts, as of now.  */
+#ifdef VMS
+  interrupt_input = 1;
+#endif
+  flow_control = !NILP (flow);
+  meta_key = !NILP (meta);
+  if (!NILP (quit))
+    /* Don't let this value be out of range.  */
+    quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
+
+  init_sys_modes ();
+  return Qnil;
+}
+
+init_keyboard ()
+{
+  this_command_keys_size = 40;
+  this_command_keys =
+    (Lisp_Object *) xmalloc (this_command_keys_size * sizeof (Lisp_Object));
+
+  /* This is correct before outermost invocation of the editor loop */
+  command_loop_level = -1;
+  immediate_quit = 0;
+  quit_char = Ctl ('g');
+  unread_command_char = Qnil;
+  recent_keys_index = 0;
+  total_keys = 0;
+  kbd_fetch_ptr = kbd_buffer;
+  kbd_store_ptr = kbd_buffer;
+  do_mouse_tracking = 0;
+  input_pending = 0;
+
+  if (!noninteractive)
+    {
+      signal (SIGINT, interrupt_signal);
+#ifdef HAVE_TERMIO
+      /* For systems with SysV TERMIO, C-g is set up for both SIGINT and
+	 SIGQUIT and we can't tell which one it will give us.  */
+      signal (SIGQUIT, interrupt_signal);
+#endif /* HAVE_TERMIO */
+/* Note SIGIO has been undef'd if FIONREAD is missing.  */
+#ifdef SIGIO
+      signal (SIGIO, input_available_signal);
+#endif SIGIO
+    }
+
+/* Use interrupt input by default, if it works and noninterrupt input
+   has deficiencies.  */
+
+#ifdef INTERRUPT_INPUT
+  interrupt_input = 1;
+#else
+  interrupt_input = 0;
+#endif
+
+/* Our VMS input only works by interrupts, as of now.  */
+#ifdef VMS
+  interrupt_input = 1;
+#endif
+
+  sigfree ();
+  dribble = 0;
+
+  if (keyboard_init_hook)
+    (*keyboard_init_hook) ();
+
+#ifdef POLL_FOR_INPUT
+  poll_suppress_count = 1;
+  start_polling ();
+#endif
+}
+
+/* This type's only use is in syms_of_keyboard, to initialize the 
+   event header symbols and put properties on them.  */
+struct event_head {
+  Lisp_Object *var;
+  char *name;
+  Lisp_Object *kind;
+};
+
+struct event_head head_table[] = {
+  &Qmouse_movement,  "mouse-movement",   &Qmouse_movement,
+  &Qvscrollbar_part, "vscrollbar-part",  &Qscrollbar_click,
+  &Qvslider_part,    "vslider-part",     &Qscrollbar_click,
+  &Qvthumbup_part,   "vthumbup-part",    &Qscrollbar_click,
+  &Qvthumbdown_part, "vthumbdown-part",  &Qscrollbar_click,
+  &Qhscrollbar_part, "hscrollbar-part",  &Qscrollbar_click,
+  &Qhslider_part,    "hslider-part",     &Qscrollbar_click,
+  &Qhthumbleft_part, "hthumbleft-part",  &Qscrollbar_click,
+  &Qhthumbright_part,"hthumbright-part", &Qscrollbar_click
+};
+
+syms_of_keyboard ()
+{
+  Qself_insert_command = intern ("self-insert-command");
+  staticpro (&Qself_insert_command);
+
+  Qforward_char = intern ("forward-char");
+  staticpro (&Qforward_char);
+
+  Qbackward_char = intern ("backward-char");
+  staticpro (&Qbackward_char);
+
+  Qdisabled = intern ("disabled");
+  staticpro (&Qdisabled);
+
+  Qfunction_key = intern ("function-key");
+  staticpro (&Qfunction_key);
+  Qmouse_movement = intern ("mouse-click");
+  staticpro (&Qmouse_click);
+  Qmouse_movement = intern ("scrollbar-click");
+  staticpro (&Qmouse_movement);
+
+  Qmode_line = intern ("mode-line");
+  staticpro (&Qmode_line);
+  Qvertical_split = intern ("vertical-split");
+  staticpro (&Qvertical_split);
+
+  Qevent_kind = intern ("event-type");
+  staticpro (&Qevent_kind);
+  Qevent_unmodified = intern ("event-unmodified");
+  staticpro (&Qevent_unmodified);
+
+  {
+    struct event_head *p;
+
+    for (p = head_table;
+	 p < head_table + (sizeof (head_table) / sizeof (head_table[0]));
+	 p++)
+      {
+	*p->var = intern (p->name);
+	staticpro (p->var);
+	Fput (*p->var, Qevent_kind, *p->kind);
+	Fput (*p->var, Qevent_unmodified, *p->var);
+      }
+  }
+
+  func_key_syms = Qnil;
+  staticpro (&func_key_syms);
+
+  mouse_syms = Qnil;
+  staticpro (&mouse_syms);
+
+  defsubr (&Sread_key_sequence);
+  defsubr (&Srecursive_edit);
+  defsubr (&Strack_mouse);
+  defsubr (&Smouse_click_p);
+  defsubr (&Sinput_pending_p);
+  defsubr (&Scommand_execute);
+  defsubr (&Srecent_keys);
+  defsubr (&Sthis_command_keys);
+  defsubr (&Ssuspend_emacs);
+  defsubr (&Sabort_recursive_edit);
+  defsubr (&Sexit_recursive_edit);
+  defsubr (&Srecursion_depth);
+  defsubr (&Stop_level);
+  defsubr (&Sdiscard_input);
+  defsubr (&Sopen_dribble_file);
+  defsubr (&Sset_input_mode);
+  defsubr (&Sexecute_extended_command);
+
+  DEFVAR_LISP ("disabled-command-hook", &Vdisabled_command_hook,
+    "Value is called instead of any command that is disabled\n\
+(has a non-nil `disabled' property).");
+
+  DEFVAR_LISP ("last-command-char", &last_command_char,
+    "Last terminal input key that was part of a command.");
+
+  DEFVAR_LISP ("last-input-char", &last_input_char,
+    "Last terminal input key.");
+
+  DEFVAR_LISP ("unread-command-char", &unread_command_char,
+    "Object to be read as next input from input stream, or nil if none.");
+
+  DEFVAR_LISP ("meta-prefix-char", &meta_prefix_char,
+    "Meta-prefix character code.  Meta-foo as command input\n\
+turns into this character followed by foo.");
+  XSET (meta_prefix_char, Lisp_Int, 033);
+
+  DEFVAR_LISP ("last-command", &last_command,
+    "The last command executed.  Normally a symbol with a function definition,\n\
+but can be whatever was found in the keymap, or whatever the variable\n\
+`this-command' was set to by that command.");
+  last_command = Qnil;
+
+  DEFVAR_LISP ("this-command", &this_command,
+    "The command now being executed.\n\
+The command can set this variable; whatever is put here\n\
+will be in `last-command' during the following command.");
+  this_command = Qnil;
+
+  DEFVAR_INT ("auto-save-interval", &auto_save_interval,
+    "*Number of keyboard input characters between auto-saves.\n\
+Zero means disable autosaving due to number of characters typed.");
+  auto_save_interval = 300;
+
+  DEFVAR_LISP ("auto-save-timeout", &Vauto_save_timeout,
+    "*Number of seconds idle time before auto-save.\n\
+Zero or nil means disable auto-saving due to idleness.");
+  XFASTINT (Vauto_save_timeout) = 30;
+
+  DEFVAR_INT ("echo-keystrokes", &echo_keystrokes,
+    "*Nonzero means echo unfinished commands after this many seconds of pause.");
+  echo_keystrokes = 1;
+
+  DEFVAR_INT ("polling-period", &polling_period,
+    "*Interval between polling for input during Lisp execution.\n\
+The reason for polling is to make C-g work to stop a running program.\n\
+Polling is needed only when using X windows and SIGIO does not work.\n\
+Polling is automatically disabled in all other cases.");
+  polling_period = 2;
+  
+  DEFVAR_INT ("num-input-keys", &num_input_keys,
+    "*Number of complete keys read from the keyboard so far.");
+  num_input_keys = 0;
+
+  DEFVAR_LISP ("last-event-screen", &Vlast_event_screen,
+    "*The screen in which the most recently read event occurred.");
+  Vlast_event_screen = Qnil;
+
+  DEFVAR_LISP ("help-char", &help_char,
+    "Character to recognize as meaning Help.\n\
+When it is read, do `(eval help-form)', and display result if it's a string.\n\
+If the value of `help-form' is nil, this char can be read normally.");
+  XSET (help_char, Lisp_Int, Ctl ('H'));
+
+  DEFVAR_LISP ("help-form", &Vhelp_form,
+    "Form to execute when character help-char is read.\n\
+If the form returns a string, that string is displayed.\n\
+If `help-form' is nil, the help char is not recognized.");
+  Vhelp_form = Qnil;
+
+  DEFVAR_LISP ("top-level", &Vtop_level,
+    "Form to evaluate when Emacs starts up.\n\
+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\
+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.");
+  Vkeyboard_translate_table = Qnil;
+
+#ifdef HAVE_X_WINDOWS
+  DEFVAR_LISP ("mouse-event-function", &Vmouse_event_function,
+    "Function to call for each mouse event, after the event's definition.\n\
+Called, if non-nil, with one argument, which is the event-list.\n\
+See the variable `mouse-event' for the format of this list.");
+  Vmouse_event_function = Qnil;
+
+  DEFVAR_LISP ("mouse-left-hook", &Vmouse_left_hook,
+	       "Function to call when mouse leaves window.  No arguments.");
+  Vmouse_left_hook = Qnil;
+
+  DEFVAR_LISP ("map-screen-hook", &Vmap_screen_hook,
+	       "Function to call when screen is mapped.  No arguments.");
+  Vmap_screen_hook = Qnil;
+
+  DEFVAR_LISP ("unmap-screen-hook", &Vunmap_screen_hook,
+	       "Function to call when screen is unmapped.  No arguments.");
+  Vunmap_screen_hook = Qnil;
+
+  DEFVAR_LISP ("mouse-motion-handler", &Vmouse_motion_handler,
+	       "Handler for motion events.  No arguments.");
+  Vmouse_motion_handler = Qnil;
+#endif
+
+  DEFVAR_BOOL ("menu-prompting", &menu_prompting,
+    "Non-nil means prompt with menus in echo area when appropriate.\n\
+This is done when reading from a keymap that has a prompt string,\n\
+for elements that have prompt strings.");
+  menu_prompting = 1;
+
+  DEFVAR_LISP ("menu-prompt-more-char", &menu_prompt_more_char,
+    "Character to see next line of menu prompt.\n\
+Type this character while in a menu prompt to rotate around the lines of it.");
+  XSET (menu_prompt_more_char, Lisp_Int, ' ');
+}
+
+keys_of_keyboard ()
+{
+  initial_define_key (global_map, Ctl ('Z'), "suspend-emacs");
+  initial_define_key (control_x_map, Ctl ('Z'), "suspend-emacs");
+  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");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/keyboard.h	Tue Jan 28 17:22:57 1992 +0000
@@ -0,0 +1,68 @@
+/* Declarations useful when processing input.
+   Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+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.  */
+
+/* Total number of times read_char has returned.  */
+extern int num_input_chars;
+
+/* Nonzero means polling for input is temporarily suppresed.  */
+extern int poll_suppress_count;
+
+/* Keymap mapping ASCII function key sequences onto their preferred forms.
+   Initialized by the terminal-specific lisp files.  */
+extern Lisp_Object Vfunction_key_map;
+
+
+/* Macros for dealing with lispy events.  */
+
+/* True iff EVENT has data fields describing it (i.e. a mouse click).  */
+#define EVENT_HAS_PARAMETERS(event) \
+  (XTYPE (event) == Lisp_Cons && Flength (event) == 5)
+
+/* Access the components of composite events.  */
+#define EVENT_HEAD(event) 		(Fnth (0, (event)))
+#define EVENT_WINDOW(event)		(Fnth (1, (event)))
+#define EVENT_BUFFER_POSN(event)	(Fnth (2, (event)))
+#define EVENT_SCROLLBAR_BUTTON EVENT_BUFFER_POSN
+#define EVENT_WINDOW_POSN(event)	(Fnth (3, (event)))
+#define EVENT_TIMESTAMP(event)		(Fnth (4, (event)))
+
+/* Some of the event heads.  */
+extern Lisp_Object Qvscrollbar_part, Qvslider_part;
+extern Lisp_Object Qvthumbup_part, Qvthumbdown_part;
+extern Lisp_Object Qhscrollbar_part, Qhslider_part;
+extern Lisp_Object Qhthumbleft_part, Qhthumbright_part;
+
+/* Properties on event heads.  */
+extern Lisp_Object Qevent_kind, Qevent_unmodified;
+
+/* Getting an unmodified version of an event head.  */
+#define EVENT_HEAD_UNMODIFIED(event_head) \
+  (Fget ((event_head), Qevent_unmodified))
+
+/* The values of Qevent_kind properties.  */
+extern Lisp_Object Qfunction_key, Qmouse_click, Qmouse_movement;
+extern Lisp_Object Qscrollbar_click;
+
+/* Getting the kind of an event head.  */
+#define EVENT_HEAD_KIND(event_head) \
+  (Fget ((event_head), Qevent_kind))
+
+/* Symbols to use for non-text mouse positions.  */
+extern Lisp_Object Qmode_line, Qvertical_split;
+