(insert-directory): Remove --dired switch when
[bpt/emacs.git] / src / keyboard.c
index c104c43..5b5b78e 100644 (file)
@@ -1,5 +1,5 @@
 /* Keyboard and mouse input; editor command loop.
-   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000, 01, 02
+   Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03
      Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -145,6 +145,10 @@ Lisp_Object recent_keys; /* A vector, holding the last 100 keystrokes */
 Lisp_Object this_command_keys;
 int this_command_key_count;
 
+/* 1 after calling Freset_this_command_lengths.
+   Usually it is 0.  */
+int this_command_key_count_reset;
+
 /* This vector is used as a buffer to record the events that were actually read
    by read_key_sequence.  */
 Lisp_Object raw_keybuf;
@@ -781,14 +785,19 @@ echo_char (c)
       /* Replace a dash from echo_dash with a space, otherwise
         add a space at the end as a separator between keys.  */
       if (STRINGP (echo_string)
-         && SCHARS (echo_string) > 0)
+         && SCHARS (echo_string) > 1)
        {
-         Lisp_Object last_char, idx;
+         Lisp_Object last_char, prev_char, idx;
+
+         idx = make_number (SCHARS (echo_string) - 2);
+         prev_char = Faref (echo_string, idx);
 
          idx = make_number (SCHARS (echo_string) - 1);
          last_char = Faref (echo_string, idx);
 
-         if (XINT (last_char) == '-')
+         /* We test PREV_CHAR to make sure this isn't the echoing
+            of a minus-sign.  */
+         if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
            Faset (echo_string, idx, make_number (' '));
          else
            echo_string = concat2 (echo_string, build_string (" "));
@@ -1349,6 +1358,17 @@ static int read_key_sequence P_ ((Lisp_Object *, int, Lisp_Object,
 void safe_run_hooks P_ ((Lisp_Object));
 static void adjust_point_for_property P_ ((int, int));
 
+/* Cancel hourglass from protect_unwind.
+   ARG is not used.  */
+#ifdef HAVE_X_WINDOWS
+static Lisp_Object
+cancel_hourglass_unwind (arg)
+     Lisp_Object arg;
+{
+  cancel_hourglass ();
+}
+#endif
+
 Lisp_Object
 command_loop_1 ()
 {
@@ -1373,6 +1393,7 @@ command_loop_1 ()
 
   nonundocount = 0;
   this_command_key_count = 0;
+  this_command_key_count_reset = 0;
   this_single_command_key_start = 0;
 
   if (NILP (Vmemory_full))
@@ -1505,6 +1526,7 @@ command_loop_1 ()
        {
          cancel_echoing ();
          this_command_key_count = 0;
+         this_command_key_count_reset = 0;
          this_single_command_key_start = 0;
          goto finalize;
        }
@@ -1718,16 +1740,22 @@ command_loop_1 ()
 
          /* Here for a command that isn't executed directly */
 
+          {
 #ifdef HAVE_X_WINDOWS
-         if (display_hourglass_p
-             && NILP (Vexecuting_macro))
-           start_hourglass ();
+            int scount = SPECPDL_INDEX ();
+
+            if (display_hourglass_p
+                && NILP (Vexecuting_macro))
+              {
+                record_unwind_protect (cancel_hourglass_unwind, Qnil);
+                start_hourglass ();
+              }
 #endif
 
-         nonundocount = 0;
-         if (NILP (current_kboard->Vprefix_arg))
-           Fundo_boundary ();
-         Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
+            nonundocount = 0;
+            if (NILP (current_kboard->Vprefix_arg))
+              Fundo_boundary ();
+            Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
 
 #ifdef HAVE_X_WINDOWS
          /* Do not check display_hourglass_p here, because
@@ -1736,8 +1764,9 @@ command_loop_1 ()
             But don't cancel the hourglass within a macro
             just because a command in the macro finishes.  */
          if (NILP (Vexecuting_macro))
-           cancel_hourglass ();
+            unbind_to (scount, Qnil);
 #endif
+          }
        }
     directly_done: ;
       current_kboard->Vlast_prefix_arg = Vcurrent_prefix_arg;
@@ -1784,6 +1813,7 @@ command_loop_1 ()
          current_kboard->Vreal_last_command = real_this_command;
          cancel_echoing ();
          this_command_key_count = 0;
+         this_command_key_count_reset = 0;
          this_single_command_key_start = 0;
        }
 
@@ -1844,7 +1874,10 @@ adjust_point_for_property (last_pt, modified)
   int beg, end;
   Lisp_Object val, overlay, tmp;
   int check_composition = 1, check_display = 1, check_invisible = 1;
+  int orig_pt = PT;
 
+  /* FIXME: cycling is probably not necessary because these properties
+     can't be usefully combined anyway.  */
   while (check_composition || check_display || check_invisible)
     {
       if (check_composition
@@ -1911,7 +1944,19 @@ adjust_point_for_property (last_pt, modified)
          /* Move away from the inside area.  */
          if (beg < PT && end > PT)
            {
-             SET_PT (PT < last_pt ? beg : end);
+             SET_PT ((orig_pt == PT && (last_pt < beg || last_pt > end))
+                     /* We haven't moved yet (so we don't need to fear
+                        infinite-looping) and we were outside the range
+                        before (so either end of the range still corresponds
+                        to a move in the right direction): pretend we moved
+                        less than we actually did, so that we still have
+                        more freedom below in choosing which end of the range
+                        to go to.  */
+                     ? (orig_pt = -1, PT < last_pt ? end : beg)
+                     /* We either have moved already or the last point
+                        was already in the range: we don't get to choose
+                        which end of the range we have to go to.  */
+                     : (PT < last_pt ? beg : end));
              check_composition = check_display = 1;
            }
          xassert (PT == beg || PT == end);
@@ -1958,6 +2003,11 @@ static Lisp_Object
 safe_run_hooks_error (data)
      Lisp_Object data;
 {
+  Lisp_Object args[3];
+  args[0] = build_string ("Error in %s: %s");
+  args[1] = Vinhibit_quit;
+  args[2] = data;
+  Fmessage (3, args);
   return Fset (Vinhibit_quit, Qnil);
 }
 
@@ -2384,6 +2434,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       goto reread_for_input_method;
     }
 
+  this_command_key_count_reset = 0;
+
   if (!NILP (Vexecuting_macro))
     {
       /* We set this to Qmacro; since that's not a frame, nobody will
@@ -2949,7 +3001,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       && (unsigned) XINT (c) < 256)
     {
       Lisp_Object keys;
-      int key_count;
+      int key_count, key_count_reset;
       struct gcpro gcpro1;
       int count = SPECPDL_INDEX ();
 
@@ -2971,6 +3023,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
       /* Save the this_command_keys status.  */
       key_count = this_command_key_count;
+      key_count_reset = this_command_key_count_reset;
 
       if (key_count > 0)
        keys = Fcopy_sequence (this_command_keys);
@@ -2980,6 +3033,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
 
       /* Clear out this_command_keys.  */
       this_command_key_count = 0;
+      this_command_key_count_reset = 0;
 
       /* Now wipe the echo area.  */
       if (!NILP (echo_area_buffer[0]))
@@ -3002,6 +3056,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       /* Restore the saved echoing state
         and this_command_keys state.  */
       this_command_key_count = key_count;
+      this_command_key_count_reset = key_count_reset;
       if (key_count > 0)
        this_command_keys = keys;
 
@@ -3051,7 +3106,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
       goto retry;
     }
 
-  if (this_command_key_count == 0 || ! reread)
+  if (! reread || this_command_key_count == 0
+      || this_command_key_count_reset)
     {
 
       /* Don't echo mouse motion events.  */
@@ -3969,14 +4025,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu)
              && !EQ (frame, selected_frame))
            obj = make_lispy_switch_frame (frame);
          internal_last_event_frame = frame;
-         kbd_fetch_ptr = event + 1;
-       }
-      else if (event->kind == SELECT_WINDOW_EVENT)
-       {
-         /* Make an event (select-window (WINDOW)).  */
-         obj = Fcons (event->frame_or_window, Qnil);
-         obj = Fcons (Qselect_window, Fcons (obj, Qnil));
-
          kbd_fetch_ptr = event + 1;
        }
       else
@@ -5053,7 +5101,7 @@ make_lispy_event (event)
        /* Build the position as appropriate for this mouse click.  */
        if (event->kind == MOUSE_CLICK_EVENT)
          {
-           int part;
+           enum window_part part;
            struct frame *f = XFRAME (event->frame_or_window);
            Lisp_Object posn;
            Lisp_Object string_info = Qnil;
@@ -5152,26 +5200,26 @@ make_lispy_event (event)
                XSETINT (event->x, wx);
                XSETINT (event->y, wy);
 
-               if (part == 1 || part == 3)
+               if (part == ON_MODE_LINE || part == ON_HEADER_LINE)
                  {
                    /* Mode line or header line.  Look for a string under
                       the mouse that may have a `local-map' property.  */
                    Lisp_Object string;
                    int charpos;
 
-                   posn = part == 1 ? Qmode_line : Qheader_line;
-                   string = mode_line_string (w, wx, wy, part == 1, &charpos);
+                   posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
+                   string = mode_line_string (w, wx, wy, part, &charpos);
                    if (STRINGP (string))
                      string_info = Fcons (string, make_number (charpos));
                  }
-               else if (part == 2)
+               else if (part == ON_VERTICAL_BORDER)
                  posn = Qvertical_line;
-               else if (part == 6 || part == 7)
+               else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
                  {
                    int charpos;
                    Lisp_Object object = marginal_area_string (w, wx, wy, part,
                                                               &charpos);
-                   posn = (part == 6) ? Qleft_margin : Qright_margin;
+                   posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin;
                    if (STRINGP (object))
                      string_info = Fcons (object, make_number (charpos));
                  }
@@ -5400,6 +5448,9 @@ make_lispy_event (event)
        event->modifiers |= click_modifier;
        event->modifiers &= ~up_modifier;
 
+       if (event->code >= ASIZE (mouse_syms))
+          mouse_syms = larger_vector (mouse_syms, event->code + 1, Qnil);
+
        /* Get the symbol we should use for the mouse click.  */
        head = modify_event_symbol (event->code,
                                    event->modifiers,
@@ -5460,7 +5511,7 @@ make_lispy_event (event)
 #if defined(WINDOWSNT) || defined(MAC_OSX)
     case MOUSE_WHEEL_EVENT:
       {
-       int part;
+       enum window_part part;
        FRAME_PTR f = XFRAME (event->frame_or_window);
        Lisp_Object window;
        Lisp_Object posn;
@@ -5491,11 +5542,11 @@ make_lispy_event (event)
            XSETINT (event->x, pixcolumn);
            XSETINT (event->y, pixrow);
 
-           if (part == 1)
+           if (part == ON_MODE_LINE)
              posn = Qmode_line;
-           else if (part == 2)
+           else if (part == ON_VERTICAL_BORDER)
              posn = Qvertical_line;
-           else if (part == 3)
+           else if (part == ON_HEADER_LINE)
              posn = Qheader_line;
            else
              {
@@ -5533,7 +5584,7 @@ make_lispy_event (event)
 
     case DRAG_N_DROP_EVENT:
       {
-       int part;
+       enum window_part part;
        FRAME_PTR f;
        Lisp_Object window;
        Lisp_Object posn;
@@ -5576,11 +5627,11 @@ make_lispy_event (event)
            XSETINT (event->x, wx);
            XSETINT (event->y, wy);
 
-           if (part == 1)
+           if (part == ON_MODE_LINE)
              posn = Qmode_line;
-           else if (part == 2)
+           else if (part == ON_VERTICAL_BORDER)
              posn = Qvertical_line;
-           else if (part == 3)
+           else if (part == ON_HEADER_LINE)
              posn = Qheader_line;
            else
              {
@@ -5624,6 +5675,12 @@ make_lispy_event (event)
       return event->arg;
 #endif
 
+    case SELECT_WINDOW_EVENT:
+      /* Make an event (select-window (WINDOW)).  */
+      return Fcons (Qselect_window,
+                   Fcons (Fcons (event->frame_or_window, Qnil),
+                          Qnil));
+
     case TOOL_BAR_EVENT:
       if (EQ (event->arg, event->frame_or_window))
        /* This is the prefix key.  We translate this to
@@ -5676,7 +5733,7 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
   /* Or is it an ordinary mouse movement?  */
   else
     {
-      int area;
+      enum window_part area;
       Lisp_Object window;
       Lisp_Object posn;
 
@@ -5697,11 +5754,11 @@ make_lispy_movement (frame, bar_window, part, x, y, time)
          XSETINT (x, wx);
          XSETINT (y, wy);
 
-         if (area == 1)
+         if (area == ON_MODE_LINE)
            posn = Qmode_line;
-         else if (area == 2)
+         else if (area == ON_VERTICAL_BORDER)
            posn = Qvertical_line;
-         else if (area == 3)
+         else if (area == ON_HEADER_LINE)
            posn = Qheader_line;
          else
            {
@@ -5807,6 +5864,26 @@ parse_modifiers_uncached (symbol, modifier_end)
          break;
 
 #undef SINGLE_LETTER_MOD
+
+#define MULTI_LETTER_MOD(BIT, NAME, LEN)                       \
+         if (i + LEN + 1 <= SBYTES (name)                      \
+             && ! strncmp (SDATA (name) + i, NAME, LEN))       \
+           {                                                   \
+             this_mod_end = i + LEN;                           \
+             this_mod = BIT;                                   \
+           }
+
+       case 'd':
+         MULTI_LETTER_MOD (drag_modifier, "drag", 4);
+         MULTI_LETTER_MOD (down_modifier, "down", 4);
+         MULTI_LETTER_MOD (double_modifier, "double", 6);
+         break;
+
+       case 't':
+         MULTI_LETTER_MOD (triple_modifier, "triple", 6);
+         break;
+#undef MULTI_LETTER_MOD
+
        }
 
       /* If we found no modifier, stop looking for them.  */
@@ -6632,7 +6709,7 @@ read_avail_input (expected)
 #ifdef SIGIO   /* for entire page */
 /* Note SIGIO has been undef'd if FIONREAD is missing.  */
 
-SIGTYPE
+static SIGTYPE
 input_available_signal (signo)
      int signo;
 {
@@ -6693,8 +6770,8 @@ reinvoke_input_signal ()
 
 
 \f
-static void menu_bar_item P_ ((Lisp_Object, Lisp_Object));
-static void menu_bar_one_keymap P_ ((Lisp_Object));
+static void menu_bar_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, void*));
+static Lisp_Object menu_bar_one_keymap_changed_items;
 
 /* These variables hold the vector under construction within
    menu_bar_items and its subroutines, and the current index
@@ -6798,7 +6875,10 @@ menu_bar_items (old)
        def = get_keymap (access_keymap (maps[mapno], Qmenu_bar, 1, 0, 1),
                          0, 1);
        if (CONSP (def))
-         menu_bar_one_keymap (def);
+         {
+           menu_bar_one_keymap_changed_items = Qnil;
+           map_keymap (def, menu_bar_item, Qnil, NULL, 1);
+         }
       }
 
   /* Move to the end those items that should be at the end.  */
@@ -6852,48 +6932,15 @@ menu_bar_items (old)
   return menu_bar_items_vector;
 }
 \f
-/* Scan one map KEYMAP, accumulating any menu items it defines
-   in menu_bar_items_vector.  */
-
-static Lisp_Object menu_bar_one_keymap_changed_items;
-
-static void
-menu_bar_one_keymap (keymap)
-     Lisp_Object keymap;
-{
-  Lisp_Object tail, item;
-
-  menu_bar_one_keymap_changed_items = Qnil;
-
-  /* Loop over all keymap entries that have menu strings.  */
-  for (tail = keymap; CONSP (tail); tail = XCDR (tail))
-    {
-      item = XCAR (tail);
-      if (CONSP (item))
-       menu_bar_item (XCAR (item), XCDR (item));
-      else if (VECTORP (item))
-       {
-         /* Loop over the char values represented in the vector.  */
-         int len = XVECTOR (item)->size;
-         int c;
-         for (c = 0; c < len; c++)
-           {
-             Lisp_Object character;
-             XSETFASTINT (character, c);
-             menu_bar_item (character, XVECTOR (item)->contents[c]);
-           }
-       }
-    }
-}
-
 /* Add one item to menu_bar_items_vector, for KEY, ITEM_STRING and DEF.
    If there's already an item for KEY, add this DEF to it.  */
 
 Lisp_Object item_properties;
 
 static void
-menu_bar_item (key, item)
-     Lisp_Object key, item;
+menu_bar_item (key, item, dummy1, dummy2)
+     Lisp_Object key, item, dummy1;
+     void *dummy2;
 {
   struct gcpro gcpro1;
   int i;
@@ -6966,7 +7013,10 @@ menu_bar_item (key, item)
     {
       Lisp_Object old;
       old = XVECTOR (menu_bar_items_vector)->contents[i + 2];
-      XVECTOR (menu_bar_items_vector)->contents[i + 2] = Fcons (item, old);
+      /* If the new and the old items are not both keymaps,
+        the lookup will only find `item'.  */
+      item = Fcons (item, KEYMAPP (item) && KEYMAPP (XCAR (old)) ? old : Qnil);
+      XVECTOR (menu_bar_items_vector)->contents[i + 2] = item;
     }
 }
 \f
@@ -8129,20 +8179,13 @@ follow_key (key, nmaps, current, defs, next)
      int nmaps;
 {
   int i, first_binding;
-  int did_meta = 0;
 
   first_binding = nmaps;
   for (i = nmaps - 1; i >= 0; i--)
     {
       if (! NILP (current[i]))
        {
-         Lisp_Object map;
-         if (did_meta)
-           map = defs[i];
-         else
-           map = current[i];
-
-         defs[i] = access_keymap (map, key, 1, 0, 1);
+         defs[i] = access_keymap (current[i], key, 1, 0, 1);
          if (! NILP (defs[i]))
            first_binding = i;
        }
@@ -8166,6 +8209,119 @@ typedef struct keyremap
   int start, end;
 } keyremap;
 
+/* Lookup KEY in MAP.
+   MAP is a keymap mapping keys to key vectors or functions.
+   If the mapping is a function and DO_FUNCTION is non-zero, then
+   the function is called with PROMPT as parameter and its return
+   value is used as the return value of this function (after checking
+   that it is indeed a vector).  */
+
+static Lisp_Object
+access_keymap_keyremap (map, key, prompt, do_funcall)
+     Lisp_Object map, key, prompt;
+     int do_funcall;
+{
+  Lisp_Object next;
+  
+  next = access_keymap (map, key, 1, 0, 1);
+
+  /* Handle symbol with autoload definition.  */
+  if (SYMBOLP (next) && !NILP (Ffboundp (next))
+      && CONSP (XSYMBOL (next)->function)
+      && EQ (XCAR (XSYMBOL (next)->function), Qautoload))
+    do_autoload (XSYMBOL (next)->function, next);
+
+  /* Handle a symbol whose function definition is a keymap
+     or an array.  */
+  if (SYMBOLP (next) && !NILP (Ffboundp (next))
+      && (!NILP (Farrayp (XSYMBOL (next)->function))
+         || KEYMAPP (XSYMBOL (next)->function)))
+    next = XSYMBOL (next)->function;
+           
+  /* If the keymap gives a function, not an
+     array, then call the function with one arg and use
+     its value instead.  */
+  if (SYMBOLP (next) && !NILP (Ffboundp (next)) && do_funcall)
+    {
+      Lisp_Object tem;
+      tem = next;
+
+      next = call1 (next, prompt);
+      /* If the function returned something invalid,
+        barf--don't ignore it.
+        (To ignore it safely, we would need to gcpro a bunch of
+        other variables.)  */
+      if (! (VECTORP (next) || STRINGP (next)))
+       error ("Function %s returns invalid key sequence", tem);
+    }
+  return next;
+}
+
+/* Do one step of the key remapping used for function-key-map and
+   key-translation-map:
+   KEYBUF is the buffer holding the input events.
+   BUFSIZE is its maximum size.
+   FKEY is a pointer to the keyremap structure to use.
+   INPUT is the index of the last element in KEYBUF.
+   DOIT if non-zero says that the remapping can actually take place.
+   DIFF is used to return the number of keys added/removed by the remapping.
+   PARENT is the root of the keymap.
+   PROMPT is the prompt to use if the remapping happens through a function.
+   The return value is non-zero if the remapping actually took place.  */
+
+static int
+keyremap_step (keybuf, bufsize, fkey, input, doit, diff, parent, prompt)
+     Lisp_Object *keybuf, prompt, parent;
+     keyremap *fkey;
+     int input, doit, *diff, bufsize;
+{
+  Lisp_Object next, key;
+
+  key = keybuf[fkey->end++];
+  next = access_keymap_keyremap (fkey->map, key, prompt, doit);
+
+  /* If keybuf[fkey->start..fkey->end] is bound in the
+     map and we're in a position to do the key remapping, replace it with
+     the binding and restart with fkey->start at the end. */
+  if ((VECTORP (next) || STRINGP (next)) && doit)
+    {
+      int len = XFASTINT (Flength (next));
+      int i;
+
+      *diff = len - (fkey->end - fkey->start);
+
+      if (input + *diff >= bufsize)
+       error ("Key sequence too long");
+
+      /* Shift the keys that follow fkey->end.  */
+      if (*diff < 0)
+       for (i = fkey->end; i < input; i++)
+         keybuf[i + *diff] = keybuf[i];
+      else if (*diff > 0)
+       for (i = input - 1; i >= fkey->end; i--)
+         keybuf[i + *diff] = keybuf[i];
+      /* Overwrite the old keys with the new ones.  */
+      for (i = 0; i < len; i++)
+       keybuf[fkey->start + i]
+         = Faref (next, make_number (i));
+
+      fkey->start = fkey->end += *diff;
+      fkey->map = parent;
+
+      return 1;
+    }
+
+  fkey->map = get_keymap (next, 0, 1);
+
+  /* If we no longer have a bound suffix, try a new position for
+     fkey->start.  */
+  if (!CONSP (fkey->map))
+    {
+      fkey->end = ++fkey->start;
+      fkey->map = parent;
+    }
+  return 0;
+}
 
 /* Read a sequence of keys that ends with a non prefix character,
    storing it in KEYBUF, a buffer of size BUFSIZE.
@@ -8285,8 +8441,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
   /* Likewise, for key_translation_map.  */
   volatile keyremap keytran;
 
-  /* If we receive a ``switch-frame'' event in the middle of a key sequence,
-     we put it off for later.  While we're reading, we keep the event here.  */
+  /* If we receive a `switch-frame' or `select-window' event in the middle of
+     a key sequence, we put it off for later.
+     While we're reading, we keep the event here.  */
   volatile Lisp_Object delayed_switch_frame;
 
   /* See the comment below... */
@@ -8457,6 +8614,9 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
         just one key.  */
       volatile int echo_local_start, keys_local_start, local_first_binding;
 
+      eassert (fkey.end == t || (fkey.end > t && fkey.end <= mock_input));
+      eassert (fkey.start <= fkey.end);
+      eassert (keytran.start <= keytran.end);
       /* key-translation-map is applied *after* function-key-map.  */
       eassert (keytran.end <= fkey.start);
 
@@ -8625,6 +8785,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
          Vquit_flag = Qnil;
 
          if (EVENT_HAS_PARAMETERS (key)
+             /* Either a `switch-frame' or a `select-window' event.  */
              && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)), Qswitch_frame))
            {
              /* If we're at the beginning of a key sequence, and the caller
@@ -9029,207 +9190,49 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last,
       else
        /* If the sequence is unbound, see if we can hang a function key
           off the end of it.  */
-       {
-         Lisp_Object next;
-
-         /* Continue scan from fkey.end until we find a bound suffix.
-            If we fail, increment fkey.start and start over from there.  */
-         while (fkey.end < t)
-           {
-             Lisp_Object key;
-
-             key = keybuf[fkey.end++];
-             next = access_keymap (fkey.map, key, 1, 0, 1);
-
-             /* Handle symbol with autoload definition.  */
-             if (SYMBOLP (next) && ! NILP (Ffboundp (next))
-                 && CONSP (XSYMBOL (next)->function)
-                 && EQ (XCAR (XSYMBOL (next)->function), Qautoload))
-               do_autoload (XSYMBOL (next)->function, next);
-
-             /* Handle a symbol whose function definition is a keymap
-                or an array.  */
-             if (SYMBOLP (next) && ! NILP (Ffboundp (next))
-                 && (!NILP (Farrayp (XSYMBOL (next)->function))
-                     || KEYMAPP (XSYMBOL (next)->function)))
-               next = XSYMBOL (next)->function;
-
-#if 0 /* I didn't turn this on, because it might cause trouble
-        for the mapping of return into C-m and tab into C-i.  */
-             /* Optionally don't map function keys into other things.
-                This enables the user to redefine kp- keys easily.  */
-             if (SYMBOLP (key) && !NILP (Vinhibit_function_key_mapping))
-               next = Qnil;
-#endif
-
-             /* If the function key map gives a function, not an
-                array, then call the function with no args and use
-                its value instead.  */
-             if (SYMBOLP (next) && ! NILP (Ffboundp (next))
-                 /* If there's a binding (i.e. first_binding >= nmaps)
-                    we don't want to apply this function-key-mapping.  */
-                 && fkey.end == t && first_binding >= nmaps)
-               {
-                 struct gcpro gcpro1, gcpro2, gcpro3;
-                 Lisp_Object tem;
-                 tem = next;
-
-                 GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
-                 next = call1 (next, prompt);
-                 UNGCPRO;
-                 /* If the function returned something invalid,
-                    barf--don't ignore it.
-                    (To ignore it safely, we would need to gcpro a bunch of
-                    other variables.)  */
-                 if (! (VECTORP (next) || STRINGP (next)))
-                   error ("Function in key-translation-map returns invalid key sequence");
-               }
-
-             /* If keybuf[fkey.start..fkey.end] is bound in the
-                function key map and it's a suffix of the current
-                sequence (i.e. fkey.end == t), replace it with
-                the binding and restart with fkey.start at the end. */
-             if ((VECTORP (next) || STRINGP (next))
-                 /* If there's a binding (i.e. first_binding >= nmaps)
-                    we don't want to apply this function-key-mapping.  */
-                 && fkey.end == t && first_binding >= nmaps)
-               {
-                 int len = XFASTINT (Flength (next));
-
-                 t = fkey.start + len;
-                 if (t >= bufsize)
-                   error ("Key sequence too long");
-
-                 if (VECTORP (next))
-                   bcopy (XVECTOR (next)->contents,
-                          keybuf + fkey.start,
-                          (t - fkey.start) * sizeof (keybuf[0]));
-                 else if (STRINGP (next))
-                   {
-                     int i;
-
-                     for (i = 0; i < len; i++)
-                       XSETFASTINT (keybuf[fkey.start + i], SREF (next, i));
-                   }
-
-                 mock_input = t;
-                 fkey.start = fkey.end = t;
-                 fkey.map = Vfunction_key_map;
-
-                 /* Do pass the results through key-translation-map.
-                    But don't retranslate what key-translation-map
-                    has already translated.  */
-                 keytran.end = keytran.start;
-                 keytran.map = Vkey_translation_map;
-
-                 goto replay_sequence;
-               }
-
-             fkey.map = get_keymap (next, 0, 1);
-
-             /* If we no longer have a bound suffix, try a new positions for
-                fkey.start.  */
-             if (!CONSP (fkey.map))
-               {
-                 fkey.end = ++fkey.start;
-                 fkey.map = Vfunction_key_map;
-               }
-           }
-       }
-
-      /* Look for this sequence in key-translation-map.  */
-      {
-       Lisp_Object next;
-
-       /* Scan from keytran.end until we find a bound suffix.  */
-       while (keytran.end < fkey.start)
+       /* Continue scan from fkey.end until we find a bound suffix.  */
+       while (fkey.end < t)
          {
-           Lisp_Object key;
-
-           key = keybuf[keytran.end++];
-           next = access_keymap (keytran.map, key, 1, 0, 1);
-
-           /* Handle symbol with autoload definition.  */
-           if (SYMBOLP (next) && ! NILP (Ffboundp (next))
-               && CONSP (XSYMBOL (next)->function)
-               && EQ (XCAR (XSYMBOL (next)->function), Qautoload))
-             do_autoload (XSYMBOL (next)->function, next);
-
-           /* Handle a symbol whose function definition is a keymap
-              or an array.  */
-           if (SYMBOLP (next) && ! NILP (Ffboundp (next))
-               && (!NILP (Farrayp (XSYMBOL (next)->function))
-                   || KEYMAPP (XSYMBOL (next)->function)))
-             next = XSYMBOL (next)->function;
-
-           /* If the key translation map gives a function, not an
-              array, then call the function with one arg and use
-              its value instead.  */
-           if (SYMBOLP (next) && ! NILP (Ffboundp (next)))
-             {
-               struct gcpro gcpro1, gcpro2, gcpro3;
-               Lisp_Object tem;
-               tem = next;
-
-               GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
-               next = call1 (next, prompt);
-               UNGCPRO;
-               /* If the function returned something invalid,
-                  barf--don't ignore it.
-                  (To ignore it safely, we would need to gcpro a bunch of
-                  other variables.)  */
-               if (! (VECTORP (next) || STRINGP (next)))
-                 error ("Function in key-translation-map returns invalid key sequence");
-             }
-
-           /* If keybuf[keytran.start..keytran.end] is bound in the
-              key translation map and it's a suffix of the current
-              sequence (i.e. keytran.end == t), replace it with
-              the binding and restart with keytran.start at the end. */
-           if ((VECTORP (next) || STRINGP (next)))
+           struct gcpro gcpro1, gcpro2, gcpro3;
+           int done, diff;
+
+           GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
+           done = keyremap_step (keybuf, bufsize, &fkey,
+                                 max (t, mock_input),
+                                 /* If there's a binding (i.e.
+                                    first_binding >= nmaps) we don't want
+                                    to apply this function-key-mapping.  */
+                                 fkey.end + 1 == t && first_binding >= nmaps,
+                                 &diff, Vfunction_key_map, prompt);
+           UNGCPRO;
+           if (done)
              {
-               int len = XFASTINT (Flength (next));
-               int i, diff = len - (keytran.end - keytran.start);
-
-               mock_input = max (t, mock_input);
-               if (mock_input + diff >= bufsize)
-                 error ("Key sequence too long");
-
-               /* Shift the keys that are after keytran.end.  */
-               if (diff < 0)
-                 for (i = keytran.end; i < mock_input; i++)
-                   keybuf[i + diff] = keybuf[i];
-               else if (diff > 0)
-                 for (i = mock_input - 1; i >= keytran.end; i--)
-                   keybuf[i + diff] = keybuf[i];
-               /* Replace the keys between keytran.start and keytran.end
-                  with those from next.  */
-               for (i = 0; i < len; i++)
-                 keybuf[keytran.start + i]
-                   = Faref (next, make_number (i));
-
-               mock_input += diff;
-               keytran.start = keytran.end += diff;
-               keytran.map = Vkey_translation_map;
-
-               /* Adjust the function-key-map counters.  */
-               fkey.start += diff;
-               fkey.end += diff;
-
+               mock_input = diff + max (t, mock_input);
                goto replay_sequence;
              }
+         }
 
-           keytran.map = get_keymap (next, 0, 1);
+      /* Look for this sequence in key-translation-map.
+        Scan from keytran.end until we find a bound suffix.  */
+      while (keytran.end < fkey.start)
+       {
+         struct gcpro gcpro1, gcpro2, gcpro3;
+         int done, diff;
 
-           /* If we no longer have a bound suffix, try a new positions for
-              keytran.start.  */
-           if (!CONSP (keytran.map))
-             {
-               keytran.end = ++keytran.start;
-               keytran.map = Vkey_translation_map;
-             }
-         }
-      }
+         GCPRO3 (fkey.map, keytran.map, delayed_switch_frame);
+         done = keyremap_step (keybuf, bufsize, &keytran, max (t, mock_input),
+                               1, &diff, Vkey_translation_map, prompt);
+         UNGCPRO;
+         if (done)
+           {
+             mock_input = diff + max (t, mock_input);
+             /* Adjust the function-key-map counters.  */
+             fkey.end += diff;
+             fkey.start += diff;
+             
+             goto replay_sequence;
+           }
+       }
 
       /* If KEY is not defined in any of the keymaps,
         and cannot be part of a function key or translation,
@@ -9404,6 +9407,7 @@ will read just one key sequence.  */)
   if (NILP (continue_echo))
     {
       this_command_key_count = 0;
+      this_command_key_count_reset = 0;
       this_single_command_key_start = 0;
     }
 
@@ -9463,6 +9467,7 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
   if (NILP (continue_echo))
     {
       this_command_key_count = 0;
+      this_command_key_count_reset = 0;
       this_single_command_key_start = 0;
     }
 
@@ -9656,6 +9661,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
     int i;
 
     this_command_key_count = 0;
+    this_command_key_count_reset = 0;
     this_single_command_key_start = 0;
 
     keys = XVECTOR (saved_keys)->contents;
@@ -9891,24 +9897,28 @@ The value is always a vector.  */)
 
 DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
        Sreset_this_command_lengths, 0, 0, 0,
-       doc: /* Used for complicated reasons in `universal-argument-other-key'.
+       doc: /* Make the unread events replace the last command and echo.
+Used in `universal-argument-other-key'.
 
 `universal-argument-other-key' rereads the event just typed.
 It then gets translated through `function-key-map'.
-The translated event gets included in the echo area and in
-the value of `this-command-keys' in addition to the raw original event.
-That is not right.
-
-Calling this function directs the translated event to replace
-the original event, so that only one version of the event actually
-appears in the echo area and in the value of `this-command-keys'.  */)
+The translated event has to replace the real events,
+both in the value of (this-command-keys) and in echoing.
+To achieve this, `universal-argument-other-key' calls
+`reset-this-command-lengths', which discards the record of reading
+these events the first time.  */)
      ()
 {
   this_command_key_count = before_command_key_count;
   if (this_command_key_count < this_single_command_key_start)
     this_single_command_key_start = this_command_key_count;
+
   echo_truncate (before_command_echo_length);
 
+  /* Cause whatever we put into unread-command-events
+     to echo as if it were being freshly read from the keyboard.  */
+  this_command_key_count_reset = 1;
+
   return Qnil;
 }
 
