# HG changeset patch # User Jim Blandy # Date 720508905 0 # Node ID 8cc7bc81d2aa5b60e80aeb9596e852f5f7cf3199 # Parent ceaecac6bf2e3320997f2e317f37f3502c83524b * keyboard.c: #include dispextern.h. (recursive_edit_unwind, command_loop, Fthis_command_keys): Declare these to return Lisp_Objects at the very top of the file, to avoid having them implicitly declared as ints. (echo_char): Use EQ to compare C to help_char. (read_char): Remember to apply XFASTINT to the return value of Flength before using it. Apply XINT to c when clearing its high bits and meta bits, and when writing it to the dribble file. (read_char_menu_prompt): Use EQ to compare obj with menu_prompt_more_char and its control-character analog. (read_key_sequence): Declare PROMPT to be char *, not a Lisp_Object. Use the appropriate accessors on keybuf when looking for ASCII function key sequences. * keyboard.c (echobuf): Make this 300 characters, not 100. This isn't a real fix, but it's quick. * keyboard.c (read_char): When returning an unread switch-frame event, jump to reread_first to return it, rather than reread; this makes sure the event gets echoed (if appropriate) and goes into this_command_keys. * keyboard.c (read_key_sequence): If the key sequence starts with a mouse click, read the key sequence using the keymaps of the buffer clicked on, not the current buffer. * keyboard.c (unread_switch_frame): Make this static, to indicate that nobody outside of this file uses it. * keyboard.c (follow_key): Ask get_keymap_1 to perform autoloads. (read_key_sequence): When pursuing potential bindings in the function key map, ask get_keymap_1 to perform autoloading. This is hardly important, but it's consistent. diff -r ceaecac6bf2e -r 8cc7bc81d2aa src/keyboard.c --- a/src/keyboard.c Sat Oct 31 05:20:51 1992 +0000 +++ b/src/keyboard.c Sat Oct 31 05:21:45 1992 +0000 @@ -33,6 +33,7 @@ #include "commands.h" #include "buffer.h" #include "disptab.h" +#include "dispextern.h" #include "keyboard.h" #include #include @@ -156,8 +157,10 @@ /* If not Qnil, this is a switch-frame event which we decided to put off until the end of a key sequence. This should be read as the - next command input, after any unread_command_char. */ -Lisp_Object unread_switch_frame; + next command input, after any unread_command_char. Only + read_key_sequence sets this; it uses it to delay switch-frame + events until the end of the key sequence. */ +static Lisp_Object unread_switch_frame; /* Char to use as prefix when a meta character is typed in. This is bound on entry to minibuffer in case ESC is changed there. */ @@ -323,6 +326,8 @@ Lisp_Object Qmode_line; Lisp_Object Qvertical_line; +Lisp_Object recursive_edit_unwind (), command_loop (); +Lisp_Object Fthis_command_keys (); /* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt happens. */ @@ -374,8 +379,8 @@ static int immediate_echo; /* The text we're echoing in the modeline - partial key sequences, - usually. '\0'-terminated. */ -static char echobuf[100]; + usually. '\0'-terminated. This really shouldn't have a fixed size. */ +static char echobuf[300]; /* Where to append more text to echobuf if we want to. */ static char *echoptr; @@ -435,7 +440,7 @@ ptr += name->size; } - if (echoptr == echobuf && c == help_char) + if (echoptr == echobuf && EQ (c, help_char)) { strcpy (ptr, " (Type ? for further options)"); ptr += strlen (ptr); @@ -563,8 +568,6 @@ last_auto_save = num_nonmacro_input_chars; } -Lisp_Object recursive_edit_unwind (), command_loop (); - DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "", "Invoke the editor command loop recursively.\n\ To get out of the recursive edit, a command can do `(throw 'exit nil)';\n\ @@ -1143,7 +1146,7 @@ from a macro should never cause a new frame to be selected. */ Vlast_event_frame = Qmacro; - if (executing_macro_index >= Flength (Vexecuting_macro)) + if (executing_macro_index >= XFASTINT (Flength (Vexecuting_macro))) { XSET (c, Lisp_Int, -1); return c; @@ -1161,8 +1164,8 @@ unread_switch_frame = Qnil; /* This event should make it into this_command_keys, and get echoed - again, so we go to reread, rather than reread_first. */ - goto reread; + again, so we go to reread_first, rather than reread. */ + goto reread_first; } /* Save outer setjmp data, in case called recursively. */ @@ -1299,11 +1302,11 @@ return c; /* Strip the high bits, and maybe the meta bit too. */ - XSETINT (c, c & (meta_key ? 0377 : 0177)); + XSETINT (c, XINT (c) & (meta_key ? 0377 : 0177)); if (XTYPE (Vkeyboard_translate_table) == Lisp_String - && XSTRING (Vkeyboard_translate_table)->size > XINT (c)) - XSETINT (c, XSTRING (Vkeyboard_translate_table)->data[c]); + && XSTRING (Vkeyboard_translate_table)->size > XFASTINT (c)) + XSETINT (c, XSTRING (Vkeyboard_translate_table)->data[XFASTINT (c)]); } total_keys++; @@ -1317,7 +1320,7 @@ if (dribble) { if (XTYPE (c) == Lisp_Int) - putc (c, dribble); + putc (XINT (c), dribble); else { Lisp_Object dribblee = c; @@ -2727,9 +2730,9 @@ else ch = XINT (obj); - if (obj != menu_prompt_more_char + if (! EQ (obj, menu_prompt_more_char) && (XTYPE (menu_prompt_more_char) != Lisp_Int - || obj != make_number (Ctl (XINT (menu_prompt_more_char))))) + || ! EQ (obj, make_number (Ctl (XINT (menu_prompt_more_char)))))) return obj; } } @@ -2777,7 +2780,7 @@ /* Note that since we pass the resulting bindings through get_keymap_1, non-prefix bindings for meta-prefix-char disappear. */ - next[i] = get_keymap_1 (next[i], 0); + next[i] = get_keymap_1 (next[i], 0, 1); } else next[i] = Qnil; @@ -2825,82 +2828,98 @@ /* Given the set of bindings we've found, produce the next set of maps. */ if (first_binding < nmaps) for (i = 0; i < nmaps; i++) - next[i] = NILP (defs[i]) ? Qnil : get_keymap_1 (defs[i], 0); + next[i] = NILP (defs[i]) ? Qnil : get_keymap_1 (defs[i], 0, 1); return first_binding; } -/* Read a sequence of keys that ends with a non prefix character - according to the keymaps in KEYMAPS[0..nmaps-1]. Keymaps appearing - earlier in KEYMAPS take precidence over those appearing later. - - Store the sequence in KEYBUF, a buffer of size BUFSIZE. Prompt - with PROMPT. Echo starting immediately unless `prompt' is 0. +/* Read a sequence of keys that ends with a non prefix character, + storing it in KEYBUF, a buffer of size BUFSIZE. + Prompt with PROMPT. Return the length of the key sequence stored. - If the user switches frames in the midst of a key sequence, we - throw away any prefix we have read so far, and start afresh. For - mouse clicks, we look up the click in the keymap of the buffer - clicked on, throwing away any prefix if it is not the same buffer - we used to be reading from. */ - + Echo starting immediately unless `prompt' is 0. + + Where a key sequence ends depends on the currently active keymaps. + These include any minor mode keymaps active in the current buffer, + the current buffer's local map, and the global map. + + If a key sequence has no other bindings, we check Vfunction_key_map + to see if some trailing subsequence might be the beginning of a + function key's sequence. If so, we try to read the whole function + key, and substitute its symbolic name into the key sequence. + + We ignore unbound `down-' mouse clicks. We turn unbound `drag-' + events into similar click events, if that would make them bound. + + If we get a mouse click in a mode line, vertical divider, or other + non-text area, we treat the click as if it were prefixed by the + symbol denoting that area - `mode-line', `vertical-line', or + whatever. + + If the sequence starts with a mouse click, we read the key sequence + with respect to the buffer clicked on, not the current buffer. + + If the user switches frames in the midst of a key sequence, we put + off the switch-frame event until later; the next call to + read_char will return it. */ static int read_key_sequence (keybuf, bufsize, prompt) Lisp_Object *keybuf; int bufsize; - Lisp_Object prompt; + char *prompt; { + int count = specpdl_ptr - specpdl; + /* How many keys there are in the current key sequence. */ int t; - /* The buffer that the most recently read event was typed at. This - helps us read mouse clicks according to the buffer clicked in, - and notice when the mouse has moved from one frame to another. */ - struct buffer *last_event_buffer = current_buffer; - /* The length of the echo buffer when we started reading, and the length of this_command_keys when we started reading. */ int echo_start; - int keys_start = this_command_key_count; + int keys_start; /* The number of keymaps we're scanning right now, and the number of keymaps we have allocated space for. */ int nmaps; int nmaps_allocated = 0; - /* submaps[0..nmaps-1] are the prefix definitions of KEYBUF[0..t-1] - in the current keymaps, or nil where it is not a prefix. */ - Lisp_Object *submaps; - /* defs[0..nmaps-1] are the definitions of KEYBUF[0..t-1] in the current keymaps. */ Lisp_Object *defs; - /* The index of the first keymap that has a binding for this key - sequence. In other words, the lowest i such that defs[i] is - non-nil.*/ + /* submaps[0..nmaps-1] are the prefix definitions of KEYBUF[0..t-1] + in the current keymaps, or nil where it is not a prefix. */ + Lisp_Object *submaps; + + /* The index in defs[] of the first keymap that has a binding for + this key sequence. In other words, the lowest i such that + defs[i] is non-nil. */ int first_binding; - /* If mock_input > t, then KEYBUF[t] should be read as the next + /* If t < mock_input, then KEYBUF[t] should be read as the next input key. We use this to recover after recognizing a function key. Once we realize that a suffix of the current key sequence is actually a function key's escape sequence, we replace the suffix with the function key's binding from Vfunction_key_map. Now keybuf - contains a new and different key sequence, so the echo area and - the submaps and defs arrays are wrong. In this situation, we set - mock_input to t, set t to 0, and jump to restart; the loop will - read keys from keybuf up until mock_input, which rebuilds the - state, and then it will resume reading characters from the keyboard. */ + contains a new and different key sequence, so the echo area, + this_command_keys, and the submaps and defs arrays are wrong. In + this situation, we set mock_input to t, set t to 0, and jump to + restart_sequence; the loop will read keys from keybuf up until + mock_input, thus rebuilding the state; and then it will resume + reading characters from the keyboard. */ int mock_input = 0; /* If the sequence is unbound in submaps[], then - keymap[fkey_start..fkey_end-1] is a prefix in Vfunction_key_map, - and fkey_map is its binding. If mock_input is in use, these - might be > t, indicating that all function key scanning should - hold off until t reaches them. */ - + keybuf[fkey_start..fkey_end-1] is a prefix in Vfunction_key_map, + and fkey_map is its binding. + + These might be > t, indicating that all function key scanning + should hold off until t reaches them. We do this when we've just + recognized a function key, to avoid searching for the function + key's again in Vfunction_key_map. */ int fkey_start = 0, fkey_end = 0; Lisp_Object fkey_map = Vfunction_key_map; @@ -2908,6 +2927,15 @@ we put it off for later. While we're reading, we keep the event here. */ Lisp_Object delayed_switch_frame = Qnil; + + /* If there is no function key map, turn off function key scanning. */ + if (NILP (Fkeymapp (Vfunction_key_map))) + fkey_start = fkey_end = bufsize + 1; + + /* We need to save the current buffer in case we switch buffers to + find the right binding for a mouse click. */ + record_unwind_protect (save_excursion_restore, save_excursion_save ()); + last_nonmenu_event = Qnil; if (INTERACTIVE) @@ -2918,22 +2946,18 @@ /* This doesn't put in a dash if the echo buffer is empty, so you don't always see a dash hanging out in the minibuffer. */ echo_dash (); - echo_start = echo_length (); } - /* If there is no function key map, turn off function key scanning. */ - if (NILP (Fkeymapp (Vfunction_key_map))) - fkey_start = fkey_end = bufsize + 1; - - restart: - 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. */ + /* Record the initial state of the echo area and this_command_keys; + we will need to restore them if we replay a key sequence. */ if (INTERACTIVE) - echo_truncate (echo_start); - + echo_start = echo_length (); + keys_start = this_command_key_count; + + replay_sequence_new_buffer: + /* Build our list of keymaps. + If the sequence starts with a mouse click, we may need to switch buffers + and jump back here; that's what replay_sequence_new_buffer is for. */ { Lisp_Object *maps; @@ -2945,7 +2969,7 @@ nmaps_allocated = nmaps; } bcopy (maps, submaps, (nmaps - 2) * sizeof (submaps[0])); - submaps[nmaps-2] = last_event_buffer->keymap; + submaps[nmaps-2] = current_buffer->keymap; submaps[nmaps-1] = global_map; } @@ -2954,6 +2978,21 @@ if (! NILP (submaps[first_binding])) break; + replay_sequence: + /* We jump here when a function key substitution has forced us to + reprocess the current key sequence. keybuf[0..mock_input] is the + sequence we want to reread. */ + t = 0; + + /* These are no-ops the first time through, but if we restart, they + revert the echo area and this_command_keys to their original state. */ + this_command_key_count = keys_start; + if (INTERACTIVE) + echo_truncate (echo_start); + + /* If the best binding for the current key sequence is a keymap, + or we may be looking at a function key's escape sequence, keep + on reading. */ while ((first_binding < nmaps && ! NILP (submaps[first_binding])) || (first_binding >= nmaps && fkey_start < t)) { @@ -2964,23 +3003,27 @@ 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; - + int echo_local_start, keys_local_start, local_first_binding; + if (t >= bufsize) error ("key sequence too long"); - retry_key: + if (INTERACTIVE) + echo_local_start = echo_length (); + keys_local_start = this_command_key_count; + local_first_binding = first_binding; + + replay_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 + jumped back up to replay_key; in that case, these restore the + variables to their original state, allowing us to replay the loop. */ - echo_truncate (echo_local_start); + if (INTERACTIVE) + 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? */ + /* Does mock_input indicate that we are re-reading a key sequence? */ if (t < mock_input) { key = keybuf[t]; @@ -2991,33 +3034,64 @@ /* If not, we should actually read a character. */ else { - struct buffer *buf; - key = read_char (!prompt, nmaps, submaps, last_nonmenu_event, &used_mouse_menu); - /* The above routines return -1 at the end of a macro. + /* read_char returns -1 at the end of a macro. Emacs 18 handles this by returning immediately with a zero, so that's what we'll do. */ if (XTYPE (key) == Lisp_Int && XINT (key) < 0) { - unread_switch_frame = delayed_switch_frame; - return 0; + t = 0; + goto done; } 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'. */ + the mode line is prefixed by the symbol `mode-line'. + + Furthermore, key sequences beginning with mouse clicks + are read using the keymaps of the buffer clicked on, not + the current buffer. So we may have to switch the buffer + here. */ if (EVENT_HAS_PARAMETERS (key)) { Lisp_Object kind = EVENT_HEAD_KIND (EVENT_HEAD (key)); + if (EQ (kind, Qmouse_click)) { - Lisp_Object posn = POSN_BUFFER_POSN (EVENT_START (key)); - - if (XTYPE (posn) == Lisp_Symbol) + Lisp_Object window = POSN_WINDOW (EVENT_START (key)); + Lisp_Object posn = POSN_BUFFER_POSN (EVENT_START (key)); + + /* Key sequences beginning with mouse clicks are + read using the keymaps in the buffer clicked on, + not the current buffer. If we're at the + beginning of a key sequence, switch buffers. */ + if (t == 0 + && XTYPE (window) == Lisp_Window + && XTYPE (XWINDOW (window)->buffer) == Lisp_Buffer + && XBUFFER (XWINDOW (window)->buffer) != current_buffer) + { + 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; + } + else + { + keybuf[t] = key; + mock_input = t + 1; + } + + set_buffer_internal (XBUFFER (XWINDOW (window)->buffer)); + goto replay_sequence_new_buffer; + } + else if (XTYPE (posn) == Lisp_Symbol) { if (t + 1 >= bufsize) error ("key sequence too long"); @@ -3025,7 +3099,7 @@ keybuf[t+1] = key; mock_input = t + 2; - goto retry_key; + goto replay_key; } } else if (EQ (kind, Qswitch_frame)) @@ -3036,57 +3110,14 @@ if (t > 0) { delayed_switch_frame = key; - goto retry_key; + goto replay_key; } } } - -#if 0 /* This shouldn't be necessary any more, now that we have - switch-frame events. */ -#ifdef MULTI_FRAME - /* What buffer was this event typed/moused at? */ - if (used_mouse_menu) - /* Never change last_event_buffer for using a menu. */ - buf = last_event_buffer; - else if (XTYPE (key) == Lisp_Int || XTYPE (key) == Lisp_Symbol) - { - buf = ((XTYPE (Vlast_event_frame) == Lisp_Frame) - ? (XBUFFER - (XWINDOW - (FRAME_SELECTED_WINDOW - (XFRAME (Vlast_event_frame)))->buffer)) - : last_event_buffer); - } - else if (EVENT_HAS_PARAMETERS (key)) - { - Lisp_Object window = POSN_WINDOW (EVENT_START (key)); - - if (NILP (window)) - abort (); - - buf = XBUFFER (XWINDOW (window)->buffer); - } - else - abort (); - - /* If this event came to a different buffer than the one - we're currently in, switch buffers and start a new key - sequence, starting with key. */ - if (buf != last_event_buffer) - { - last_event_buffer = buf; - Fselect_frame (Vlast_event_frame, Qnil); - - /* Arrange to read key as the next event. */ - keybuf[0] = key; - mock_input = 1; - - goto restart; - } -#endif /* MULTI_FRAME */ -#endif /* 0 */ } - + + /* We have finally decided that KEY is something we might want + to look up. */ first_binding = (follow_key (key, nmaps - first_binding, submaps + first_binding, @@ -3094,7 +3125,7 @@ submaps + first_binding) + first_binding); - /* If this key wasn't bound, we'll try some fallbacks. */ + /* If KEY wasn't bound, we'll try some fallbacks. */ if (first_binding >= nmaps) { Lisp_Object head = EVENT_HEAD (key); @@ -3108,15 +3139,27 @@ /* 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. + /* To make sure that mock_input doesn't just give + this event back to us; we want to delete this + event from the mock input queue. We could delete + keybuf[t] and shift everything after that to the + left by one spot, but we'd also have to fix up + any variable that points into keybuf, and shifting + isn't really necessary anyway. + + Adding prefixes for non-textual mouse clicks creates + two characters of mock input, and this must be the + second, so mock_input would be over anyway; it's okay + to zero it. + + Beyond that, only function key expansion could + create more than two keys, but that should never + generate mouse events, so it's okay to zero + mock_input in that case too. + Isn't this just the most wonderful code ever? */ mock_input = 0; - goto retry_key; + goto replay_key; } /* We turn unbound `drag-' events into `click-' @@ -3159,7 +3202,7 @@ /* If the sequence is unbound, see if we can hang a function key off the end of it. We only want to scan real keyboard input for function key sequences, so if mock_input says that we're - re-scanning after expanding a function key, don't examine it. */ + re-reading old events, don't examine it. */ if (first_binding >= nmaps && t >= mock_input) { @@ -3168,20 +3211,26 @@ /* Scan from fkey_end until we find a bound suffix. */ while (fkey_end < t) { + Lisp_Object key; + + key = keybuf[fkey_end++]; /* Look up meta-characters by prefixing them with meta_prefix_char. I hate this. */ - if (keybuf[fkey_end] & 0x80) - fkey_next = - get_keymap_1 - ((get_keyelt - (access_keymap (fkey_map, meta_prefix_char, 1))), - 0); + if (XTYPE (key) == Lisp_Int && XINT (key) & 0x80) + { + fkey_next = + get_keymap_1 + (get_keyelt + (access_keymap + (fkey_map, meta_prefix_char, 1)), + 0, 1); + XFASTINT (key) = XFASTINT (key) & 0x7f; + } else fkey_next = fkey_map; fkey_next = - get_keyelt (access_keymap - (fkey_next, keybuf[fkey_end++] & 0x7f, 1)); + get_keyelt (access_keymap (fkey_next, key, 1)); /* If keybuf[fkey_start..fkey_end] is bound in the function key map and it's a suffix of the current @@ -3201,10 +3250,10 @@ mock_input = t; fkey_start = fkey_end = t; - goto restart; + goto replay_sequence; } - fkey_map = get_keymap_1 (fkey_next, 0); + fkey_map = get_keymap_1 (fkey_next, 0, 1); /* If we no longer have a bound suffix, try a new positions for fkey_start. */ @@ -3221,7 +3270,9 @@ ? defs[first_binding] : Qnil); + done: unread_switch_frame = delayed_switch_frame; + unbind_to (count, Qnil); return t; } @@ -3257,7 +3308,7 @@ this_command_key_count = 0; i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])), - NILP (prompt) ? 0 : XSTRING (prompt)->data); + NILP (prompt) ? 0 : XSTRING (prompt)->data); UNGCPRO; return make_array (i, keybuf);