summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Blandy <jimb@redhat.com>1992-10-03 15:37:35 +0000
committerJim Blandy <jimb@redhat.com>1992-10-03 15:37:35 +0000
commitd8f5a8e7d6b8ffc0bee48c5e423b7ceef81744dc (patch)
treef560104751a43a0f2077e91b18ab25ed372978bf
parentcb674b574d36cc0b902091af389b8b185a67e145 (diff)
downloademacs-d8f5a8e7d6b8ffc0bee48c5e423b7ceef81744dc.tar.gz
* keyboard.c (read_key_sequence): Treat mouse clicks on non-text
areas as if they were prefixed with the symbol denoting the area clicked on - `mode-line', etcetera. When we throw away an unbound `down-' event, reset mock_input as well. * keyboard.c (Qevent_symbol_element_mask, Qmodifier_cache): Two new symbols, used to implement caches on event heads. These take the place of some of the caching that modify_event_symbol used to do. (parse_modifiers_uncached, apply_modifiers_uncached, lispy_modifier_list, parse_modifiers, apply_modifiers): New functions, which replace format_modifiers and reorder_modifiers; they can be useful elsewhere too. (reorder_modifiers, modify_event_symbol): Re-implement these in terms of parse_modifiers and apply_modifiers. modify_event_symbol now uses a much simpler cache, and takes advantage of the caches maintained by parse_ and apply_modifiers. (follow_key): Don't modify NEXT if KEY has no bindings. (read_key_sequence): Drop unbound `down-' events, and turn unbound `drag-' events into clicks if that would make them bound. This benefits from the rewriting of the modifier key handling code. (syms_of_keyboard): Initialize and intern Qevent_symbol_element_mask and Qmodifier_cache. * keyboard.c (echo_prompt): Terminate the echo buffer properly even when the string is too long to display in the minibuffer. (echo_truncate): Just return echoptr - echobuf, rather than calling strlen on echobuf. * keyboard.c (modifier_names): The modifier is named "control", not "ctrl".
-rw-r--r--src/keyboard.c529
1 files changed, 359 insertions, 170 deletions
diff --git a/src/keyboard.c b/src/keyboard.c
index 06fe85d6bb4..9afcb951a1b 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -295,6 +295,19 @@ Lisp_Object Qscrollbar_click;
Lisp_Object Qevent_kind;
Lisp_Object Qevent_symbol_elements;
+/* An event header symbol HEAD may have a property named
+ Qevent_symbol_element_mask, which is of the form (BASE MODIFIERS);
+ BASE is the base, unmodified version of HEAD, and MODIFIERS is the
+ mask of modifiers applied to it. If present, this is used to help
+ speed up parse_modifiers. */
+Lisp_Object Qevent_symbol_element_mask;
+
+/* An unmodified event header BASE may have a property named
+ Qmodifier_cache, which is an alist mapping modifier masks onto
+ modified versions of BASE. If present, this helps speed up
+ apply_modifiers. */
+Lisp_Object Qmodifier_cache;
+
/* Symbols to use for non-text mouse positions. */
Lisp_Object Qmode_line;
Lisp_Object Qvertical_line;
@@ -369,8 +382,9 @@ echo_prompt (str)
int len = strlen (str);
if (len > sizeof echobuf - 4)
len = sizeof echobuf - 4;
- bcopy (str, echobuf, len + 1);
+ bcopy (str, echobuf, len);
echoptr = echobuf + len;
+ *echoptr = '\0';
echo ();
}
@@ -487,7 +501,7 @@ echo_truncate (len)
int len;
{
echobuf[len] = '\0';
- echoptr = echobuf + strlen (echobuf);
+ echoptr = echobuf + len;
}
@@ -1703,7 +1717,7 @@ make_lispy_event (event)
{
/* A simple keystroke. */
case ascii_keystroke:
- return event->code;
+ return XFASTINT (event->code);
break;
/* A function key. The symbol may need to have modifier prefixes
@@ -1720,12 +1734,13 @@ make_lispy_event (event)
a press, click or drag, and build the appropriate structure. */
case mouse_click:
{
+ int button = XFASTINT (event->code);
int part;
Lisp_Object window;
Lisp_Object posn;
struct mouse_position *loc;
- if (event->code < 0 || event->code >= NUM_MOUSE_BUTTONS)
+ if (button < 0 || button >= NUM_MOUSE_BUTTONS)
abort ();
/* Where did this mouse click occur? */
@@ -1753,7 +1768,7 @@ make_lispy_event (event)
/* If this is a button press, squirrel away the location, so we
can decide later whether it was a click or a drag. */
- loc = button_down_location + event->code;
+ loc = button_down_location + button;
if (event->modifiers & down_modifier)
{
loc->window = window;
@@ -1783,7 +1798,7 @@ make_lispy_event (event)
Lisp_Object head, start, end;
/* Build the components of the event. */
- head = modify_event_symbol (XFASTINT (event->code) - 1,
+ head = modify_event_symbol (button - 1,
event->modifiers,
Qmouse_click,
lispy_mouse_names, &mouse_syms,
@@ -1883,107 +1898,64 @@ make_lispy_movement (frame, x, y, time)
}
+
+/* Manipulating modifiers. */
-/* 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;
-
- /* Only the event queue may use the `up' modifier; it should always
- be turned into a click or drag event before presented to lisp code. */
- if (modifiers & up_modifier)
- abort ();
-
- if (modifiers & alt_modifier) { *p++ = 'A'; *p++ = '-'; }
- if (modifiers & ctrl_modifier) { *p++ = 'C'; *p++ = '-'; }
- if (modifiers & hyper_modifier) { *p++ = 'H'; *p++ = '-'; }
- if (modifiers & meta_modifier) { *p++ = 'M'; *p++ = '-'; }
- if (modifiers & shift_modifier) { *p++ = 'S'; *p++ = '-'; }
- if (modifiers & super_modifier) { strcpy (p, "super-"); p += 6; }
- if (modifiers & down_modifier) { strcpy (p, "down-"); p += 5; }
- if (modifiers & drag_modifier) { strcpy (p, "drag-"); p += 5; }
- /* The click modifier is denoted by the absence of other modifiers. */
- *p = '\0';
-
- return p - buf;
-}
+/* Parse the name of SYMBOL, and return the set of modifiers it contains.
+ If MODIFIER_END is non-zero, set *MODIFIER_END to the position in
+ SYMBOL's name of the end of the modifiers; the string from this
+ position is the unmodified symbol name.
-/* Given a symbol whose name begins with modifiers ("C-", "M-", etc),
- return a symbol with the modifiers placed in the canonical order.
- Canonical order is alphabetical, except for down and drag, which
- always come last. The 'click' modifier is never written out.
-
- 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)
+ This doesn't use any caches. */
+static int
+parse_modifiers_uncached (symbol, modifier_end)
Lisp_Object symbol;
+ int *modifier_end;
{
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->data[i]; )
+ for (i = 0; i+2 <= name->size; )
switch (name->data[i])
{
- case 'A':
- if (name->data[i] != '-') goto no_more_modifiers;
- not_canonical |= (modifiers & ~(alt_modifier - 1));
- modifiers |= alt_modifier;
+#define SINGLE_LETTER_MOD(bit) \
+ if (name->data[i+1] != '-') \
+ goto no_more_modifiers; \
+ modifiers |= bit; \
i += 2;
+
+ case 'A':
+ SINGLE_LETTER_MOD (alt_modifier);
break;
case 'C':
- if (name->data[i] != '-') goto no_more_modifiers;
- not_canonical |= (modifiers & ~(ctrl_modifier - 1));
- modifiers |= ctrl_modifier;
- i += 2;
+ SINGLE_LETTER_MOD (ctrl_modifier);
break;
case 'H':
- if (name->data[i] != '-') goto no_more_modifiers;
- not_canonical |= (modifiers & ~(hyper_modifier - 1));
- modifiers |= hyper_modifier;
- i += 2;
+ SINGLE_LETTER_MOD (hyper_modifier);
break;
case 'M':
- if (name->data[i] != '-') goto no_more_modifiers;
- not_canonical |= (modifiers & ~(meta_modifier - 1));
- modifiers |= meta_modifier;
- i += 2;
+ SINGLE_LETTER_MOD (meta_modifier);
break;
case 'S':
- if (name->data[i] != '-') goto no_more_modifiers;
- not_canonical |= (modifiers & ~(shift_modifier - 1));
- modifiers |= shift_modifier;
- i += 2;
+ SINGLE_LETTER_MOD (shift_modifier);
break;
case 's':
if (i + 6 > name->size
|| strncmp (name->data + i, "super-", 6))
goto no_more_modifiers;
- not_canonical |= (modifiers & ~(super_modifier - 1));
modifiers |= super_modifier;
i += 6;
break;
@@ -1993,13 +1965,11 @@ reorder_modifiers (symbol)
goto no_more_modifiers;
if (! strncmp (name->data + i, "drag-", 5))
{
- not_canonical |= (modifiers & ~(drag_modifier - 1));
modifiers |= drag_modifier;
i += 5;
}
else if (! strncmp (name->data + i, "down-", 5))
{
- not_canonical |= (modifiers & ~(down_modifier - 1));
modifiers |= down_modifier;
i += 5;
}
@@ -2009,29 +1979,209 @@ reorder_modifiers (symbol)
default:
goto no_more_modifiers;
+
+#undef SINGLE_LETTER_MOD
}
no_more_modifiers:
- if (!not_canonical)
- return symbol;
+ /* Should we include the `click' modifier? */
+ if (! (modifiers & (down_modifier | drag_modifier))
+ && i + 7 == name->size
+ && strncmp (name->data + i, "mouse-", 6)
+ && '0' <= name->data[i + 6]
+ && name->data[i + 6] <= '9')
+ modifiers |= click_modifier;
+
+ if (modifier_end)
+ *modifier_end = i;
+
+ return modifiers;
+}
+
+
+/* Return a symbol whose name is the modifier prefixes for MODIFIERS
+ prepended to the string BASE[0..BASE_LEN-1].
+ This doesn't use any caches. */
+static Lisp_Object
+apply_modifiers_uncached (modifiers, base, base_len)
+ int modifiers;
+ char *base;
+ int base_len;
+{
+ /* Since BASE 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 ("A-C-H-M-S-super-down-drag-"));
+ int mod_len;
- /* 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 ("A-C-H-M-S-super-U-down-drag-"));
- int len = format_modifiers (modifiers, new_mods);
- Lisp_Object new_name = make_uninit_string (len + name->size - i);
+ char *p = new_mods;
+
+ /* Only the event queue may use the `up' modifier; it should always
+ be turned into a click or drag event before presented to lisp code. */
+ if (modifiers & up_modifier)
+ abort ();
+
+ if (modifiers & alt_modifier) { *p++ = 'A'; *p++ = '-'; }
+ if (modifiers & ctrl_modifier) { *p++ = 'C'; *p++ = '-'; }
+ if (modifiers & hyper_modifier) { *p++ = 'H'; *p++ = '-'; }
+ if (modifiers & meta_modifier) { *p++ = 'M'; *p++ = '-'; }
+ if (modifiers & shift_modifier) { *p++ = 'S'; *p++ = '-'; }
+ if (modifiers & super_modifier) { strcpy (p, "super-"); p += 6; }
+ if (modifiers & down_modifier) { strcpy (p, "down-"); p += 5; }
+ if (modifiers & drag_modifier) { strcpy (p, "drag-"); p += 5; }
+ /* The click modifier is denoted by the absence of other modifiers. */
+
+ *p = '\0';
+
+ mod_len = p - new_mods;
+ }
- bcopy (new_mods, XSTRING (new_name)->data, len);
- bcopy (name->data + i, XSTRING (new_name)->data + len, name->size - i);
+ {
+ Lisp_Object new_name = make_uninit_string (mod_len + base_len);
+
+ bcopy (new_mods, XSTRING (new_name)->data, mod_len);
+ bcopy (base, XSTRING (new_name)->data + mod_len, base_len);
return Fintern (new_name, Qnil);
}
}
+static char *modifier_names[] =
+{
+ "up", "alt", "control", "hyper", "meta", "shift", "super", "down", "drag",
+ "click"
+};
+
+static Lisp_Object modifier_symbols;
+
+/* Return the list of modifier symbols corresponding to the mask MODIFIERS. */
+static Lisp_Object
+lispy_modifier_list (modifiers)
+ int modifiers;
+{
+ Lisp_Object modifier_list;
+ int i;
+
+ modifier_list = Qnil;
+ for (i = 0; (1<<i) <= modifiers; i++)
+ if (modifiers & (1<<i))
+ modifier_list = Fcons (XVECTOR (modifier_symbols)->contents[i],
+ modifier_list);
+
+ return modifier_list;
+}
+
+
+/* Parse the modifiers on SYMBOL, and return a list like (UNMODIFIED MASK),
+ where UNMODIFIED is the unmodified form of SYMBOL,
+ MASK is the set of modifiers present in SYMBOL's name.
+ This is similar to parse_modifiers_uncached, but uses the cache in
+ SYMBOL's Qevent_symbol_element_mask property, and maintains the
+ Qevent_symbol_elements property. */
+static Lisp_Object
+parse_modifiers (symbol)
+ Lisp_Object symbol;
+{
+ Lisp_Object elements = Fget (symbol, Qevent_symbol_element_mask);
+
+ if (CONSP (elements))
+ return elements;
+ else
+ {
+ int end;
+ int modifiers = parse_modifiers_uncached (symbol, &end);
+ Lisp_Object unmodified
+ = Fintern (make_string (XSYMBOL (symbol)->name->data + end,
+ XSYMBOL (symbol)->name->size - end),
+ Qnil);
+ Lisp_Object mask;
+
+ XFASTINT (mask) = modifiers;
+ elements = Fcons (unmodified, Fcons (mask, Qnil));
+
+ /* Cache the parsing results on SYMBOL. */
+ Fput (symbol, Qevent_symbol_element_mask,
+ elements);
+ Fput (symbol, Qevent_symbol_elements,
+ Fcons (unmodified, lispy_modifier_list (modifiers)));
+
+ /* Since we know that SYMBOL is modifiers applied to unmodified,
+ it would be nice to put that in unmodified's cache.
+ But we can't, since we're not sure that parse_modifiers is
+ canonical. */
+
+ return elements;
+ }
+}
+
+/* Apply the modifiers MODIFIERS to the symbol BASE.
+ BASE must be unmodified.
+
+ This is like apply_modifiers_uncached, but uses BASE's
+ Qmodifier_cache property, if present. It also builds
+ Qevent_symbol_elements properties, since it has that info anyway. */
+static Lisp_Object
+apply_modifiers (modifiers, base)
+ int modifiers;
+ Lisp_Object base;
+{
+ Lisp_Object cache, index, entry;
+
+ /* The click modifier never figures into cache indices. */
+ XFASTINT (index) = (modifiers & ~click_modifier);
+ cache = Fget (base, Qmodifier_cache);
+ entry = Fassq (index, cache);
+
+ if (CONSP (entry))
+ return XCONS (entry)->cdr;
+
+ /* We have to create the symbol ourselves. */
+ {
+ Lisp_Object new_symbol
+ = apply_modifiers_uncached (modifiers,
+ XSYMBOL (base)->name->data,
+ XSYMBOL (base)->name->size);
+
+ /* Add the new symbol to the base's cache. */
+ Fput (base, Qmodifier_cache,
+ Fcons (Fcons (index, new_symbol), cache));
+
+ /* We have the parsing info now for free, so add it to the caches. */
+ XFASTINT (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)));
+
+ return new_symbol;
+ }
+}
+
+
+/* Given a symbol whose name begins with modifiers ("C-", "M-", etc),
+ return a symbol with the modifiers placed in the canonical order.
+ Canonical order is alphabetical, except for down and drag, which
+ always come last. The 'click' modifier is never written out.
+
+ 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;
+{
+ /* It's hopefully okay to write the code this way, since everything
+ will soon be in caches, and no consing will be done at all. */
+ Lisp_Object parsed = parse_modifiers (symbol);
+
+ return apply_modifiers (XCONS (XCONS (parsed)->cdr)->car,
+ XCONS (parsed)->car);
+}
+
+
/* 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.
@@ -2058,14 +2208,6 @@ reorder_modifiers (symbol)
`event-symbol-elements' propery, which lists the modifiers present
in the symbol's name. */
-static char *modifier_names[] =
-{
- "up", "alt", "ctrl", "hyper", "meta", "shift", "super", "down", "drag",
- "click"
-};
-
-static Lisp_Object modifier_symbols;
-
static Lisp_Object
modify_event_symbol (symbol_num, modifiers, symbol_kind, name_table,
symbol_table, table_size)
@@ -2077,89 +2219,42 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_table,
int table_size;
{
Lisp_Object *slot;
- Lisp_Object unmodified;
- Lisp_Object temp;
/* Is this a request for a valid symbol? */
if (symbol_num < 0 || symbol_num >= table_size)
abort ();
- /* If *symbol_table doesn't seem to be initialized property, fix that.
-
+ /* If *symbol_table doesn't seem to be initialized properly, fix that.
*symbol_table should be a lisp vector TABLE_SIZE elements long,
- where the Nth element is an alist for modified versions of
- name_table[N]; the alist maps modifier masks onto the modified
- symbols. The click modifier is always omitted from the mask; it
- is indicated implicitly on a mouse event by the absence of the
- down_ and drag_ modifiers. */
+ where the Nth element is the symbol for NAME_TABLE[N]. */
if (XTYPE (*symbol_table) != Lisp_Vector
|| XVECTOR (*symbol_table)->size != table_size)
{
- XFASTINT (temp) = table_size;
- *symbol_table = Fmake_vector (temp, Qnil);
+ Lisp_Object size;
+
+ XFASTINT (size) = table_size;
+ *symbol_table = Fmake_vector (size, Qnil);
}
slot = & XVECTOR (*symbol_table)->contents[symbol_num];
- /* Have we already modified this symbol? */
- XFASTINT (temp) = modifiers & ~(click_modifier);
- temp = Fassq (temp, *slot);
- if (CONSP (temp))
- return (XCONS (temp)->cdr);
-
- /* We don't have an entry for the symbol; we have to build it. */
-
- /* Create a modified version of the symbol, and add it to the alist. */
- {
- Lisp_Object modified;
- char *modified_name
- = (char *) alloca (sizeof ("A-C-H-M-S-super-U-down-drag")
- + strlen (name_table [symbol_num]));
-
- strcpy (modified_name + format_modifiers (modifiers, modified_name),
- name_table [symbol_num]);
-
- modified = intern (modified_name);
- XFASTINT (temp) = modifiers & ~click_modifier;
- *slot = Fcons (Fcons (temp, modified), *slot);
- Fput (modified, Qevent_kind, symbol_kind);
-
+ /* Have we already used this symbol before? */
+ if (NILP (*slot))
{
- Lisp_Object modifier_list;
- int i;
-
- modifier_list = Qnil;
- for (i = 0; (1<<i) <= modifiers; i++)
- if (modifiers & (1<<i))
- modifier_list = Fcons (XVECTOR (modifier_symbols)->contents[i],
- modifier_list);
-
- /* Put an unmodified version of the symbol at the head of the
- list of symbol elements. */
- {
- /* We recurse to get the unmodified symbol; this allows us to
- write out the code to build event headers only once.
-
- Note that we put ourselves in the symbol_table before we
- recurse, so when an unmodified symbol calls this code
- to put itself on its Qevent_symbol_elements property, we do
- terminate. */
- Lisp_Object unmodified =
- modify_event_symbol (symbol_num,
- ((modifiers & (down_modifier | drag_modifier))
- ? click_modifier
- : 0),
- symbol_kind,
- name_table, symbol_table, table_size);
-
- Fput (modified, Qevent_symbol_elements,
- Fcons (unmodified, modifier_list));
- }
+ /* No; let's create it. */
+ *slot = intern (name_table[symbol_num]);
+
+ /* Fill in the cache entries for this symbol; this also
+ builds the Qevent_symbol_elements property, which the user
+ cares about. */
+ apply_modifiers (0, *slot);
+ Fput (*slot, Qevent_kind, symbol_kind);
}
- return modified;
- }
+ /* Apply modifiers to that symbol. */
+ return apply_modifiers (modifiers, *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\
@@ -2667,8 +2762,9 @@ follow_key (key, nmaps, current, defs, next)
}
/* 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);
+ if (first_binding < nmaps)
+ for (i = 0; i < nmaps; i++)
+ next[i] = NILP (defs[i]) ? Qnil : get_keymap_1 (defs[i], 0);
return first_binding;
}
@@ -2768,6 +2864,11 @@ read_key_sequence (keybuf, bufsize, prompt)
t = 0;
this_command_key_count = keys_start;
+ /* This is a no-op the first time through, but if we restart, it
+ reverts the echo area to its original state. */
+ if (INTERACTIVE)
+ echo_truncate (echo_start);
+
{
Lisp_Object *maps;
@@ -2794,9 +2895,26 @@ read_key_sequence (keybuf, bufsize, prompt)
Lisp_Object key;
int used_mouse_menu = 0;
+ /* These variables are analogous to echo_start and keys_start;
+ while those allow us to restart the entire key sequence,
+ echo_local_start and keys_local_start allow us to throw away
+ just one key. */
+ int echo_local_start = echo_length ();
+ int keys_local_start = this_command_key_count;
+ int local_first_binding = first_binding;
+
if (t >= bufsize)
error ("key sequence too long");
+ retry_key:
+ /* These are no-ops, unless we throw away a keystroke below and
+ jumped back up to retry_key; in that case, these restore these
+ variables to their original state, allowing us to restart the
+ loop. */
+ echo_truncate (echo_local_start);
+ this_command_key_count = keys_local_start;
+ first_binding = local_first_binding;
+
/* Are we re-reading a key sequence, as indicated by mock_input? */
if (t < mock_input)
{
@@ -2821,6 +2939,26 @@ read_key_sequence (keybuf, bufsize, prompt)
Vquit_flag = Qnil;
+ /* Clicks in non-text areas get prefixed by the symbol
+ in their CHAR-ADDRESS field. For example, a click on
+ the mode line is prefixed by the symbol `mode-line'. */
+ if (EVENT_HAS_PARAMETERS (key)
+ && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)), Qmouse_click))
+ {
+ Lisp_Object posn = POSN_BUFFER_POSN (EVENT_START (key));
+
+ if (XTYPE (posn) == Lisp_Symbol)
+ {
+ if (t + 1 >= bufsize)
+ error ("key sequence too long");
+ keybuf[t] = posn;
+ keybuf[t+1] = key;
+ mock_input = t + 2;
+
+ goto retry_key;
+ }
+ }
+
#ifdef MULTI_FRAME
/* What buffer was this event typed/moused at? */
if (used_mouse_menu)
@@ -2859,21 +2997,72 @@ read_key_sequence (keybuf, bufsize, prompt)
keybuf[0] = key;
mock_input = 1;
- /* Truncate the key sequence in the echo area. */
- if (INTERACTIVE)
- echo_truncate (echo_start);
-
goto restart;
}
#endif
}
-
+
first_binding = (follow_key (key,
nmaps - first_binding,
submaps + first_binding,
defs + first_binding,
submaps + first_binding)
+ first_binding);
+
+ /* If this key wasn't bound, we'll try some fallbacks. */
+ if (first_binding >= nmaps)
+ {
+ Lisp_Object head = EVENT_HEAD (key);
+
+ if (XTYPE (head) == Lisp_Symbol)
+ {
+ Lisp_Object breakdown = parse_modifiers (head);
+ Lisp_Object modifiers =
+ XINT (XCONS (XCONS (breakdown)->cdr)->car);
+
+ /* We drop unbound `down-' events altogether. */
+ if (modifiers & down_modifier)
+ {
+ /* Adding prefixes for non-textual mouse clicks creates
+ two characters of mock input, and this can't be the
+ first, so it's okay to clear mock_input in that case.
+ Only function key expansion could create more than
+ two keys, but that should never generate mouse events,
+ so it's okay to nuke mock_input in that case too.
+ Isn't this just the most wonderful code ever? */
+ mock_input = 0;
+ goto retry_key;
+ }
+
+ /* We turn unbound `drag-' events into `click-'
+ events, if the click would be bound. */
+ else if (modifiers & drag_modifier)
+ {
+ Lisp_Object new_head =
+ apply_modifiers (modifiers & ~drag_modifier,
+ XCONS (breakdown)->car);
+ Lisp_Object new_click =
+ Fcons (new_head, Fcons (EVENT_START (key), Qnil));
+
+ /* Look for a binding for this new key. follow_key
+ promises that it didn't munge submaps the
+ last time we called it, since key was unbound. */
+ first_binding =
+ (follow_key (new_click,
+ nmaps - local_first_binding,
+ submaps + local_first_binding,
+ defs + local_first_binding,
+ submaps + local_first_binding)
+ + local_first_binding);
+
+ /* If that click is bound, go for it. */
+ if (first_binding < nmaps)
+ key = new_click;
+ /* Otherwise, we'll leave key set to the drag event. */
+ }
+ }
+ }
+
keybuf[t++] = key;
/* Normally, last_nonmenu_event gets the previous key we read.
But when a mouse popup menu is being used,
@@ -2926,10 +3115,6 @@ read_key_sequence (keybuf, bufsize, prompt)
mock_input = t;
fkey_start = fkey_end = t;
- /* Truncate the key sequence in the echo area. */
- if (INTERACTIVE)
- echo_truncate (echo_start);
-
goto restart;
}
@@ -3125,7 +3310,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_
UNGCPRO;
- function = Fintern (function, Vobarray);
+ function = Fintern (function, Qnil);
Vprefix_arg = prefixarg;
this_command = function;
@@ -3621,6 +3806,10 @@ syms_of_keyboard ()
staticpro (&Qevent_kind);
Qevent_symbol_elements = intern ("event-symbol-elements");
staticpro (&Qevent_symbol_elements);
+ Qevent_symbol_element_mask = intern ("event-symbol-element-mask");
+ staticpro (&Qevent_symbol_element_mask);
+ Qmodifier_cache = intern ("modifier-cache");
+ staticpro (&Qmodifier_cache);
{
struct event_head *p;