@@ -9923,6 +9933,7 @@ KEEP-RECORD is non-nil.  */)
   int i;
 
   this_command_key_count = 0;
+  this_command_key_count_reset = 0;
 
   if (NILP (keep_record))
     {
@@ -10542,6 +10553,11 @@ init_keyboard ()
   poll_suppress_count = 1;
   start_polling ();
 #endif
+
+#ifdef MAC_OSX
+  /* At least provide an escape route since C-g doesn't work.  */
+  signal (SIGINT, interrupt_signal);
+#endif
 }
 
 /* This type's only use is in syms_of_keyboard, to initialize the
@@ -10559,7 +10575,9 @@ struct event_head head_table[] = {
   {&Qdelete_frame,        "delete-frame",        &Qdelete_frame},
   {&Qiconify_frame,       "iconify-frame",       &Qiconify_frame},
   {&Qmake_frame_visible,  "make-frame-visible",  &Qmake_frame_visible},
-  {&Qselect_window,       "select-window",       &Qselect_window}
+  /* `select-window' should be handled just like `switch-frame'
+     in read_key_sequence.  */
+  {&Qselect_window,       "select-window",       &Qswitch_frame}
 };
 
 void
@@ -11229,8 +11247,12 @@ keys_of_keyboard ()
                            "ignore-event");
   initial_define_lispy_key (Vspecial_event_map, "make-frame-visible",
                            "ignore-event");
-  initial_define_lispy_key (Vspecial_event_map, "select-window",
-                           "handle-select-window");
+  /* Handling it at such a low-level causes read_key_sequence to get
+   * confused because it doesn't realize that the current_buffer was
+   * changed by read_char.
+   * 
+   * initial_define_lispy_key (Vspecial_event_map, "select-window",
+   *                       "handle-select-window"); */
   initial_define_lispy_key (Vspecial_event_map, "save-session",
                            "handle-save-session");
 }