/* 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.
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;
before this command was read. */
static int before_command_key_count;
static int before_command_echo_length;
-/* Values of before_command_key_count and before_command_echo_length
- saved by reset-this-command-lengths. */
-static int before_command_key_count_1;
-static int before_command_echo_length_1;
-/* Flag set by reset-this-command-lengths,
- saying to reset the lengths when add_command_key is called. */
-static int before_command_restore_flag;
extern int minbuf_level;
extern char *x_get_keysym_name ();
static void record_menu_key ();
+static int echo_length ();
Lisp_Object Qpolling_period;
/* 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 (" "));
for (i = 0; i < this_command_key_count; i++)
{
Lisp_Object c;
+
+ /* Set before_command_echo_length to the value that would
+ have been saved before the start of this subcommand in
+ command_loop_1, if we had already been echoing then. */
+ if (i == this_single_command_key_start)
+ before_command_echo_length = echo_length ();
+
c = XVECTOR (this_command_keys)->contents[i];
if (! (EVENT_HAS_PARAMETERS (c)
&& EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
echo_char (c);
}
+
+ /* Set before_command_echo_length to the value that would
+ have been saved before the start of this subcommand in
+ command_loop_1, if we had already been echoing then. */
+ if (this_command_key_count == this_single_command_key_start)
+ before_command_echo_length = echo_length ();
+
+ /* Put a dash at the end to invite the user to type more. */
echo_dash ();
}
add_command_key (key)
Lisp_Object key;
{
+#if 0 /* Not needed after we made Freset_this_command_lengths
+ do the job immediately. */
/* If reset-this-command-length was called recently, obey it now.
See the doc string of that function for an explanation of why. */
if (before_command_restore_flag)
echo_truncate (before_command_echo_length_1);
before_command_restore_flag = 0;
}
+#endif
if (this_command_key_count >= ASIZE (this_command_keys))
this_command_keys = larger_vector (this_command_keys,
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 ()
{
nonundocount = 0;
this_command_key_count = 0;
+ this_command_key_count_reset = 0;
this_single_command_key_start = 0;
if (NILP (Vmemory_full))
{
cancel_echoing ();
this_command_key_count = 0;
+ this_command_key_count_reset = 0;
this_single_command_key_start = 0;
goto finalize;
}
if (SYMBOLP (cmd))
{
Lisp_Object cmd1;
- if (cmd1 = Fremap_command (cmd), !NILP (cmd1))
+ if (cmd1 = Fcommand_remapping (cmd), !NILP (cmd1))
cmd = cmd1;
}
/* Put this before calling adjust_point_for_property
so it will only get called once in any case. */
goto directly_done;
- adjust_point_for_property (last_point_position, 0);
+ if (current_buffer == prev_buffer
+ && last_point_position != PT
+ && NILP (Vdisable_point_adjustment)
+ && NILP (Vglobal_disable_point_adjustment))
+ adjust_point_for_property (last_point_position, 0);
already_adjusted = 1;
if (PT == last_point_position + 1
&& (dp
lose = FETCH_CHAR (PT_BYTE);
if (! NILP (Vpost_command_hook))
goto directly_done;
- adjust_point_for_property (last_point_position, 0);
+ if (current_buffer == prev_buffer
+ && last_point_position != PT
+ && NILP (Vdisable_point_adjustment)
+ && NILP (Vglobal_disable_point_adjustment))
+ adjust_point_for_property (last_point_position, 0);
already_adjusted = 1;
if (PT == last_point_position - 1
&& (dp
/* 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
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;
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;
}
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
/* 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);
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);
}
also_record = Qnil;
+#if 0 /* This was commented out as part of fixing echo for C-u left. */
before_command_key_count = this_command_key_count;
before_command_echo_length = echo_length ();
+#endif
c = Qnil;
previous_echo_area_message = Qnil;
goto reread_for_input_method;
}
- /* If there is no function key translated before
- reset-this-command-lengths takes effect, forget about it. */
- before_command_restore_flag = 0;
+ this_command_key_count_reset = 0;
if (!NILP (Vexecuting_macro))
{
&& (unsigned) XINT (c) < 256)
{
Lisp_Object keys;
- int key_count;
+ int key_count, key_count_reset;
struct gcpro gcpro1;
int count = SPECPDL_INDEX ();
struct kboard *saved_ok_to_echo = ok_to_echo_at_next_pause;
int saved_echo_after_prompt = current_kboard->echo_after_prompt;
+#if 0
if (before_command_restore_flag)
{
this_command_key_count = before_command_key_count_1;
echo_truncate (before_command_echo_length_1);
before_command_restore_flag = 0;
}
+#endif
/* 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);
/* 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]))
/* 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;
goto retry;
}
- if (this_command_key_count == 0 || ! reread)
+ if (! reread || this_command_key_count == 0
+ || this_command_key_count_reset)
{
- before_command_key_count = this_command_key_count;
- before_command_echo_length = echo_length ();
/* Don't echo mouse motion events. */
if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
record_char (c);
+#if 0
before_command_key_count = this_command_key_count;
before_command_echo_length = echo_length ();
+#endif
/* Don't echo mouse motion events. */
if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
&& !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
case MULTIBYTE_CHAR_KEYSTROKE_EVENT:
{
Lisp_Object lispy_c;
+ int c = event->code;
- XSETFASTINT (lispy_c, event->code);
+ /* Add in the other modifier bits. We took care of ctrl_modifier
+ just above, and the shift key was taken care of by the X code,
+ and applied to control characters by make_ctrl_char. */
+ c |= (event->modifiers
+ & (meta_modifier | alt_modifier
+ | hyper_modifier | super_modifier | ctrl_modifier));
+ /* What about the `shift' modifier ? */
+ button_down_time = 0;
+ XSETFASTINT (lispy_c, c);
return lispy_c;
}
/* 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;
int row, column;
+ int wx, wy;
/* Ignore mouse events that were made on frame that
have been deleted. */
/* Set `window' to the window under frame pixel coordinates
event->x/event->y. */
window = window_from_coordinates (f, XINT (event->x),
- XINT (event->y), &part, 0);
+ XINT (event->y),
+ &part, &wx, &wy, 0);
if (!WINDOWP (window))
{
event->x/ event->y. */
struct window *w = XWINDOW (window);
- /* Get window relative coordinates. Original code
- `rounded' this to glyph boundaries. */
- int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
- int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
-
/* Set event coordinates to window-relative coordinates
for constructing the Lisp event below. */
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));
}
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,
}
}
#endif /* WINDOWSNT */
-#if defined(WINDOWSNT) || defined(MAC_OSX)
+#if 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;
pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
&column, &row, NULL, 1);
window = window_from_coordinates (f, XINT (event->x),
- XINT (event->y), &part, 0);
+ XINT (event->y),
+ &part, 0, 0, 0);
if (!WINDOWP (window))
{
else
{
int pixcolumn, pixrow;
- column -= XINT (XWINDOW (window)->left);
- row -= XINT (XWINDOW (window)->top);
+ column -= WINDOW_LEFT_EDGE_COL (XWINDOW (window));
+ row -= WINDOW_TOP_EDGE_LINE (XWINDOW (window));
glyph_to_pixel_coords (XWINDOW(window), column, row,
&pixcolumn, &pixrow);
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
{
Qnil))));
}
}
-#endif /* WINDOWSNT || MAC_OSX */
+#endif /* MAC_OSX */
case DRAG_N_DROP_EVENT:
{
- int part;
+ enum window_part part;
FRAME_PTR f;
Lisp_Object window;
Lisp_Object posn;
Lisp_Object files;
+ int wx, wy;
/* The frame_or_window field should be a cons of the frame in
which the event occurred and a list of the filenames
return Qnil;
window = window_from_coordinates (f, XINT (event->x),
- XINT (event->y), &part, 0);
+ XINT (event->y),
+ &part, &wx, &wy, 0);
if (!WINDOWP (window))
{
event->x/ event->y. */
struct window *w = XWINDOW (window);
- /* Get window relative coordinates. */
- int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
- int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
-
/* Set event coordinates to window-relative coordinates
for constructing the Lisp event below. */
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
{
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
/* Or is it an ordinary mouse movement? */
else
{
- int area;
+ enum window_part area;
Lisp_Object window;
Lisp_Object posn;
+ int wx, wy;
if (frame)
/* It's in a frame; which window on that frame? */
- window = window_from_coordinates (frame, XINT (x), XINT (y), &area, 0);
+ window = window_from_coordinates (frame, XINT (x), XINT (y),
+ &area, &wx, &wy, 0);
else
window = Qnil;
if (WINDOWP (window))
{
struct window *w = XWINDOW (window);
- int wx, wy;
- /* Get window relative coordinates. */
- wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (x));
- wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (y));
+ /* Set window relative coordinates. */
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
{
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. */
entry = Fcons (index, new_symbol);
Fput (base, Qmodifier_cache, Fcons (entry, cache));
- /* We have the parsing info now for free, so add it to the caches. */
- XSETFASTINT (index, modifiers);
- Fput (new_symbol, Qevent_symbol_element_mask,
- Fcons (base, Fcons (index, Qnil)));
- Fput (new_symbol, Qevent_symbol_elements,
- Fcons (base, lispy_modifier_list (modifiers)));
+ /* We have the parsing info now for free, so we could add it to
+ the caches:
+ XSETFASTINT (index, modifiers);
+ Fput (new_symbol, Qevent_symbol_element_mask,
+ Fcons (base, Fcons (index, Qnil)));
+ Fput (new_symbol, Qevent_symbol_elements,
+ Fcons (base, lispy_modifier_list (modifiers)));
+ Sadly, this is only correct if `base' is indeed a base event,
+ which is not necessarily the case. -stef */
}
/* Make sure this symbol is of the same kind as BASE.
#ifdef SIGIO /* for entire page */
/* Note SIGIO has been undef'd if FIONREAD is missing. */
-SIGTYPE
+static SIGTYPE
input_available_signal (signo)
int signo;
{
\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
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. */
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;
{
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
register Lisp_Object name;
int nlength;
/* FIXME: Use the minibuffer's frame width. */
- int width = FRAME_WIDTH (SELECTED_FRAME ()) - 4;
+ int width = FRAME_COLS (SELECTED_FRAME ()) - 4;
int idx = -1;
int nobindings = 1;
Lisp_Object rest, vector;
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;
}
such as Vfunction_key_map and Vkey_translation_map. */
typedef struct keyremap
{
- Lisp_Object map;
+ Lisp_Object map, parent;
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, prompt)
+ Lisp_Object *keybuf, prompt;
+ 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 = fkey->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 = fkey->parent;
+ }
+ return 0;
+}
/* Read a sequence of keys that ends with a non prefix character,
storing it in KEYBUF, a buffer of size BUFSIZE.
/* 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... */
last_nonmenu_event = Qnil;
delayed_switch_frame = Qnil;
- fkey.map = Vfunction_key_map;
- keytran.map = Vkey_translation_map;
+ fkey.map = fkey.parent = Vfunction_key_map;
+ keytran.map = keytran.parent = Vkey_translation_map;
/* If there is no translation-map, turn off scanning. */
fkey.start = fkey.end = KEYMAPP (fkey.map) ? 0 : bufsize + 1;
keytran.start = keytran.end = KEYMAPP (keytran.map) ? 0 : bufsize + 1;
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);
keybuf[i - first_unbound - 1] = keybuf[i];
mock_input = t - first_unbound - 1;
fkey.end = fkey.start -= first_unbound + 1;
- fkey.map = Vfunction_key_map;
+ fkey.map = fkey.parent;
keytran.end = keytran.start -= first_unbound + 1;
- keytran.map = Vkey_translation_map;
+ keytran.map = keytran.parent;
goto replay_sequence;
}
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
xterm-mouse-mode. -stef
Isn't this just the most wonderful code ever? */
+
+ /* If mock_input > t + 1, the above simplification
+ will actually end up dropping keys on the floor.
+ This is probably OK for now, but even
+ if mock_input <= t + 1, we need to adjust fkey
+ and keytran.
+ Typical case [header-line down-mouse-N]:
+ mock_input = 2, t = 1, fkey.end = 1,
+ last_real_key_start = 0. */
+ if (fkey.end > last_real_key_start)
+ {
+ fkey.end = fkey.start
+ = min (last_real_key_start, fkey.start);
+ fkey.map = fkey.parent;
+ if (keytran.end > last_real_key_start)
+ {
+ keytran.end = keytran.start
+ = min (last_real_key_start, keytran.start);
+ keytran.map = keytran.parent;
+ }
+ }
if (t == last_real_key_start)
{
mock_input = 0;
invariant that keytran.end <= fkey.start). */
{
if (fkey.start < t)
- (fkey.start = fkey.end = t, fkey.map = Vfunction_key_map);
+ (fkey.start = fkey.end = t, fkey.map = fkey.parent);
}
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, 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, 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,
if (NILP (continue_echo))
{
this_command_key_count = 0;
+ this_command_key_count_reset = 0;
this_single_command_key_start = 0;
}
if (NILP (continue_echo))
{
this_command_key_count = 0;
+ this_command_key_count_reset = 0;
this_single_command_key_start = 0;
}
int i;
this_command_key_count = 0;
+ this_command_key_count_reset = 0;
this_single_command_key_start = 0;
keys = XVECTOR (saved_keys)->contents;
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. */)
()
{
- before_command_restore_flag = 1;
- before_command_key_count_1 = before_command_key_count;
- before_command_echo_length_1 = before_command_echo_length;
+ 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;
}
int i;
this_command_key_count = 0;
+ this_command_key_count_reset = 0;
if (NILP (keep_record))
{
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
{&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
Vthis_command = Qnil;
DEFVAR_LISP ("this-original-command", &Vthis_original_command,
- doc: /* If non-nil, the original command bound to the current key sequence.
-The value of `this-command' is the result of looking up the original
-command in the active keymaps. */);
+ doc: /* The command bound to the current key sequence before remapping.
+It equals `this-command' if the original command was not remapped through
+any of the active keymaps. Otherwise, the value of `this-command' is the
+result of looking up the original command in the active keymaps. */);
Vthis_original_command = Qnil;
DEFVAR_INT ("auto-save-interval", &auto_save_interval,
"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");
}