/* Allow config.h to undefine symbols found here. */
#include <signal.h>
-#include "config.h"
+#include <config.h>
#include <stdio.h>
#undef NULL
#include "termchar.h"
#include <setjmp.h>
#include <errno.h>
+#ifdef MSDOS
+#include "msdos.h"
+#include <time.h>
+#else /* not MSDOS */
#ifndef VMS
#include <sys/ioctl.h>
#endif
+#endif /* not MSDOS */
#include "syssignal.h"
#include "systty.h"
/* Non-nil disable property on a command means
do not execute it; call disabled-command-hook's value instead. */
-Lisp_Object Qdisabled, Vdisabled_command_hook;
+Lisp_Object Qdisabled, Qdisabled_command_hook;
#define NUM_RECENT_KEYS (100)
int recent_keys_index; /* Index for storing next element into recent_keys */
/* True while displaying for echoing. Delays C-g throwing. */
static int echoing;
-/* Nonzero means C-G should cause immediate error-signal. */
+/* Nonzero means C-g should cause immediate error-signal. */
int immediate_quit;
/* Character to recognize as the help char. */
-Lisp_Object help_char;
+Lisp_Object Vhelp_char;
/* Form to execute when help char is typed. */
Lisp_Object Vhelp_form;
+/* Command to run when the help character follows a prefix key. */
+Lisp_Object Vprefix_help_command;
+
+/* List of items that should move to the end of the menu bar. */
+Lisp_Object Vmenu_bar_final_items;
+
/* Character that causes a quit. Normally C-g.
If we are running on an ordinary terminal, this must be an ordinary
extern Lisp_Object current_global_map;
extern int minibuf_level;
+/* If non-nil, this is a map that overrides all other local maps. */
+Lisp_Object Voverriding_local_map;
+
/* Current depth in recursive edits. */
int command_loop_level;
instead of the actual command. */
Lisp_Object this_command;
+/* The value of point when the last command was executed. */
+int last_point_position;
+
#ifdef MULTI_FRAME
/* The frame in which the last input event occurred, or Qmacro if the
last event came from a macro. We use this to determine when to
Lisp_Object Qself_insert_command;
Lisp_Object Qforward_char;
Lisp_Object Qbackward_char;
+Lisp_Object Qundefined;
/* read_key_sequence stores here the command definition of the
key sequence that it reads. */
/* Keymap mapping ASCII function key sequences onto their preferred forms. */
extern Lisp_Object Vfunction_key_map;
+/* Keymap mapping ASCII function key sequences onto their preferred forms. */
+Lisp_Object Vkey_translation_map;
+
/* Non-nil means deactivate the mark at end of this command. */
Lisp_Object Vdeactivate_mark;
/* Hooks to run before and after each command. */
Lisp_Object Qpre_command_hook, Qpost_command_hook;
Lisp_Object Vpre_command_hook, Vpost_command_hook;
+Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal;
/* File in which we write all commands we read. */
FILE *dribble;
Lisp_Object recursive_edit_unwind (), command_loop ();
Lisp_Object Fthis_command_keys ();
+Lisp_Object Qextended_command_history;
/* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
happens. */
#endif
#endif
-/* If we support X Windows, and won't get an interrupt when input
- arrives from the server, poll periodically so we can detect C-g. */
+/* If we support X Windows, turn on the code to poll periodically
+ to detect C-g. It isn't actually used when doing interrupt input. */
#ifdef HAVE_X_WINDOWS
-#ifndef SIGIO
#define POLL_FOR_INPUT
#endif
-#endif
\f
/* Global variable declarations. */
static int read_avail_input ();
static void get_input_pending ();
+static int readable_events ();
+static Lisp_Object read_char_x_menu_prompt ();
+static Lisp_Object read_char_minibuf_menu_prompt ();
+static Lisp_Object make_lispy_event ();
+static Lisp_Object make_lispy_movement ();
+static Lisp_Object modify_event_symbol ();
+static Lisp_Object make_lispy_switch_frame ();
/* > 0 if we are to echo keystrokes. */
static int echo_keystrokes;
/* Where to append more text to echobuf if we want to. */
static char *echoptr;
+/* Nonzero means don't try to suspend even if the operating system seems
+ to support it. */
+static int cannot_suspend;
+
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
ptr += name->size;
}
- if (echoptr == echobuf && EQ (c, help_char))
+ if (echoptr == echobuf && EQ (c, Vhelp_char))
{
strcpy (ptr, " (Type ? for further options)");
ptr += strlen (ptr);
{
echobuf[len] = '\0';
echoptr = echobuf + len;
+ truncate_echo_area (len);
}
\f
if (this_command_key_count >= size)
{
- Lisp_Object new_keys = Fmake_vector (make_number (size * 2), Qnil);
+ Lisp_Object new_keys;
+ new_keys = Fmake_vector (make_number (size * 2), Qnil);
bcopy (XVECTOR (this_command_keys)->contents,
XVECTOR (new_keys)->contents,
size * sizeof (Lisp_Object));
waiting_for_input = 0;
cancel_echoing ();
- /* Don't clear out last_command at the beginning of a macro. */
- if (XTYPE (Vexecuting_macro) != Lisp_String)
- last_command = Qt;
-
nonundocount = 0;
no_redisplay = 0;
this_command_key_count = 0;
+ /* Make sure this hook runs after commands that get errors and
+ throw to top level. */
+ if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
+ {
+ /* If we get an error during the post-command-hook,
+ cause post-command-hook to be nil. */
+ Vcommand_hook_internal = Vpost_command_hook;
+ Vpost_command_hook = Qnil;
+
+ call1 (Vrun_hooks, Qcommand_hook_internal);
+
+ Vpost_command_hook = Vcommand_hook_internal;
+ }
+
+ /* Do this after running Vpost_command_hook, for consistency. */
+ last_command = this_command;
+
while (1)
{
/* Install chars successfully executed in kbd macro. */
Vdeactivate_mark = Qnil;
/* If minibuffer on and echo area in use,
- wait 2 sec and redraw minibufer. */
+ wait 2 sec and redraw minibuffer. */
if (minibuf_level && echo_area_glyphs)
{
#endif
/* If it has changed current-menubar from previous value,
really recompute the menubar from the value. */
- if (! NILP (Vlucid_menu_bar_dirty_flag))
+ if (! NILP (Vlucid_menu_bar_dirty_flag)
+ && !NILP (Ffboundp (Qrecompute_lucid_menubar)))
call0 (Qrecompute_lucid_menubar);
-#if 0 /* This is done in xdisp.c now. */
-#ifdef MULTI_FRAME
- for (tem = Vframe_list; CONSP (tem); tem = XCONS (tem)->cdr)
- {
- struct frame *f = XFRAME (XCONS (tem)->car);
- struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
-
- /* If the user has switched buffers or windows, we need to
- recompute to reflect the new bindings. But we'll
- recompute when update_mode_lines is set too; that means
- that people can use force-mode-line-update to request
- that the menu bar be recomputed. The adverse effect on
- the rest of the redisplay algorithm is about the same as
- windows_or_buffers_changed anyway. */
- if (windows_or_buffers_changed
- || update_mode_lines
- || (XFASTINT (w->last_modified) < MODIFF
- && (XFASTINT (w->last_modified)
- <= XBUFFER (w->buffer)->save_modified)))
- {
- struct buffer *prev = current_buffer;
- current_buffer = XBUFFER (w->buffer);
- FRAME_MENU_BAR_ITEMS (f) = menu_bar_items ();
- current_buffer = prev;
- }
- }
-#endif /* MULTI_FRAME */
-#endif /* 0 */
-
/* Read next key sequence; i gets its length. */
- i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])), 0);
+ i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])), Qnil);
++num_input_keys;
if (i == 0) /* End of file -- happens only in */
return Qnil; /* a kbd macro, at the end. */
+ /* -1 means read_key_sequence got a menu that was rejected.
+ Just loop around and read another command. */
+ if (i == -1)
+ {
+ cancel_echoing ();
+ this_command_key_count = 0;
+ continue;
+ }
last_command_char = keybuf[i - 1];
}
/* Do redisplay processing after this command except in special
- cases identified below that set no_redisplay to 1. */
+ cases identified below that set no_redisplay to 1.
+ (actually, there's currently no way to prevent the redisplay,
+ and no_redisplay is ignored.
+ Perhaps someday we will really implement it. */
no_redisplay = 0;
prev_buffer = current_buffer;
prev_modiff = MODIFF;
+ last_point_position = PT;
/* Execute the command. */
this_command = cmd;
- if (!NILP (Vpre_command_hook))
- call1 (Vrun_hooks, Qpre_command_hook);
+ if (!NILP (Vpre_command_hook) && !NILP (Vrun_hooks))
+ {
+ /* If we get an error during the pre-command-hook,
+ cause pre-command-hook to be nil. */
+ Vcommand_hook_internal = Vpre_command_hook;
+ Vpre_command_hook = Qnil;
+
+ call1 (Vrun_hooks, Qcommand_hook_internal);
+
+ Vpre_command_hook = Vcommand_hook_internal;
+ }
if (NILP (this_command))
{
lose = FETCH_CHAR (point);
SET_PT (point + 1);
if ((dp
- ? (XTYPE (DISP_CHAR_VECTOR (dp, lose)) != Lisp_Vector
+ ? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
&& XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1)
: (lose >= 0x20 && lose < 0x7f))
&& (XFASTINT (XWINDOW (selected_window)->last_modified)
|| !EQ (current_buffer->selective_display, Qnil)
|| detect_input_pending ()
|| !NILP (Vexecuting_macro);
- if (internal_self_insert (XINT (c), 0))
+ if (internal_self_insert (c, 0))
{
lose = 1;
nonundocount = 0;
{
struct Lisp_Vector *dp
= window_display_table (XWINDOW (selected_window));
- int lose = XINT (c);
+ int lose = c;
if (dp)
{
- Lisp_Object obj = DISP_CHAR_VECTOR (dp, lose);
+ Lisp_Object obj;
+ obj = DISP_CHAR_VECTOR (dp, lose);
if (XTYPE (obj) == Lisp_Vector
&& XVECTOR (obj)->size == 1
&& (XTYPE (obj = XVECTOR (obj)->contents[0])
}
directly_done: ;
- if (!NILP (Vpost_command_hook))
- call1 (Vrun_hooks, Qpost_command_hook);
+ if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
+ {
+ /* If we get an error during the post-command-hook,
+ cause post-command-hook to be nil. */
+ Vcommand_hook_internal = Vpost_command_hook;
+ Vpost_command_hook = Qnil;
+
+ call1 (Vrun_hooks, Qcommand_hook_internal);
+
+ Vpost_command_hook = Vcommand_hook_internal;
+ }
/* If there is a prefix argument,
1) We don't want last_command to be ``universal-argument''
this_command_key_count = 0;
}
- if (!NILP (current_buffer->mark_active))
+ if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
{
if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
{
/* Number of seconds between polling for input. */
int polling_period;
-/* Nonzero means polling for input is temporarily suppresed. */
+/* Nonzero means polling for input is temporarily suppressed. */
int poll_suppress_count;
#ifdef POLL_FOR_INPUT
start_polling ()
{
#ifdef POLL_FOR_INPUT
- if (read_socket_hook)
+ if (read_socket_hook && !interrupt_input)
{
poll_suppress_count--;
if (poll_suppress_count == 0)
stop_polling ()
{
#ifdef POLL_FOR_INPUT
- if (read_socket_hook)
+ if (read_socket_hook && !interrupt_input)
{
if (poll_suppress_count == 0)
{
}
#endif
}
+
+/* Set the value of poll_suppress_count to COUNT
+ and start or stop polling accordingly. */
+
+void
+set_poll_suppress_count (count)
+ int count;
+{
+#ifdef POLL_FOR_INPUT
+ if (count == 0 && poll_suppress_count != 0)
+ {
+ poll_suppress_count = 1;
+ start_polling ();
+ }
+ else if (count != 0 && poll_suppress_count == 0)
+ {
+ stop_polling ();
+ }
+ poll_suppress_count = count;
+#endif
+}
\f
/* Applying the control modifier to CHARACTER. */
int
If USED_MOUSE_MENU is non-zero, then we set *USED_MOUSE_MENU to 1
if we used a mouse menu to read the input, or zero otherwise. If
- USED_MOUSE_MENU is zero, *USED_MOUSE_MENU is left alone. */
+ USED_MOUSE_MENU is zero, *USED_MOUSE_MENU is left alone.
+
+ Value is t if we showed a menu and the user rejected it. */
Lisp_Object
read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu)
remain unchanged.
Since this event came from a macro, it would be misleading to
- leave internal_last_event_frame set to whereever the last
+ leave internal_last_event_frame set to wherever the last
real event came from. Normally, a switch-frame event selects
internal_last_event_frame after each command is read, but
events read from a macro should never cause a new frame to be
goto reread_first;
}
+ if (commandflag >= 0 && !input_pending && !detect_input_pending ())
+ prepare_menu_bars ();
+
/* Save outer setjmp data, in case called recursively. */
save_getcjmp (save_jump);
/* If already echoing, continue. */
echo_dash ();
+ /* Try reading a character via menu prompting in the minibuf.
+ Try this before the sit-for, because the sit-for
+ would do the wrong thing if we are supposed to do
+ menu prompting. If EVENT_HAS_PARAMETERS then we are reading
+ after a mouse event so don't try a minibuf menu. */
+ c = Qnil;
+ if (nmaps > 0 && INTERACTIVE &&
+ !NILP (prev_event) && ! EVENT_HAS_PARAMETERS (prev_event))
+ {
+ c = read_char_minibuf_menu_prompt (commandflag, nmaps, maps);
+ if ( ! NILP(c) ) return c ;
+ }
+
/* If in middle of key sequence and minibuffer not active,
start echoing if enough time elapses. */
if (minibuf_level == 0 && !immediate_echo && this_command_key_count > 0
+ && ! noninteractive
&& echo_keystrokes > 0
&& (echo_area_glyphs == 0 || *echo_area_glyphs == 0))
{
restore_getcjmp (temp);
}
- /* Try reading a character via menu prompting.
- Try this before the sit-for, because the sit-for
- would do the wrong thing if we are supposed to do
- menu prompting. */
- c = Qnil;
- if (INTERACTIVE && !NILP (prev_event))
- c = read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
+ /* Try reading using an X menu.
+ This is never confused with reading using the minibuf because the recursive
+ call of read_char in read_char_minibuf_menu_prompt does not pass on
+ any keys maps */
+ if (nmaps > 0 && INTERACTIVE &&
+ !NILP (prev_event) && EVENT_HAS_PARAMETERS (prev_event))
+ c = read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu);
/* Slow down auto saves logarithmically in size of current buffer,
and garbage collect while we're at it. */
- if (NILP (c))
+ if (INTERACTIVE && NILP (c))
{
int delay_level, buffer_size;
consing going on to make it worthwhile. */
if (!detect_input_pending ()
&& consing_since_gc > gc_cons_threshold / 2)
- Fgarbage_collect ();
+ {
+ Fgarbage_collect ();
+ /* prepare_menu_bars isn't safe here, but it should
+ also be unnecessary. */
+ redisplay ();
+ }
}
}
}
/* Actually read a character, waiting if necessary. */
- if (NILP (c))
- c = kbd_buffer_get_event ();
-
- if (NILP (c))
- abort (); /* Don't think this can happen. */
+ while (NILP (c))
+ {
+ c = kbd_buffer_get_event ();
+ if (!NILP (c))
+ break;
+ if (commandflag >= 0 && !input_pending && !detect_input_pending ())
+ redisplay ();
+ }
/* Terminate Emacs in batch mode if at eof. */
if (noninteractive && XTYPE (c) == Lisp_Int && XINT (c) < 0)
/* Transfer any other modifier bits directly from
extra_keyboard_modifiers to c. Ignore the actual character code
in the low 16 bits of extra_keyboard_modifiers. */
- c |= (extra_keyboard_modifiers & ~0xff7f & ~CHAR_CTL);
+ XSETINT (c, XINT (c) | (extra_keyboard_modifiers & ~0xff7f & ~CHAR_CTL));
}
non_reread:
putc (XINT (c), dribble);
else
{
- Lisp_Object dribblee = c;
+ Lisp_Object dribblee;
/* If it's a structured event, take the event header. */
- dribblee = EVENT_HEAD (dribblee);
+ dribblee = EVENT_HEAD (c);
if (XTYPE (dribblee) == Lisp_Symbol)
{
num_input_chars++;
/* Process the help character specially if enabled */
- if (EQ (c, help_char) && !NILP (Vhelp_form))
+ if (EQ (c, Vhelp_char) && !NILP (Vhelp_form))
{
Lisp_Object tem0;
count = specpdl_ptr - specpdl;
internal_with_output_to_temp_buffer ("*Help*", print_help, tem0);
cancel_echoing ();
- c = read_char (0, 0, 0, Qnil, 0);
+ do
+ c = read_char (0, 0, 0, Qnil, 0);
+ while (XTYPE (c) == Lisp_Buffer);
/* Remove the help from the frame */
unbind_to (count, Qnil);
+ prepare_menu_bars ();
redisplay ();
if (EQ (c, make_number (040)))
{
cancel_echoing ();
- c = read_char (0, 0, 0, Qnil, 0);
+ do
+ c = read_char (0, 0, 0, Qnil, 0);
+ while (XTYPE (c) == Lisp_Buffer);
}
}
}
\f
-/* Low level keyboard/mouse input.
- kbd_buffer_store_event places events in kbd_buffer, and
- kbd_buffer_get_event retrieves them.
- mouse_moved indicates when the mouse has moved again, and
- *mouse_position_hook provides the mouse position. */
-
-/* Set this for debugging, to have a way to get out */
-int stop_character;
-
-extern int frame_garbaged;
-
-/* Return true iff there are any events in the queue that read-char
- would return. If this returns false, a read-char would block. */
-static int
-readable_events ()
-{
- return ! EVENT_QUEUES_EMPTY;
-}
-
-
/* Restore mouse tracking enablement. See Ftrack_mouse for the only use
of this function. */
static Lisp_Object
redisplay. */
if (!readable_events ())
{
+ prepare_menu_bars ();
redisplay_preserve_echo_area ();
get_input_pending (&input_pending);
}
val = Fprogn (args);
return unbind_to (count, val);
}
+\f
+/* Low level keyboard/mouse input.
+ kbd_buffer_store_event places events in kbd_buffer, and
+ kbd_buffer_get_event retrieves them.
+ mouse_moved indicates when the mouse has moved again, and
+ *mouse_position_hook provides the mouse position. */
+
+/* Return true iff there are any events in the queue that read-char
+ would return. If this returns false, a read-char would block. */
+static int
+readable_events ()
+{
+ return ! EVENT_QUEUES_EMPTY;
+}
+
+/* Set this for debugging, to have a way to get out */
+int stop_character;
/* Store an event obtained at interrupt level into kbd_buffer, fifo */
if (event->kind == ascii_keystroke)
{
- register int c = XFASTINT (event->code) & 0377;
+ register int c = event->code & 0377;
if (event->modifiers & ctrl_modifier)
c = make_ctrl_char (c);
+ c |= (event->modifiers
+ & (meta_modifier | alt_modifier
+ | hyper_modifier | super_modifier));
+
if (c == quit_char)
{
extern SIGTYPE interrupt_signal ();
get returned to Emacs as an event, the next event read
will set Vlast_event_frame again, so this is safe to do. */
{
- Lisp_Object focus =
- FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window));
+ Lisp_Object focus;
+ focus = FRAME_FOCUS_FRAME (XFRAME (event->frame_or_window));
if (NILP (focus))
internal_last_event_frame = event->frame_or_window;
else
sys_suspend ();
return;
}
-
- XSET (event->code, Lisp_Int, c);
}
if (kbd_store_ptr - kbd_buffer == KBD_BUFFER_SIZE)
if (kbd_fetch_ptr - 1 != kbd_store_ptr)
{
kbd_store_ptr->kind = event->kind;
- kbd_store_ptr->code = event->code;
- kbd_store_ptr->part = event->part;
- kbd_store_ptr->frame_or_window = event->frame_or_window;
- kbd_store_ptr->modifiers = event->modifiers;
- kbd_store_ptr->x = event->x;
- kbd_store_ptr->y = event->y;
- kbd_store_ptr->timestamp = event->timestamp;
+ if (event->kind == selection_request_event)
+ {
+ /* We must not use the ordinary copying code for this case,
+ since `part' is an enum and copying it might not copy enough
+ in this case. */
+ bcopy (event, kbd_store_ptr, sizeof (*event));
+ }
+ else
+ {
+ kbd_store_ptr->code = event->code;
+ kbd_store_ptr->part = event->part;
+ kbd_store_ptr->frame_or_window = event->frame_or_window;
+ kbd_store_ptr->modifiers = event->modifiers;
+ kbd_store_ptr->x = event->x;
+ kbd_store_ptr->y = event->y;
+ kbd_store_ptr->timestamp = event->timestamp;
+ }
(XVECTOR (kbd_buffer_frame_or_window)->contents[kbd_store_ptr
- kbd_buffer]
= event->frame_or_window);
kbd_store_ptr++;
}
}
-
-static Lisp_Object make_lispy_event ();
-static Lisp_Object make_lispy_movement ();
-static Lisp_Object modify_event_symbol ();
-static Lisp_Object make_lispy_switch_frame ();
+\f
+/* Read one event from the event buffer, waiting if necessary.
+ The value is a Lisp object representing the event.
+ The value is nil for an event that should be ignored,
+ or that was handled here.
+ We always read and discard one event. */
static Lisp_Object
kbd_buffer_get_event ()
return obj;
}
- retry:
/* Wait until there is input available. */
for (;;)
{
wait_reading_process_input (0, 0, minus_one, 1);
if (!interrupt_input && EVENT_QUEUES_EMPTY)
- {
- read_avail_input (0);
- }
+ /* Pass 1 for EXPECT since we just waited to have input. */
+ read_avail_input (1);
}
#endif /* not VMS */
}
obj = Qnil;
/* These two kinds of events get special handling
- and don't actually appear to the command loop. */
+ and don't actually appear to the command loop.
+ We return nil for them. */
if (event->kind == selection_request_event)
{
#ifdef HAVE_X11
x_handle_selection_request (event);
kbd_fetch_ptr = event + 1;
- goto retry;
#else
/* We're getting selection request events, but we don't have
a window system. */
#endif
}
- if (event->kind == selection_clear_event)
+ else if (event->kind == selection_clear_event)
{
#ifdef HAVE_X11
x_handle_selection_clear (event);
kbd_fetch_ptr = event + 1;
- goto retry;
#else
/* We're getting selection request events, but we don't have
a window system. */
abort ();
#endif
}
+#ifdef HAVE_X11
+ else if (event->kind == delete_window_event)
+ {
+ Lisp_Object tail, frame;
+ struct frame *f;
+
+ /* If the user destroys the only frame, Emacs should exit.
+ Count visible frames and iconified frames. */
+ for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
+ {
+ frame = XCONS (tail)->car;
+ if (XTYPE (frame) != Lisp_Frame || EQ (frame, event->frame_or_window))
+ continue;
+ f = XFRAME (frame);
+ if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
+ break;
+ }
+
+ if (! CONSP (tail))
+ Fkill_emacs (Qnil);
+
+ Fdelete_frame (event->frame_or_window, Qt);
+ kbd_fetch_ptr = event + 1;
+ }
+#endif
+ else if (event->kind == buffer_switch_event)
+ {
+ /* The value doesn't matter here; only the type is tested. */
+ XSET (obj, Lisp_Buffer, current_buffer);
+ kbd_fetch_ptr = event + 1;
+ }
+ /* Just discard these, by returning nil.
+ (They shouldn't be found in the buffer,
+ but on some machines it appears they do show up.) */
+ else if (event->kind == no_event)
+ kbd_fetch_ptr = event + 1;
-#ifdef MULTI_FRAME
/* If this event is on a different frame, return a switch-frame this
time, and leave the event in the queue for next time. */
- {
- Lisp_Object frame = event->frame_or_window;
- Lisp_Object focus;
+ else
+ {
+#ifdef MULTI_FRAME
+ Lisp_Object frame;
+ Lisp_Object focus;
- if (XTYPE (frame) == Lisp_Window)
- frame = WINDOW_FRAME (XWINDOW (frame));
+ frame = event->frame_or_window;
+ if (XTYPE (frame) == Lisp_Window)
+ frame = WINDOW_FRAME (XWINDOW (frame));
- focus = FRAME_FOCUS_FRAME (XFRAME (frame));
- if (! NILP (focus))
- frame = focus;
+ focus = FRAME_FOCUS_FRAME (XFRAME (frame));
+ if (! NILP (focus))
+ frame = focus;
- if (! EQ (frame, internal_last_event_frame)
- && XFRAME (frame) != selected_frame)
- obj = make_lispy_switch_frame (frame);
- internal_last_event_frame = frame;
- }
-#endif
+ if (! EQ (frame, internal_last_event_frame)
+ && XFRAME (frame) != selected_frame)
+ obj = make_lispy_switch_frame (frame);
+ internal_last_event_frame = frame;
+#endif /* MULTI_FRAME */
- /* If we didn't decide to make a switch-frame event, go ahead
- and build a real event from the queue entry. */
- if (NILP (obj))
- {
- obj = make_lispy_event (event);
-
- /* Wipe out this event, to catch bugs. */
- event->kind = no_event;
- (XVECTOR (kbd_buffer_frame_or_window)->contents[event - kbd_buffer]
- = Qnil);
+ /* If we didn't decide to make a switch-frame event, go ahead
+ and build a real event from the queue entry. */
- kbd_fetch_ptr = event + 1;
+ if (NILP (obj))
+ {
+ obj = make_lispy_event (event);
+
+ /* Wipe out this event, to catch bugs. */
+ event->kind = no_event;
+ (XVECTOR (kbd_buffer_frame_or_window)->contents[event - kbd_buffer]
+ = Qnil);
+
+ kbd_fetch_ptr = event + 1;
+ }
}
}
+ /* Try generating a mouse motion event. */
else if (do_mouse_tracking && mouse_moved)
{
- FRAME_PTR f;
+ FRAME_PTR f = 0;
Lisp_Object bar_window;
enum scroll_bar_part part;
Lisp_Object x, y;
frames. */
if (f)
{
- Lisp_Object frame = FRAME_FOCUS_FRAME (f);
+ Lisp_Object frame;
+ frame = FRAME_FOCUS_FRAME (f);
if (NILP (frame))
XSET (frame, Lisp_Frame, f);
if (! EQ (frame, internal_last_event_frame)
&& XFRAME (frame) != selected_frame)
- obj = make_lispy_switch_frame (internal_last_event_frame);
+ obj = make_lispy_switch_frame (frame);
internal_last_event_frame = frame;
}
#endif
something for us to read! */
abort ();
- /* If something gave back nil as the Lispy event,
- it means the event was discarded, so try again. */
- if (NILP (obj))
- goto retry;
-
input_pending = readable_events ();
#ifdef MULTI_FRAME
return (obj);
}
+\f
+/* Process any events that are not user-visible,
+ then return, without reading any user-visible events. */
+
+void
+swallow_events ()
+{
+ while (kbd_fetch_ptr != kbd_store_ptr)
+ {
+ struct input_event *event;
+
+ event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
+ ? kbd_fetch_ptr
+ : kbd_buffer);
+
+ last_event_timestamp = event->timestamp;
+
+ /* These two kinds of events get special handling
+ and don't actually appear to the command loop. */
+ if (event->kind == selection_request_event)
+ {
+#ifdef HAVE_X11
+ x_handle_selection_request (event);
+ kbd_fetch_ptr = event + 1;
+#else
+ /* We're getting selection request events, but we don't have
+ a window system. */
+ abort ();
+#endif
+ }
+ else if (event->kind == selection_clear_event)
+ {
+#ifdef HAVE_X11
+ x_handle_selection_clear (event);
+ kbd_fetch_ptr = event + 1;
+#else
+ /* We're getting selection request events, but we don't have
+ a window system. */
+ abort ();
+#endif
+ }
+ else
+ break;
+ }
+ get_input_pending (&input_pending);
+}
+\f
/* Caches for modify_event_symbol. */
+static Lisp_Object accent_key_syms;
+static Lisp_Object system_key_syms;
static Lisp_Object func_key_syms;
static Lisp_Object mouse_syms;
+Lisp_Object Vsystem_key_alist;
+
+/* This is a list of keysym codes for special "accent" characters.
+ It parallels lispy_accent_keys. */
+
+static int lispy_accent_codes[] =
+{
+#ifdef XK_dead_circumflex
+ XK_dead_circumflex,
+#else
+ 0,
+#endif
+#ifdef XK_dead_grave
+ XK_dead_grave,
+#else
+ 0,
+#endif
+#ifdef XK_dead_tilde
+ XK_dead_tilde,
+#else
+ 0,
+#endif
+#ifdef XK_dead_diaeresis
+ XK_dead_diaeresis,
+#else
+ 0,
+#endif
+#ifdef XK_dead_macron
+ XK_dead_macron,
+#else
+ 0,
+#endif
+#ifdef XK_dead_degree
+ XK_dead_degree,
+#else
+ 0,
+#endif
+#ifdef XK_dead_acute
+ XK_dead_acute,
+#else
+ 0,
+#endif
+#ifdef XK_dead_cedilla
+ XK_dead_cedilla,
+#else
+ 0,
+#endif
+#ifdef XK_dead_breve
+ XK_dead_breve,
+#else
+ 0,
+#endif
+#ifdef XK_dead_ogonek
+ XK_dead_ogonek,
+#else
+ 0,
+#endif
+#ifdef XK_dead_caron
+ XK_dead_caron,
+#else
+ 0,
+#endif
+#ifdef XK_dead_doubleacute
+ XK_dead_doubleacute,
+#else
+ 0,
+#endif
+#ifdef XK_dead_abovedot
+ XK_dead_abovedot,
+#else
+ 0,
+#endif
+};
+
+/* This is a list of Lisp names for special "accent" characters.
+ It parallels lispy_accent_codes. */
+
+static char *lispy_accent_keys[] =
+{
+ "dead-circumflex",
+ "dead-grave",
+ "dead-tilde",
+ "dead-diaeresis",
+ "dead-macron",
+ "dead-degree",
+ "dead-acute",
+ "dead-cedilla",
+ "dead-breve",
+ "dead-ogonek",
+ "dead-caron",
+ "dead-doubleacute",
+ "dead-abovedot",
+};
+
/* You'll notice that this table is arranged to be conveniently
indexed by X Windows keysym values. */
static char *lispy_function_keys[] =
"help",
"break", /* 0xff6b */
- /* Here are some keys found mostly on HP keyboards. The X event
- handling code will strip bit 29, which flags vendor-specific
- keysyms. */
- "reset", /* 0x1000ff6c */
- "system",
- "user",
- "clearline",
- "insertline",
- "deleteline",
- "insertchar",
- "deletechar",
- "backtab",
- "kp_backtab", /* 0x1000ff75 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, /* 0xff76 */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xff7f */
+ 0, 0, 0, 0, 0, 0, 0, 0, "kp-numlock", /* 0xff7f */
"kp-space", /* 0xff80 */ /* IsKeypadKey */
0, 0, 0, 0, 0, 0, 0, 0,
"kp-tab", /* 0xff89 */
static Lisp_Object button_down_location;
+/* Information about the most recent up-going button event: Which
+ button, what location, and what time. */
+
+static int last_mouse_button;
+static int last_mouse_x;
+static int last_mouse_y;
+static unsigned long button_down_time;
+
+/* The maximum time between clicks to make a double-click,
+ or Qnil to disable double-click detection,
+ or Qt for no time limit. */
+Lisp_Object Vdouble_click_time;
+
+/* The number of clicks in this multiple-click. */
+
+int double_click_count;
+
+#ifdef USE_X_TOOLKIT
+extern Lisp_Object map_event_to_object ();
+#endif /* USE_X_TOOLKIT */
+
/* Given a struct input_event, build the lisp event which represents
it. If EVENT is 0, build a mouse movement event from the mouse
movement buffer, which should have a movement event in it.
make_lispy_event (event)
struct input_event *event;
{
+ int i;
+
#ifdef SWITCH_ENUM_BUG
switch ((int) event->kind)
#else
/* A simple keystroke. */
case ascii_keystroke:
{
- int c = XFASTINT (event->code);
+ int c = event->code & 0377;
/* Turn ASCII characters into control characters
when proper. */
if (event->modifiers & ctrl_modifier)
c |= (event->modifiers
& (meta_modifier | alt_modifier
| hyper_modifier | super_modifier));
+ button_down_time = 0;
return c;
}
/* A function key. The symbol may need to have modifier prefixes
tacked onto it. */
case non_ascii_keystroke:
- return modify_event_symbol (XFASTINT (event->code), event->modifiers,
- Qfunction_key,
+ button_down_time = 0;
+
+ for (i = 0; i < sizeof (lispy_accent_codes) / sizeof (int); i++)
+ if (event->code == lispy_accent_codes[i])
+ return modify_event_symbol (i,
+ event->modifiers,
+ Qfunction_key, Qnil,
+ lispy_accent_keys, &accent_key_syms,
+ (sizeof (lispy_accent_keys)
+ / sizeof (lispy_accent_keys[0])));
+
+ /* Handle system-specific keysyms. */
+ if (event->code & (1 << 28))
+ {
+ /* We need to use an alist rather than a vector as the cache
+ since we can't make a vector long enuf. */
+ if (NILP (system_key_syms))
+ system_key_syms = Fcons (Qnil, Qnil);
+ return modify_event_symbol (event->code & 0xffffff,
+ event->modifiers,
+ Qfunction_key, Vsystem_key_alist,
+ 0, &system_key_syms, 0xffffff);
+ }
+
+ return modify_event_symbol (event->code - 0xff00,
+ event->modifiers,
+ Qfunction_key, Qnil,
lispy_function_keys, &func_key_syms,
(sizeof (lispy_function_keys)
/ sizeof (lispy_function_keys[0])));
case mouse_click:
case scroll_bar_click:
{
- int button = XFASTINT (event->code);
+ int button = event->code;
+ int is_double;
Lisp_Object position;
Lisp_Object *start_pos_ptr;
Lisp_Object start_pos;
{
int part;
FRAME_PTR f = XFRAME (event->frame_or_window);
- Lisp_Object window
- = window_from_coordinates (f, XINT (event->x), XINT (event->y),
- &part);
+ Lisp_Object window;
Lisp_Object posn;
+ int row, column;
+
+ pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
+ &column, &row, 0, 0);
- if (XINT (event->y) < FRAME_MENU_BAR_LINES (f))
+#ifdef USE_X_TOOLKIT
+ if (FRAME_EXTERNAL_MENU_BAR (f) && XINT (event->y) == -1)
+#else
+ if (row < FRAME_MENU_BAR_LINES (f))
+#endif
{
+ Lisp_Object items, item;
+
+#ifdef USE_X_TOOLKIT
+ /* The click happened in the menubar.
+ Look for the menu item selected. */
+ item = map_event_to_object (event, f);
+
+ XFASTINT (event->y) = 1;
+#else /* not USE_X_TOOLKIT */
int hpos;
- Lisp_Object items;
+ int i;
+
items = FRAME_MENU_BAR_ITEMS (f);
- for (; CONSP (items); items = XCONS (items)->cdr)
+ for (i = 0; i < XVECTOR (items)->size; i += 3)
{
Lisp_Object pos, string;
- pos = Fcdr (Fcdr (Fcar (items)));
- string = Fcar (Fcdr (Fcar (items)));
- if (XINT (event->x) > XINT (pos)
- && XINT (event->x) <= XINT (pos) + XSTRING (string)->size)
+ string = XVECTOR (items)->contents[i + 1];
+ pos = XVECTOR (items)->contents[i + 2];
+ if (NILP (string))
break;
+ if (column >= XINT (pos)
+ && column < XINT (pos) + XSTRING (string)->size)
+ {
+ item = XVECTOR (items)->contents[i];
+ break;
+ }
}
+#endif /* not USE_X_TOOLKIT */
+
position
= Fcons (event->frame_or_window,
Fcons (Qmenu_bar,
Fcons (make_number (event->timestamp),
Qnil))));
- if (CONSP (items))
- return Fcons (Fcar (Fcar (items)),
- Fcons (position, Qnil));
- else
- return Fcons (Qnil, Fcons (position, Qnil));
+ return Fcons (item, Fcons (position, Qnil));
}
- else if (XTYPE (window) != Lisp_Window)
+
+ window = window_from_coordinates (f, column, row, &part);
+
+ if (XTYPE (window) != Lisp_Window)
posn = Qnil;
else
{
- XSETINT (event->x,
- (XINT (event->x) - XINT (XWINDOW (window)->left)));
- XSETINT (event->y,
- (XINT (event->y) - XINT (XWINDOW (window)->top)));
+ int pixcolumn, pixrow;
+ column -= XINT (XWINDOW (window)->left);
+ row -= XINT (XWINDOW (window)->top);
+ glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
+ XSETINT (event->x, pixcolumn);
+ XSETINT (event->y, pixrow);
if (part == 1)
posn = Qmode_line;
else
XSET (posn, Lisp_Int,
buffer_posn_from_coords (XWINDOW (window),
- XINT (event->x),
- XINT (event->y)));
+ column, row));
}
position
}
else
{
- Lisp_Object window = event->frame_or_window;
- Lisp_Object portion_whole = Fcons (event->x, event->y);
- Lisp_Object part = *scroll_bar_parts[(int) event->part];
+ Lisp_Object window;
+ Lisp_Object portion_whole;
+ Lisp_Object part;
+
+ window = event->frame_or_window;
+ portion_whole = Fcons (event->x, event->y);
+ part = *scroll_bar_parts[(int) event->part];
position =
Fcons (window,
Fcons (Qvertical_scroll_bar,
Fcons (portion_whole,
Fcons (make_number (event->timestamp),
- Fcons (part,
- Qnil)))));
+ Fcons (part, Qnil)))));
}
start_pos_ptr = &XVECTOR (button_down_location)->contents[button];
start_pos = *start_pos_ptr;
*start_pos_ptr = Qnil;
+ is_double = (button == last_mouse_button
+ && XINT (event->x) == last_mouse_x
+ && XINT (event->y) == last_mouse_y
+ && button_down_time != 0
+ && (EQ (Vdouble_click_time, Qt)
+ || (INTEGERP (Vdouble_click_time)
+ && ((int)(event->timestamp - button_down_time)
+ < XINT (Vdouble_click_time)))));
+ last_mouse_button = button;
+ last_mouse_x = XINT (event->x);
+ last_mouse_y = XINT (event->y);
+
/* If this is a button press, squirrel away the location, so
we can decide later whether it was a click or a drag. */
if (event->modifiers & down_modifier)
- *start_pos_ptr = Fcopy_alist (position);
+ {
+ if (is_double)
+ {
+ double_click_count++;
+ event->modifiers |= ((double_click_count > 2)
+ ? triple_modifier
+ : double_modifier);
+ }
+ else
+ double_click_count = 1;
+ button_down_time = event->timestamp;
+ *start_pos_ptr = Fcopy_alist (position);
+ }
/* Now we're releasing a button - check the co-ordinates to
see if this was a click or a drag. */
{
/* The third element of every position should be the (x,y)
pair. */
- Lisp_Object down = Fnth (make_number (2), start_pos);
+ Lisp_Object down;
- event->modifiers |= ((EQ (event->x, XCONS (down)->car)
- && EQ (event->y, XCONS (down)->cdr))
- ? click_modifier
- : drag_modifier);
+ down = Fnth (make_number (2), start_pos);
+ if (EQ (event->x, XCONS (down)->car)
+ && EQ (event->y, XCONS (down)->cdr))
+ {
+ if (is_double && double_click_count > 1)
+ event->modifiers |= ((double_click_count > 2)
+ ? triple_modifier
+ : double_modifier);
+ else
+ event->modifiers |= click_modifier;
+ }
+ else
+ {
+ button_down_time = 0;
+ event->modifiers |= drag_modifier;
+ }
}
}
else
{
/* Get the symbol we should use for the mouse click. */
- Lisp_Object head
- = modify_event_symbol (button,
- event->modifiers,
- Qmouse_click,
- lispy_mouse_names, &mouse_syms,
- (sizeof (lispy_mouse_names)
- / sizeof (lispy_mouse_names[0])));
-
+ Lisp_Object head;
+
+ head = modify_event_symbol (button,
+ event->modifiers,
+ Qmouse_click, Qnil,
+ lispy_mouse_names, &mouse_syms,
+ (sizeof (lispy_mouse_names)
+ / sizeof (lispy_mouse_names[0])));
if (event->modifiers & drag_modifier)
return Fcons (head,
Fcons (start_pos,
Fcons (position,
Qnil)));
+ else if (event->modifiers & (double_modifier | triple_modifier))
+ return Fcons (head,
+ Fcons (position,
+ Fcons (make_number (double_click_count),
+ Qnil)));
else
return Fcons (head,
Fcons (position,
/* Is it a scroll bar movement? */
if (frame && ! NILP (bar_window))
{
- Lisp_Object part_sym = *scroll_bar_parts[(int) part];
+ Lisp_Object part_sym;
+ part_sym = *scroll_bar_parts[(int) part];
return Fcons (Qscroll_bar_movement,
(Fcons (Fcons (bar_window,
Fcons (Qvertical_scroll_bar,
else
{
int area;
- Lisp_Object window =
- (frame
- ? window_from_coordinates (frame, XINT (x), XINT (y), &area)
- : Qnil);
+ Lisp_Object window;
Lisp_Object posn;
+ int column, row;
+
+ pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row, 0, 0);
+
+ if (frame)
+ window = window_from_coordinates (frame, column, row, &area);
+ else
+ window = Qnil;
if (XTYPE (window) == Lisp_Window)
{
- XSETINT (x, XINT (x) - XINT (XWINDOW (window)->left));
- XSETINT (y, XINT (y) - XINT (XWINDOW (window)->top));
+ int pixcolumn, pixrow;
+ column -= XINT (XWINDOW (window)->left);
+ row -= XINT (XWINDOW (window)->top);
+ glyph_to_pixel_coords (frame, column, row, &pixcolumn, &pixrow);
+ XSETINT (x, pixcolumn);
+ XSETINT (y, pixrow);
if (area == 1)
posn = Qmode_line;
posn = Qvertical_line;
else
XSET (posn, Lisp_Int,
- buffer_posn_from_coords (XWINDOW (window),
- XINT (x), XINT (y)));
+ buffer_posn_from_coords (XWINDOW (window), column, row));
+ }
+ else if (frame != 0)
+ {
+ XSET (window, Lisp_Frame, frame);
+ posn = Qnil;
}
else
{
modifiers |= down_modifier;
i += 5;
}
+ else if (i + 7 <= name->size
+ && ! strncmp (name->data + i, "double-", 7))
+ {
+ modifiers |= double_modifier;
+ i += 7;
+ }
+ else
+ goto no_more_modifiers;
+ break;
+
+ case 't':
+ if (i + 7 > name->size)
+ goto no_more_modifiers;
+ if (! strncmp (name->data + i, "triple-", 7))
+ {
+ modifiers |= triple_modifier;
+ i += 7;
+ }
else
goto no_more_modifiers;
break;
no_more_modifiers:
/* Should we include the `click' modifier? */
- if (! (modifiers & (down_modifier | drag_modifier))
+ if (! (modifiers & (down_modifier | drag_modifier
+ | double_modifier | triple_modifier))
&& i + 7 == name->size
&& strncmp (name->data + i, "mouse-", 6) == 0
&& ('0' <= name->data[i + 6] && name->data[i + 6] <= '9'))
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-s-down-drag-"));
+ (char *) alloca (sizeof ("A-C-H-M-S-s-down-drag-double-triple-"));
int mod_len;
{
if (modifiers & meta_modifier) { *p++ = 'M'; *p++ = '-'; }
if (modifiers & shift_modifier) { *p++ = 'S'; *p++ = '-'; }
if (modifiers & super_modifier) { *p++ = 's'; *p++ = '-'; }
+ if (modifiers & double_modifier) { strcpy (p, "double-"); p += 7; }
+ if (modifiers & triple_modifier) { strcpy (p, "triple-"); p += 7; }
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. */
}
{
- Lisp_Object new_name = make_uninit_string (mod_len + base_len);
+ Lisp_Object new_name;
+ 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);
static char *modifier_names[] =
{
- "up", "down", "drag", "click", 0, 0, 0, 0,
+ "up", "down", "drag", "click", "double", "triple", 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, "alt", "super", "hyper", "shift", "control", "meta"
};
parse_modifiers (symbol)
Lisp_Object symbol;
{
- Lisp_Object elements = Fget (symbol, Qevent_symbol_element_mask);
+ Lisp_Object elements;
+ 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 unmodified;
Lisp_Object mask;
+ unmodified = Fintern (make_string (XSYMBOL (symbol)->name->data + end,
+ XSYMBOL (symbol)->name->size - end),
+ Qnil);
+
if (modifiers & ~((1<<VALBITS) - 1))
abort ();
XFASTINT (mask) = modifiers;
Qevent_kind set right as well. */
if (NILP (Fget (new_symbol, Qevent_kind)))
{
- Lisp_Object kind = Fget (base, Qevent_kind);
+ Lisp_Object kind;
+ kind = Fget (base, Qevent_kind);
if (! NILP (kind))
Fput (new_symbol, Qevent_kind, kind);
}
{
/* 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);
+ Lisp_Object parsed;
+ parsed = parse_modifiers (symbol);
return apply_modifiers (XCONS (XCONS (parsed)->cdr)->car,
XCONS (parsed)->car);
}
is the name of the i'th symbol. TABLE_SIZE is the number of elements
in the table.
+ Alternatively, NAME_ALIST is an alist mapping codes into symbol names.
+ NAME_ALIST is used if it is non-nil; otherwise NAME_TABLE is used.
+
SYMBOL_TABLE should be a pointer to a Lisp_Object whose value will
persist between calls to modify_event_symbol that it can use to
store a cache of the symbols it's generated for this NAME_TABLE
- before.
+ before. The object stored there may be a vector or an alist.
SYMBOL_NUM is the number of the base name we want from NAME_TABLE.
the returned symbol.
The symbols we create are supposed to have an
- `event-symbol-elements' propery, which lists the modifiers present
+ `event-symbol-elements' property, which lists the modifiers present
in the symbol's name. */
static Lisp_Object
-modify_event_symbol (symbol_num, modifiers, symbol_kind, name_table,
- symbol_table, table_size)
+modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist,
+ name_table, symbol_table, table_size)
int symbol_num;
unsigned modifiers;
Lisp_Object symbol_kind;
+ Lisp_Object name_alist;
char **name_table;
Lisp_Object *symbol_table;
int table_size;
{
- Lisp_Object *slot;
+ Lisp_Object value;
+ Lisp_Object symbol_int;
+
+ XSET (symbol_int, Lisp_Int, symbol_num);
/* Is this a request for a valid symbol? */
if (symbol_num < 0 || symbol_num >= table_size)
abort ();
+ if (CONSP (*symbol_table))
+ value = Fcdr (assq_no_quit (symbol_int, *symbol_table));
+
/* 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 the symbol for NAME_TABLE[N], or nil if
we've never used that symbol before. */
- if (XTYPE (*symbol_table) != Lisp_Vector
- || XVECTOR (*symbol_table)->size != table_size)
+ else
{
- Lisp_Object size;
+ if (! VECTORP (*symbol_table)
+ || XVECTOR (*symbol_table)->size != table_size)
+ {
+ Lisp_Object size;
- XFASTINT (size) = table_size;
- *symbol_table = Fmake_vector (size, Qnil);
- }
+ XFASTINT (size) = table_size;
+ *symbol_table = Fmake_vector (size, Qnil);
+ }
- slot = & XVECTOR (*symbol_table)->contents[symbol_num];
+ value = XVECTOR (*symbol_table)->contents[symbol_num];
+ }
/* Have we already used this symbol before? */
- if (NILP (*slot))
+ if (NILP (value))
{
/* No; let's create it. */
- *slot = intern (name_table[symbol_num]);
+ if (!NILP (name_alist))
+ value = Fassq (symbol_int, name_alist);
+ else if (name_table[symbol_num])
+ value = intern (name_table[symbol_num]);
+ else
+ {
+ char buf[20];
+ sprintf (buf, "key-%d", symbol_num);
+ value = intern (buf);
+ }
+
+ if (CONSP (*symbol_table))
+ *symbol_table = Fcons (value, *symbol_table);
+ else
+ XVECTOR (*symbol_table)->contents[symbol_num] = value;
/* Fill in the cache entries for this symbol; this also
builds the Qevent_symbol_elements property, which the user
cares about. */
- apply_modifiers (modifiers & click_modifier, *slot);
- Fput (*slot, Qevent_kind, symbol_kind);
+ apply_modifiers (modifiers & click_modifier, value);
+ Fput (value, Qevent_kind, symbol_kind);
}
/* Apply modifiers to that symbol. */
- return apply_modifiers (modifiers, *slot);
+ return apply_modifiers (modifiers, value);
}
\f
read_avail_input (expected);
#endif
}
+
+record_asynch_buffer_change ()
+{
+ struct input_event event;
+ event.kind = buffer_switch_event;
+ event.frame_or_window = Qnil;
+ kbd_buffer_store_event (&event);
+}
\f
#ifndef VMS
nread = (*read_socket_hook) (0, buf, KBD_BUFFER_SIZE, expected, expected);
else
{
- unsigned char cbuf[KBD_BUFFER_SIZE];
-
+ /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
+ the kbd_buffer can really hold. That may prevent loss
+ of characters on some systems when input is stuffed at us. */
+ unsigned char cbuf[KBD_BUFFER_SIZE - 1];
+
+#ifdef MSDOS
+ nread = dos_keysns ();
+ if (nread == 0) return 0;
+#else */ not MSDOS */
#ifdef FIONREAD
/* Find out how much input is available. */
if (ioctl (0, FIONREAD, &nread) < 0)
if (nread > sizeof cbuf)
nread = sizeof cbuf;
#else /* no FIONREAD */
-#ifdef USG
+#if defined(USG) || defined(DGUX)
/* Read some input if available, but don't wait. */
nread = sizeof cbuf;
fcntl (fileno (stdin), F_SETFL, O_NDELAY);
you lose;
#endif
#endif
+#endif /* not MSDOS */
/* Now read; for one reason or another, this will not block. */
while (1)
{
+#ifdef MSDOS
+ cbuf[0] = dos_keyread();
+ nread = 1;
+#else
nread = read (fileno (stdin), cbuf, nread);
+#endif
#ifdef AIX
/* The kernel sometimes fails to deliver SIGHUP for ptys.
This looks incorrect, but it isn't, because _BSD causes
O_NDELAY to be defined in fcntl.h as O_NONBLOCK,
and that causes a value other than 0 when there is no input. */
if (nread == 0)
- kill (SIGHUP, 0);
+ kill (0, SIGHUP);
#endif
+ /* This code is wrong, but at least it gets the right results.
+ Fix it for 19.23. */
/* Retry the read if it is interrupted. */
if (nread >= 0
- || ! (errno == EAGAIN || errno == EFAULT
+ || ! (errno == EAGAIN
+#ifdef EFAULT
+ || errno == EFAULT
+#endif
#ifdef EBADSLT
|| errno == EBADSLT
#endif
}
#ifndef FIONREAD
-#ifdef USG
+#if defined (USG) || defined (DGUX)
fcntl (fileno (stdin), F_SETFL, 0);
-#endif /* USG */
+#endif /* USG or DGUX */
#endif /* no FIONREAD */
for (i = 0; i < nread; i++)
{
return Qnil;
}
-static Lisp_Object menu_bar_item ();
-static Lisp_Object menu_bar_one_keymap ();
+static void menu_bar_item ();
+static void menu_bar_one_keymap ();
+
+/* These variables hold the vector under construction within
+ menu_bar_items and its subroutines, and the current index
+ for storing into that vector. */
+static Lisp_Object menu_bar_items_vector;
+static Lisp_Object menu_bar_items_index;
-/* Return a list of menu items for a menu bar, appropriate
- to the current buffer.
- The elements have the form (KEY STRING . nil). */
+/* Return a vector of menu items for a menu bar, appropriate
+ to the current buffer. Each item has three elements in the vector:
+ KEY STRING nil.
+
+ OLD is an old vector we can optionally reuse, or nil. */
Lisp_Object
-menu_bar_items ()
+menu_bar_items (old)
+ Lisp_Object old;
{
/* The number of keymaps we're scanning right now, and the number of
keymaps we have allocated space for. */
in the current keymaps, or nil where it is not a prefix. */
Lisp_Object *maps;
- Lisp_Object def, tem;
+ Lisp_Object def, tem, tail;
Lisp_Object result;
int mapno;
+ Lisp_Object oquit;
+
+ int i;
+
+ struct gcpro gcpro1;
+
+ /* In order to build the menus, we need to call the keymap
+ accessors. They all call QUIT. But this function is called
+ during redisplay, during which a quit is fatal. So inhibit
+ quitting while building the menus.
+ We do this instead of specbind because (1) errors will clear it anyway
+ and (2) this avoids risk of specpdl overflow. */
+ oquit = Vinhibit_quit;
+ Vinhibit_quit = Qt;
+
+ if (!NILP (old))
+ menu_bar_items_vector = old;
+ else
+ menu_bar_items_vector = Fmake_vector (make_number (24), Qnil);
+ menu_bar_items_index = 0;
+
+ GCPRO1 (menu_bar_items_vector);
/* Build our list of keymaps.
If we recognize a function key and replace its escape sequence in
{
Lisp_Object *tmaps;
- nmaps = current_minor_maps (0, &tmaps) + 2;
- maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
- bcopy (tmaps, maps, (nmaps - 2) * sizeof (maps[0]));
+ if (!NILP (Voverriding_local_map))
+ {
+ nmaps = 2;
+ maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
+ maps[0] = Voverriding_local_map;
+ }
+ else
+ {
+ nmaps = current_minor_maps (0, &tmaps) + 2;
+ maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
+ bcopy (tmaps, maps, (nmaps - 2) * sizeof (maps[0]));
#ifdef USE_TEXT_PROPERTIES
- maps[nmaps-2] = get_local_map (PT, current_buffer);
+ maps[nmaps-2] = get_local_map (PT, current_buffer);
#else
- maps[nmaps-2] = current_buffer->local_map;
+ maps[nmaps-2] = current_buffer->keymap;
#endif
- maps[nmaps-1] = global_map;
+ }
+ maps[nmaps-1] = current_global_map;
}
/* Look up in each map the dummy prefix key `menu-bar'. */
result = Qnil;
- for (mapno = 0; mapno < nmaps; mapno++)
+ for (mapno = nmaps - 1; mapno >= 0; mapno--)
{
if (! NILP (maps[mapno]))
- def = get_keyelt (access_keymap (maps[mapno], Qmenu_bar, 1));
+ def = get_keyelt (access_keymap (maps[mapno], Qmenu_bar, 1, 0));
else
def = Qnil;
tem = Fkeymapp (def);
if (!NILP (tem))
- result = menu_bar_one_keymap (def, result);
+ menu_bar_one_keymap (def);
+ }
+
+ /* Move to the end those items that should be at the end. */
+
+ for (tail = Vmenu_bar_final_items; CONSP (tail); tail = XCONS (tail)->cdr)
+ {
+ int i;
+ int end = menu_bar_items_index;
+
+ for (i = 0; i < end; i += 3)
+ if (EQ (XCONS (tail)->car, XVECTOR (menu_bar_items_vector)->contents[i]))
+ {
+ Lisp_Object tem0, tem1, tem2;
+ /* Move the item at index I to the end,
+ shifting all the others forward. */
+ tem0 = XVECTOR (menu_bar_items_vector)->contents[i + 0];
+ tem1 = XVECTOR (menu_bar_items_vector)->contents[i + 1];
+ tem2 = XVECTOR (menu_bar_items_vector)->contents[i + 2];
+ if (end > i + 3)
+ bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 3],
+ &XVECTOR (menu_bar_items_vector)->contents[i],
+ (end - i - 3) * sizeof (Lisp_Object));
+ XVECTOR (menu_bar_items_vector)->contents[end - 3] = tem0;
+ XVECTOR (menu_bar_items_vector)->contents[end - 2] = tem1;
+ XVECTOR (menu_bar_items_vector)->contents[end - 1] = tem2;
+ break;
+ }
+ }
+
+ /* Add nil, nil, nil at the end. */
+ i = menu_bar_items_index;
+ if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+ {
+ Lisp_Object tem;
+ int newsize = 2 * i;
+ tem = Fmake_vector (make_number (2 * i), Qnil);
+ bcopy (XVECTOR (menu_bar_items_vector)->contents,
+ XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
+ menu_bar_items_vector = tem;
}
+ /* Add this item. */
+ XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+ XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+ XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+ menu_bar_items_index = i;
- return Fnreverse (result);
+ Vinhibit_quit = oquit;
+ UNGCPRO;
+ return menu_bar_items_vector;
}
\f
/* Scan one map KEYMAP, accumulating any menu items it defines
- that have not yet been seen in RESULT. Return the updated RESULT. */
+ that have not yet been seen in RESULT. Return the updated RESULT.
+ *OLD is the frame's old menu bar list; we swipe elts from that
+ to avoid consing. */
-static Lisp_Object
-menu_bar_one_keymap (keymap, result)
- Lisp_Object keymap, result;
+static void
+menu_bar_one_keymap (keymap)
+ Lisp_Object keymap;
{
Lisp_Object tail, item, key, binding, item_string, table;
{
item_string = XCONS (binding)->car;
if (XTYPE (item_string) == Lisp_String)
- result = menu_bar_item (key, item_string,
- Fcdr (binding), result);
+ menu_bar_item (key, item_string, Fcdr (binding));
}
+ else if (EQ (binding, Qundefined))
+ menu_bar_item (key, item_string, binding);
}
else if (XTYPE (item) == Lisp_Vector)
{
{
item_string = XCONS (binding)->car;
if (XTYPE (item_string) == Lisp_String)
- result = menu_bar_item (key, item_string,
- Fcdr (binding), result);
+ menu_bar_item (key, item_string, Fcdr (binding));
}
+ else if (EQ (binding, Qundefined))
+ menu_bar_item (key, item_string, binding);
}
}
}
-
- return result;
}
+/* This is used as the handler when calling internal_condition_case_1. */
+
static Lisp_Object
-menu_bar_item (key, item_string, def, result)
- Lisp_Object key, item_string, def, result;
+menu_bar_item_1 (arg)
+ Lisp_Object arg;
+{
+ return Qnil;
+}
+
+static void
+menu_bar_item (key, item_string, def)
+ Lisp_Object key, item_string, def;
{
- Lisp_Object tem, elt;
+ Lisp_Object tem;
Lisp_Object enabled;
+ int i;
+
+ if (EQ (def, Qundefined))
+ {
+ /* If a map has an explicit nil as definition,
+ discard any previously made menu bar item. */
+
+ for (i = 0; i < menu_bar_items_index; i += 3)
+ if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
+ {
+ if (menu_bar_items_index > i + 3)
+ bcopy (&XVECTOR (menu_bar_items_vector)->contents[i + 3],
+ &XVECTOR (menu_bar_items_vector)->contents[i],
+ (menu_bar_items_index - i - 3) * sizeof (Lisp_Object));
+ menu_bar_items_index -= 3;
+ return;
+ }
+ }
/* See if this entry is enabled. */
enabled = Qt;
Otherwise, enable if value is not nil. */
tem = Fget (def, Qmenu_enable);
if (!NILP (tem))
- enabled = Feval (tem);
+ /* (condition-case nil (eval tem)
+ (error nil)) */
+ enabled = internal_condition_case_1 (Feval, tem, Qerror,
+ menu_bar_item_1);
}
- /* Add an entry for this key and string
- if there is none yet. */
- elt = Fassq (key, result);
- if (!NILP (enabled) && NILP (elt))
- result = Fcons (Fcons (key, Fcons (item_string, Qnil)), result);
+ /* Ignore this item if it's not enabled. */
+ if (NILP (enabled))
+ return;
+
+ /* If there's already such an item, don't make another. */
+ for (i = 0; i < menu_bar_items_index; i += 3)
+ if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
+ break;
- return result;
+ /* If we did not find this item, add it at the end. */
+ if (i == menu_bar_items_index)
+ {
+ /* If vector is too small, get a bigger one. */
+ if (i + 3 > XVECTOR (menu_bar_items_vector)->size)
+ {
+ Lisp_Object tem;
+ int newsize = 2 * i;
+ tem = Fmake_vector (make_number (2 * i), Qnil);
+ bcopy (XVECTOR (menu_bar_items_vector)->contents,
+ XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
+ menu_bar_items_vector = tem;
+ }
+ /* Add this item. */
+ XVECTOR (menu_bar_items_vector)->contents[i++] = key;
+ XVECTOR (menu_bar_items_vector)->contents[i++] = item_string;
+ XVECTOR (menu_bar_items_vector)->contents[i++] = Qnil;
+ menu_bar_items_index = i;
+ }
}
\f
-static int echo_flag;
-static int echo_now;
-
-/* Read a character like read_char but optionally prompt based on maps
- in the array MAPS. NMAPS is the length of MAPS. Return nil if we
- decided not to read a character, because there are no menu items in
- MAPS.
+/* Read a character using menus based on maps in the array MAPS.
+ NMAPS is the length of MAPS. Return nil if there are no menus in the maps.
+ Return t if we displayed a menu but the user rejected it.
PREV_EVENT is the previous input event, or nil if we are reading
the first event of a key sequence.
USED_MOUSE_MENU is zero, *USED_MOUSE_MENU is left alone.
The prompting is done based on the prompt-string of the map
- and the strings associated with various map elements. */
+ and the strings associated with various map elements.
-Lisp_Object
-read_char_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
+ This can be done with X menus or with menus put in the minibuf.
+ These are done in different ways, depending on how the input will be read.
+ Menus using X are done after auto-saving in read-char, getting the input
+ event from Fx_popup_menu; menus using the minibuf use read_char recursively
+ and do auto-saving in the inner call of read_char. */
+
+static Lisp_Object
+read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu)
int nmaps;
Lisp_Object *maps;
Lisp_Object prev_event;
{
int mapno;
register Lisp_Object name;
- int nlength;
- int width = FRAME_WIDTH (selected_frame) - 4;
- char *menu = (char *) alloca (width + 4);
- int idx = -1;
Lisp_Object rest, vector;
if (used_mouse_menu)
value = XCONS (value)->car;
}
if (NILP (value))
- XSET (value, Lisp_Int, quit_char);
+ value = Qt;
if (used_mouse_menu)
*used_mouse_menu = 1;
return value;
}
#endif /* HAVE_X_MENU */
#endif /* HAVE_X_WINDOWS */
+ return Qnil ;
+}
+
+static Lisp_Object
+read_char_minibuf_menu_prompt(commandflag, nmaps, maps)
+ int commandflag ;
+ int nmaps;
+ Lisp_Object *maps;
+{
+ int mapno;
+ register Lisp_Object name;
+ int nlength;
+ int width = FRAME_WIDTH (selected_frame) - 4;
+ char *menu = (char *) alloca (width + 4);
+ int idx = -1;
+ int nobindings ;
+ Lisp_Object rest, vector;
+
+ if (! menu_prompting)
+ return Qnil;
+
+ /* Get the menu name from the first map that has one (a prompt string). */
+ for (mapno = 0; mapno < nmaps; mapno++)
+ {
+ name = map_prompt (maps[mapno]);
+ if (!NILP (name))
+ break;
+ }
+
+ /* If we don't have any menus, just read a character normally. */
+ if (mapno >= nmaps)
+ return Qnil;
/* Prompt string always starts with map's prompt, and a space. */
strcpy (menu, XSTRING (name)->data);
int i = nlength;
Lisp_Object obj;
int ch;
+ int orig_defn_macro ;
/* Loop over elements of map. */
while (i < width)
or end this line if already have something on it. */
if (mapno == nmaps)
{
- if (notfirst)
- break;
- else
- mapno = 0;
+ mapno = 0;
+ if (notfirst || nobindings) break;
}
rest = maps[mapno];
}
else
{
/* An ordinary element. */
- s = Fcar_safe (Fcdr_safe (elt));
+ if ( idx < 0 )
+ s = Fcar_safe (Fcdr_safe (elt)); /* alist */
+ else
+ s = Fcar_safe(elt); /* vector */
if (XTYPE (s) != Lisp_String)
/* Ignore the element if it has no prompt string. */
;
/* If we have room for the prompt string, add it to this line.
If this is the first on the line, always add it. */
- else if (XSTRING (s)->size + i < width
+ else if (XSTRING (s)->size + i + 2 < width
|| !notfirst)
{
int thiswidth;
i += 2;
}
notfirst = 1;
+ nobindings = 0 ;
/* Add as much of string as fits. */
thiswidth = XSTRING (s)->size;
thiswidth = width - i;
bcopy (XSTRING (s)->data, menu + i, thiswidth);
i += thiswidth;
+ menu[i] = 0;
}
else
{
}
/* Move past this element. */
- if (idx >= 0 && idx + 1 >= XVECTOR (rest)->size)
+ if (idx >= 0 && idx + 1 >= XVECTOR (vector)->size)
/* Handle reaching end of dense table. */
idx = -1;
if (idx >= 0)
/* Prompt with that and read response. */
message1 (menu);
- obj = read_char (1, 0, 0, Qnil, 0);
+
+ /* Make believe its not a keyboard macro in case the help char
+ is pressed. Help characters are not recorded because menu prompting
+ is not used on replay.
+ */
+ orig_defn_macro = defining_kbd_macro ;
+ defining_kbd_macro = 0 ;
+ do
+ obj = read_char (commandflag, 0, 0, Qnil, 0);
+ while (XTYPE (obj) == Lisp_Buffer);
+ defining_kbd_macro = orig_defn_macro ;
if (XTYPE (obj) != Lisp_Int)
return obj;
if (! EQ (obj, menu_prompt_more_char)
&& (XTYPE (menu_prompt_more_char) != Lisp_Int
|| ! EQ (obj, make_number (Ctl (XINT (menu_prompt_more_char))))))
- return obj;
+ {
+ if ( defining_kbd_macro )
+ store_kbd_macro_char(obj) ;
+ return obj;
+ }
+ /* Help char - go round again */
}
}
\f
When KEY is not defined in any of the keymaps, if it is an upper
case letter and there are bindings for the corresponding lower-case
letter, return the bindings for the lower-case letter.
+ We store 1 in *CASE_CONVERTED in this case.
+ Otherwise, we don't change *CASE_CONVERTED.
If KEY has no bindings in any of the CURRENT maps, NEXT is left
unmodified.
NEXT may == CURRENT. */
static int
-follow_key (key, nmaps, current, defs, next)
+follow_key (key, nmaps, current, defs, next, case_converted)
Lisp_Object key;
Lisp_Object *current, *defs, *next;
int nmaps;
+ int *case_converted;
{
int i, first_binding;
if (! NILP (current[i]))
{
next[i] =
- get_keyelt (access_keymap (current[i], meta_prefix_char, 1));
+ get_keyelt (access_keymap (current[i], meta_prefix_char, 1, 0));
/* Note that since we pass the resulting bindings through
get_keymap_1, non-prefix bindings for meta-prefix-char
{
if (! NILP (current[i]))
{
- defs[i] = get_keyelt (access_keymap (current[i], key, 1));
+ defs[i] = get_keyelt (access_keymap (current[i], key, 1, 0));
if (! NILP (defs[i]))
first_binding = i;
}
if (XINT (key) & shift_modifier)
XSETINT (key, XINT (key) & ~shift_modifier);
else
- XSETINT (key, DOWNCASE (XINT (key)));
+ XSETINT (key, (DOWNCASE (XINT (key) & 0x3ffff)
+ | (XINT (key) & ~0x3ffff)));
first_binding = nmaps;
for (i = nmaps - 1; i >= 0; i--)
{
if (! NILP (current[i]))
{
- defs[i] = get_keyelt (access_keymap (current[i], key, 1));
+ defs[i] = get_keyelt (access_keymap (current[i], key, 1, 0));
if (! NILP (defs[i]))
first_binding = i;
}
else
defs[i] = Qnil;
}
+ if (first_binding != nmaps)
+ *case_converted = 1;
}
/* Given the set of bindings we've found, produce the next set of maps. */
storing it in KEYBUF, a buffer of size BUFSIZE.
Prompt with PROMPT.
Return the length of the key sequence stored.
+ Return -1 if the user rejected a command menu.
Echo starting immediately unless `prompt' is 0.
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.
+ We ignore unbound `down-' mouse clicks. We turn unbound `drag-' and
+ `double-' events into similar click events, if that would make them
+ bound. We try to turn `triple-' events first into `double-' events,
+ then into clicks.
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
read_key_sequence (keybuf, bufsize, prompt)
Lisp_Object *keybuf;
int bufsize;
- char *prompt;
+ Lisp_Object prompt;
{
int count = specpdl_ptr - specpdl;
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;
+ Lisp_Object fkey_map;
+
+ /* Likewise, for key_translation_map. */
+ int keytran_start = 0, keytran_end = 0;
+ Lisp_Object keytran_map;
/* 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. */
- Lisp_Object delayed_switch_frame = Qnil;
+ Lisp_Object delayed_switch_frame;
+ /* See the comment below... */
+#if defined (GOBBLE_FIRST_EVENT)
+ Lisp_Object first_event;
+#endif
- /* If there is no function key map, turn off function key scanning. */
+ struct buffer *starting_buffer;
+
+ /* Nonzero if we found the binding for one of the chars
+ in this key sequence by downcasing it. */
+ int case_converted = 0;
+
+ /* Nonzero if we seem to have got the beginning of a binding
+ in function_key_map. */
+ int function_key_possible = 0;
+
+ int junk;
+
+ last_nonmenu_event = Qnil;
+
+ delayed_switch_frame = Qnil;
+ fkey_map = Vfunction_key_map;
+ keytran_map = Vkey_translation_map;
+
+ /* If there is no function-key-map, turn off function key scanning. */
if (NILP (Fkeymapp (Vfunction_key_map)))
fkey_start = fkey_end = bufsize + 1;
- last_nonmenu_event = Qnil;
+ /* If there is no key-translation-map, turn off scanning. */
+ if (NILP (Fkeymapp (Vkey_translation_map)))
+ keytran_start = keytran_end = bufsize + 1;
if (INTERACTIVE)
{
- if (prompt)
- echo_prompt (prompt);
+ if (!NILP (prompt))
+ echo_prompt (XSTRING (prompt)->data);
else if (cursor_in_echo_area)
/* This doesn't put in a dash if the echo buffer is empty, so
you don't always see a dash hanging out in the minibuffer. */
echo_start = echo_length ();
keys_start = this_command_key_count;
+#if defined (GOBBLE_FIRST_EVENT)
+ /* This doesn't quite work, because some of the things that read_char
+ does cannot safely be bypassed. It seems too risky to try to make
+ this work right. */
+
+ /* Read the first char of the sequence specially, before setting
+ up any keymaps, in case a filter runs and switches buffers on us. */
+ first_event = read_char (NILP (prompt), 0, submaps, last_nonmenu_event,
+ &junk);
+#endif /* GOBBLE_FIRST_EVENT */
+
/* We jump here when the key sequence has been thoroughly changed, and
we need to rescan it starting from the beginning. When we jump here,
keybuf[0..mock_input] holds the sequence we should reread. */
replay_sequence:
+ starting_buffer = current_buffer;
+ case_converted = 0;
+ function_key_possible = 0;
+
/* Build our list of keymaps.
If we recognize a function key and replace its escape sequence in
keybuf with its symbol, or if the sequence starts with a mouse
{
Lisp_Object *maps;
- nmaps = current_minor_maps (0, &maps) + 2;
- if (nmaps > nmaps_allocated)
+ if (!NILP (Voverriding_local_map))
{
- submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
- defs = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
- nmaps_allocated = nmaps;
+ nmaps = 2;
+ if (nmaps > nmaps_allocated)
+ {
+ submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
+ defs = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
+ nmaps_allocated = nmaps;
+ }
+ submaps[0] = Voverriding_local_map;
}
- bcopy (maps, submaps, (nmaps - 2) * sizeof (submaps[0]));
+ else
+ {
+ nmaps = current_minor_maps (0, &maps) + 2;
+ if (nmaps > nmaps_allocated)
+ {
+ submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
+ defs = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
+ nmaps_allocated = nmaps;
+ }
+ bcopy (maps, submaps, (nmaps - 2) * sizeof (submaps[0]));
#ifdef USE_TEXT_PROPERTIES
- submaps[nmaps-2] = get_local_map (PT, current_buffer);
+ submaps[nmaps-2] = get_local_map (PT, current_buffer);
#else
- submaps[nmaps-2] = current_buffer->local_map;
+ submaps[nmaps-2] = current_buffer->keymap;
#endif
- submaps[nmaps-1] = global_map;
+ }
+ submaps[nmaps-1] = current_global_map;
}
/* Find an accurate initial value for first_binding. */
if (! NILP (submaps[first_binding]))
break;
- /* 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. */
+ /* Start from the beginning in keybuf. */
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)
+ if (INTERACTIVE && t < mock_input)
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. */
+ /* 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))
+ || (first_binding >= nmaps
+ && fkey_start < t
+ /* mock input is never part of a function key's sequence. */
+ && mock_input <= fkey_start)
+ || (first_binding >= nmaps
+ && keytran_start < t
+ /* mock input is never part of a function key's sequence. */
+ && mock_input <= keytran_start)
+ /* Don't return in the middle of a possible function key sequence,
+ if the only bindings we found were via case conversion.
+ Thus, if ESC O a has a function-key-map translation
+ and ESC o has a binding, don't return after ESC O,
+ so that we can translate ESC O plus the next character. */
+ || (function_key_possible && case_converted))
{
Lisp_Object key;
int used_mouse_menu = 0;
jumped back up to replay_key; in that case, these restore the
variables to their original state, allowing us to replay the
loop. */
- if (INTERACTIVE)
+ if (INTERACTIVE && t < mock_input)
echo_truncate (echo_local_start);
this_command_key_count = keys_local_start;
first_binding = local_first_binding;
+ /* By default, assume each event is "real". */
+ last_real_key_start = t;
+
/* Does mock_input indicate that we are re-reading a key sequence? */
if (t < mock_input)
{
/* If not, we should actually read a character. */
else
{
- last_real_key_start = t;
+ struct buffer *buf = current_buffer;
- key = read_char (!prompt, nmaps, submaps, last_nonmenu_event,
+ key = read_char (NILP (prompt), nmaps, submaps, last_nonmenu_event,
&used_mouse_menu);
+ /* read_char returns t when it shows a menu and the user rejects it.
+ Just return -1. */
+ if (EQ (key, Qt))
+ return -1;
+
/* 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. */
goto done;
}
+ /* If the current buffer has been changed from under us, the
+ keymap may have changed, so replay the sequence. */
+ if (XTYPE (key) == Lisp_Buffer)
+ {
+ mock_input = t;
+ goto replay_sequence;
+ }
+
+ /* If we have a quit that was typed in another frame, and
+ quit_throw_to_read_char switched buffers,
+ replay to get the right keymap. */
+ if (EQ (key, quit_char) && current_buffer != starting_buffer)
+ {
+ keybuf[t++] = key;
+ mock_input = t;
+ Vquit_flag = Qnil;
+ goto replay_sequence;
+ }
+
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'.
+ /* 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'.
+
+ 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.
+
+ When we turn one event into two events, we must make sure
+ that neither of the two looks like the original--so that,
+ if we replay the events, they won't be expanded again.
+ If not for this, such reexpansion could happen either here
+ or when user programs play with this-command-keys. */
+ if (EVENT_HAS_PARAMETERS (key))
+ {
+ Lisp_Object kind;
- 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))
+ kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
+ if (EQ (kind, Qmouse_click))
{
- Lisp_Object kind = EVENT_HEAD_KIND (EVENT_HEAD (key));
+ Lisp_Object window, posn;
- if (EQ (kind, Qmouse_click))
+ window = POSN_WINDOW (EVENT_START (key));
+ posn = POSN_BUFFER_POSN (EVENT_START (key));
+ if (XTYPE (posn) == Lisp_Cons)
{
- 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;
- }
-
- /* Arrange to go back to the original buffer once we're
- done reading the key sequence. Note that we can't
- use save_excursion_{save,restore} here, because they
- save point as well as the current buffer; we don't
- want to save point, because redisplay may change it,
- to accomodate a Fset_window_start or something. We
- don't want to do this at the top of the function,
- because we may get input from a subprocess which
- wants to change the selected window and stuff (say,
- emacsclient). */
- record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
-
- set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
- goto replay_sequence;
- }
- else 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;
+ /* We're looking at the second event of a
+ sequence which we expanded before. Set
+ last_real_key_start appropriately. */
+ if (t > 0)
+ last_real_key_start = t - 1;
+ }
- goto replay_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 (last_real_key_start == 0
+ && XTYPE (window) == Lisp_Window
+ && XTYPE (XWINDOW (window)->buffer) == Lisp_Buffer
+ && XBUFFER (XWINDOW (window)->buffer) != current_buffer)
+ {
+ keybuf[t] = key;
+ mock_input = t + 1;
+
+ /* Arrange to go back to the original buffer once we're
+ done reading the key sequence. Note that we can't
+ use save_excursion_{save,restore} here, because they
+ save point as well as the current buffer; we don't
+ want to save point, because redisplay may change it,
+ to accommodate a Fset_window_start or something. We
+ don't want to do this at the top of the function,
+ because we may get input from a subprocess which
+ wants to change the selected window and stuff (say,
+ emacsclient). */
+ record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+
+ set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
+ goto replay_sequence;
}
- else if (EQ (kind, Qswitch_frame))
+ else if (XTYPE (posn) == Lisp_Symbol)
{
- /* If we're at the beginning of a key sequence, go
- ahead and return this event. If we're in the
- midst of a key sequence, delay it until the end. */
- if (t > 0)
- {
- delayed_switch_frame = key;
- goto replay_key;
- }
+ /* Expand mode-line and scroll-bar events into two events:
+ use posn as a fake prefix key. */
+
+ if (t + 1 >= bufsize)
+ error ("key sequence too long");
+ keybuf[t] = posn;
+ keybuf[t+1] = key;
+ mock_input = t + 2;
+
+ /* Zap the position in key, so we know that we've
+ expanded it, and don't try to do so again. */
+ POSN_BUFFER_POSN (EVENT_START (key))
+ = Fcons (posn, Qnil);
+ goto replay_key;
}
- else
+ }
+ else if (EQ (kind, Qswitch_frame))
+ {
+ /* If we're at the beginning of a key sequence, go
+ ahead and return this event. If we're in the
+ midst of a key sequence, delay it until the end. */
+ if (t > 0)
{
- Lisp_Object posn = POSN_BUFFER_POSN (EVENT_START (key));
+ delayed_switch_frame = key;
+ goto replay_key;
+ }
+ }
+ else
+ {
+ Lisp_Object posn;
- /* Handle menu-bar events:
- insert the dummy prefix char `menu-bar'. */
- if (EQ (posn, Qmenu_bar))
- {
- if (t + 1 >= bufsize)
- error ("key sequence too long");
- /* Run the Lucid hook. */
- call1 (Vrun_hooks, Qactivate_menubar_hook);
- /* If it has changed current-menubar from previous value,
- really recompute the menubar from the value. */
- if (! NILP (Vlucid_menu_bar_dirty_flag))
- call0 (Qrecompute_lucid_menubar);
- keybuf[t] = posn;
- keybuf[t+1] = key;
- mock_input = t + 2;
- goto replay_sequence;
- }
+ posn = POSN_BUFFER_POSN (EVENT_START (key));
+ /* Handle menu-bar events:
+ insert the dummy prefix event `menu-bar'. */
+ if (EQ (posn, Qmenu_bar))
+ {
+ if (t + 1 >= bufsize)
+ error ("key sequence too long");
+ /* Run the Lucid hook. */
+ if (!NILP (Vrun_hooks))
+ call1 (Vrun_hooks, Qactivate_menubar_hook);
+ /* If it has changed current-menubar from previous value,
+ really recompute the menubar from the value. */
+ if (! NILP (Vlucid_menu_bar_dirty_flag))
+ call0 (Qrecompute_lucid_menubar);
+ keybuf[t] = posn;
+ keybuf[t+1] = key;
+
+ /* Zap the position in key, so we know that we've
+ expanded it, and don't try to do so again. */
+ POSN_BUFFER_POSN (EVENT_START (key))
+ = Fcons (posn, Qnil);
+
+ mock_input = t + 2;
+ goto replay_sequence;
+ }
+ else if (XTYPE (posn) == Lisp_Cons)
+ {
+ /* We're looking at the second event of a
+ sequence which we expanded before. Set
+ last_real_key_start appropriately. */
+ if (last_real_key_start == t && t > 0)
+ last_real_key_start = t - 1;
}
}
}
nmaps - first_binding,
submaps + first_binding,
defs + first_binding,
- submaps + first_binding)
+ submaps + first_binding,
+ &case_converted)
+ first_binding);
/* If KEY wasn't bound, we'll try some fallbacks. */
if (first_binding >= nmaps)
{
- Lisp_Object head = EVENT_HEAD (key);
+ Lisp_Object head;
- if (XTYPE (head) == Lisp_Symbol)
+ head = EVENT_HEAD (key);
+ if (EQ (head, Vhelp_char))
{
- Lisp_Object breakdown = parse_modifiers (head);
- int modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
+ read_key_sequence_cmd = Vprefix_help_command;
+ keybuf[t++] = key;
+ last_nonmenu_event = key;
+ goto done;
+ }
- /* We drop unbound `down-' events altogether. */
- if (modifiers & down_modifier)
+ if (XTYPE (head) == Lisp_Symbol)
+ {
+ Lisp_Object breakdown;
+ int modifiers;
+
+ breakdown = parse_modifiers (head);
+ modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
+ /* Attempt to reduce an unbound mouse event to a simpler
+ event that is bound:
+ Drags reduce to clicks.
+ Double-clicks reduce to clicks.
+ Triple-clicks reduce to double-clicks, then to clicks.
+ Down-clicks are eliminated.
+ Double-downs reduce to downs, then are eliminated.
+ Triple-downs reduce to double-downs, then to downs,
+ then are eliminated. */
+ if (modifiers & (down_modifier | drag_modifier
+ | double_modifier | triple_modifier))
{
- /* Dispose of this event by simply jumping back to
- replay_key, to get another event.
-
- Note that if this event came from mock input,
- then just jumping back to replay_key will just
- hand it to us again. So we have to wipe out any
- mock input.
-
- 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 both
- must be thrown away. If we're only looking at
- the prefix now, we can just jump back to
- replay_key. On the other hand, if we've already
- processed the prefix, and now the actual click
- itself is giving us trouble, then we've lost the
- state of the keymaps we want to backtrack to, and
- we need to replay the whole sequence to rebuild
- 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? */
- if (t == last_real_key_start)
+ while (modifiers & (down_modifier | drag_modifier
+ | double_modifier | triple_modifier))
{
- mock_input = 0;
- goto replay_key;
- }
- else
- {
- mock_input = last_real_key_start;
- goto replay_sequence;
- }
- }
+ Lisp_Object new_head, new_click;
+ if (modifiers & triple_modifier)
+ modifiers ^= (double_modifier | triple_modifier);
+ else if (modifiers & (drag_modifier | double_modifier))
+ modifiers &= ~(drag_modifier | double_modifier);
+ else
+ {
+ /* Dispose of this `down' event by simply jumping
+ back to replay_key, to get another event.
+
+ Note that if this event came from mock input,
+ then just jumping back to replay_key will just
+ hand it to us again. So we have to wipe out any
+ mock input.
+
+ 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 both
+ must be thrown away. If we're only looking at
+ the prefix now, we can just jump back to
+ replay_key. On the other hand, if we've already
+ processed the prefix, and now the actual click
+ itself is giving us trouble, then we've lost the
+ state of the keymaps we want to backtrack to, and
+ we need to replay the whole sequence to rebuild
+ 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? */
+ if (t == last_real_key_start)
+ {
+ mock_input = 0;
+ goto replay_key;
+ }
+ else
+ {
+ mock_input = last_real_key_start;
+ goto replay_sequence;
+ }
+ }
- /* 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. */
+ new_head
+ = apply_modifiers (modifiers, XCONS (breakdown)->car);
+ 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,
+ &case_converted)
+ + local_first_binding);
+
+ /* If that click is bound, go for it. */
+ if (first_binding < nmaps)
+ {
+ key = new_click;
+ break;
+ }
+ /* Otherwise, we'll leave key set to the drag event. */
+ }
}
}
}
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-reading old events, don't examine it. */
- if (first_binding >= nmaps
+ if ((first_binding >= nmaps || case_converted)
&& t >= mock_input)
{
Lisp_Object fkey_next;
- /* Scan from fkey_end until we find a bound suffix. */
+ /* Continue scan from fkey_end until we find a bound suffix.
+ If we fail, increment fkey_start
+ and start fkey_end from there. */
while (fkey_end < t)
{
Lisp_Object key;
with meta_prefix_char. I hate this. */
if (XTYPE (key) == Lisp_Int && XINT (key) & meta_modifier)
{
- fkey_next =
- get_keymap_1
+ fkey_next
+ = get_keymap_1
(get_keyelt
- (access_keymap
- (fkey_map, meta_prefix_char, 1)),
+ (access_keymap (fkey_map, meta_prefix_char, 1, 0)),
0, 1);
XFASTINT (key) = XFASTINT (key) & ~meta_modifier;
}
else
fkey_next = fkey_map;
- fkey_next =
- get_keyelt (access_keymap (fkey_next, key, 1));
+ fkey_next
+ = get_keyelt (access_keymap (fkey_next, key, 1, 0));
+
+ /* 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 (fkey_next) && ! NILP (Ffboundp (fkey_next))
+ && fkey_end == t)
+ {
+ struct gcpro gcpro1, gcpro2, gcpro3;
+ Lisp_Object tem;
+ tem = fkey_next;
+
+ GCPRO3 (fkey_map, keytran_map, delayed_switch_frame);
+ fkey_next = call1 (fkey_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 (fkey_next) || STRINGP (fkey_next)))
+ error ("Function in function-key-map returns invalid key sequence");
+ }
+
+ function_key_possible = ! NILP (fkey_next);
/* 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 (XTYPE (fkey_next) == Lisp_Vector
+ if ((VECTORP (fkey_next) || STRINGP (fkey_next))
&& fkey_end == t)
{
- t = fkey_start + XVECTOR (fkey_next)->size;
+ int len = XFASTINT (Flength (fkey_next));
+
+ t = fkey_start + len;
if (t >= bufsize)
error ("key sequence too long");
- bcopy (XVECTOR (fkey_next)->contents,
- keybuf + fkey_start,
- (t - fkey_start) * sizeof (keybuf[0]));
+ if (VECTORP (fkey_next))
+ bcopy (XVECTOR (fkey_next)->contents,
+ keybuf + fkey_start,
+ (t - fkey_start) * sizeof (keybuf[0]));
+ else if (STRINGP (fkey_next))
+ {
+ int i;
+
+ for (i = 0; i < len; i++)
+ XFASTINT (keybuf[fkey_start + i])
+ = XSTRING (fkey_next)->data[i];
+ }
mock_input = t;
fkey_start = fkey_end = t;
+ fkey_map = Vfunction_key_map;
goto replay_sequence;
}
{
fkey_end = ++fkey_start;
fkey_map = Vfunction_key_map;
+ function_key_possible = 0;
}
}
}
+
+ /* Look for this sequence in key-translation-map. */
+ {
+ Lisp_Object keytran_next;
+
+ /* Scan from keytran_end until we find a bound suffix. */
+ while (keytran_end < t)
+ {
+ Lisp_Object key;
+
+ key = keybuf[keytran_end++];
+ /* Look up meta-characters by prefixing them
+ with meta_prefix_char. I hate this. */
+ if (XTYPE (key) == Lisp_Int && XINT (key) & meta_modifier)
+ {
+ keytran_next
+ = get_keymap_1
+ (get_keyelt
+ (access_keymap (keytran_map, meta_prefix_char, 1, 0)),
+ 0, 1);
+ XFASTINT (key) = XFASTINT (key) & ~meta_modifier;
+ }
+ else
+ keytran_next = keytran_map;
+
+ keytran_next
+ = get_keyelt (access_keymap (keytran_next, key, 1, 0));
+
+ /* If the key translation map gives a function, not an
+ array, then call the function with no args and use
+ its value instead. */
+ if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
+ && keytran_end == t)
+ {
+ struct gcpro gcpro1, gcpro2, gcpro3;
+ Lisp_Object tem;
+ tem = keytran_next;
+
+ GCPRO3 (fkey_map, keytran_map, delayed_switch_frame);
+ keytran_next = call1 (keytran_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 (keytran_next) || STRINGP (keytran_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 (keytran_next) || STRINGP (keytran_next))
+ && keytran_end == t)
+ {
+ int len = XFASTINT (Flength (keytran_next));
+
+ t = keytran_start + len;
+ if (t >= bufsize)
+ error ("key sequence too long");
+
+ if (VECTORP (keytran_next))
+ bcopy (XVECTOR (keytran_next)->contents,
+ keybuf + keytran_start,
+ (t - keytran_start) * sizeof (keybuf[0]));
+ else if (STRINGP (keytran_next))
+ {
+ int i;
+
+ for (i = 0; i < len; i++)
+ XFASTINT (keybuf[keytran_start + i])
+ = XSTRING (keytran_next)->data[i];
+ }
+
+ mock_input = t;
+ keytran_start = keytran_end = t;
+ keytran_map = Vkey_translation_map;
+
+ goto replay_sequence;
+ }
+
+ keytran_map = get_keymap_1 (keytran_next, 0, 1);
+
+ /* If we no longer have a bound suffix, try a new positions for
+ keytran_start. */
+ if (NILP (keytran_map))
+ {
+ keytran_end = ++keytran_start;
+ keytran_map = Vkey_translation_map;
+ }
+ }
+ }
}
read_key_sequence_cmd = (first_binding < nmaps
done:
unread_switch_frame = delayed_switch_frame;
unbind_to (count, Qnil);
+
+ /* Occasionally we fabricate events, perhaps by expanding something
+ according to function-key-map, or by adding a prefix symbol to a
+ mouse click in the scroll bar or modeline. In this cases, return
+ the entire generated key sequence, even if we hit an unbound
+ prefix or a definition before the end. This means that you will
+ be able to push back the event properly, and also means that
+ read-key-sequence will always return a logical unit.
+
+ Better ideas? */
+ for (; t < mock_input; t++)
+ {
+ echo_char (keybuf[t]);
+ add_command_key (keybuf[t]);
+ }
+
return t;
}
+#if 0 /* This doc string is too long for some compilers.
+ This commented-out definition serves for DOC. */
DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 2, 0,
"Read a sequence of keystrokes and return as a string or vector.\n\
The sequence is sufficient to specify a non-prefix command in the\n\
If the key sequence starts with a mouse click, then the sequence is read\n\
using the keymaps of the buffer of the window clicked in, not the buffer\n\
of the selected window as normal.\n\
-\n\
+""\n\
`read-key-sequence' drops unbound button-down events, since you normally\n\
only care about the click or drag events which follow them. If a drag\n\
-event is unbound, but the corresponding click event would be bound,\n\
-`read-key-sequence' turns the drag event into a click event at the\n\
+or multi-click event is unbound, but the corresponding click event would\n\
+be bound, `read-key-sequence' turns the event into a click event at the\n\
drag's starting position. This means that you don't have to distinguish\n\
-between click and drag events unless you want to.\n\
+between click and drag, double, or triple events unless you want to.\n\
\n\
`read-key-sequence' prefixes mouse events on mode lines, the vertical\n\
lines separating windows, and scroll bars with imaginary keys\n\
`read-key-sequence' checks `function-key-map' for function key\n\
sequences, where they wouldn't conflict with ordinary bindings. See\n\
`function-key-map' for more details.")
+ (prompt, continue_echo)
+#endif
+
+DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 2, 0,
+ 0)
(prompt, continue_echo)
Lisp_Object prompt, continue_echo;
{
if (NILP (continue_echo))
this_command_key_count = 0;
- i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
- NILP (prompt) ? 0 : XSTRING (prompt)->data);
+ i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])), prompt);
+ if (i == -1)
+ {
+ Vquit_flag = Qt;
+ QUIT;
+ }
UNGCPRO;
return make_event_array (i, keybuf);
}
if (XTYPE (cmd) == Lisp_Symbol)
{
tem = Fget (cmd, Qdisabled);
- if (!NILP (tem))
- return call1 (Vrun_hooks, Vdisabled_command_hook);
+ if (!NILP (tem) && !NILP (Vrun_hooks))
+ return call1 (Vrun_hooks, Qdisabled_command_hook);
}
while (1)
Lisp_Object saved_keys;
struct gcpro gcpro1;
- saved_keys = Fthis_command_keys ();
+ saved_keys = Fvector (this_command_key_count,
+ XVECTOR (this_command_keys)->contents);
buf[0] = 0;
GCPRO1 (saved_keys);
/* Prompt with buf, and then read a string, completing from and
restricting to the set of all defined commands. Don't provide
- any initial input. The last Qnil says not to perform a
- peculiar hack on the initial input. */
+ any initial input. Save the command read on the extended-command
+ history list. */
function = Fcompleting_read (build_string (buf),
Vobarray, Qcommandp,
- Qt, Qnil, Qnil);
+ Qt, Qnil, Qextended_command_history);
/* Set this_command_keys to the concatenation of saved_keys and
function, followed by a RET. */
{
struct Lisp_String *str;
+ Lisp_Object *keys;
int i;
Lisp_Object tem;
this_command_key_count = 0;
- str = XSTRING (saved_keys);
- for (i = 0; i < str->size; i++)
- {
- XFASTINT (tem) = str->data[i];
- add_command_key (tem);
- }
+ keys = XVECTOR (saved_keys)->contents;
+ for (i = 0; i < XVECTOR (saved_keys)->size; i++)
+ add_command_key (keys[i]);
str = XSTRING (function);
for (i = 0; i < str->size; i++)
\f
DEFUN ("suspend-emacs", Fsuspend_emacs, Ssuspend_emacs, 0, 1, "",
"Stop Emacs and return to superior process. You can resume later.\n\
-On systems that don't have job control, run a subshell instead.\n\n\
+If `cannot-suspend' is non-nil, or if the system doesn't support job\n\
+control, run a subshell instead.\n\n\
If optional arg STUFFSTRING is non-nil, its characters are stuffed\n\
to be read as terminal input by Emacs's parent, after suspension.\n\
\n\
and the system resources aren't available for that. */
record_unwind_protect (init_sys_modes, 0);
stuff_buffered_input (stuffstring);
- sys_suspend ();
+ if (cannot_suspend)
+ sys_subshell ();
+ else
+ sys_suspend ();
unbind_to (count, Qnil);
/* Check if terminal/window size has changed.
with a window system; but suspend should be disabled in that case. */
get_frame_size (&width, &height);
if (width != old_width || height != old_height)
- change_frame_size (0, height, width, 0, 0);
+ change_frame_size (selected_frame, height, width, 0, 0);
/* Run suspend-resume-hook. */
if (!NILP (Vrun_hooks))
}
/* If STUFFSTRING is a string, stuff its contents as pending terminal input.
- Then in any case stuff anthing Emacs has read ahead and not used. */
+ Then in any case stuff anything Emacs has read ahead and not used. */
stuff_buffered_input (stuffstring)
Lisp_Object stuffstring;
if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
kbd_fetch_ptr = kbd_buffer;
if (kbd_fetch_ptr->kind == ascii_keystroke)
- stuff_char (XINT (kbd_fetch_ptr->code));
+ stuff_char (kbd_fetch_ptr->code);
kbd_fetch_ptr->kind = no_event;
(XVECTOR (kbd_buffer_frame_or_window)->contents[kbd_fetch_ptr
- kbd_buffer]
make it run again now, to avoid timing error. */
if (!NILP (Vquit_flag))
quit_throw_to_read_char ();
-
- /* If alarm has gone off already, echo now. */
- if (echo_flag)
- {
- echo ();
- echo_flag = 0;
- }
}
clear_waiting_for_input ()
printf ("you can continue or abort.\n");
#endif /* not VMS */
#endif /* not SIGTSTP */
+#ifdef MSDOS
+ /* We must remain inside the screen area when the internal terminal
+ is used. Note that [Enter] is not echoed by dos. */
+ cursor_to (0, 0);
+#endif
printf ("Auto-save? (y or n) ");
fflush (stdout);
if (((c = getchar ()) & ~040) == 'Y')
- Fdo_auto_save (Qnil, Qnil);
+ {
+ Fdo_auto_save (Qt, Qnil);
+#ifdef MSDOS
+ printf ("\r\nAuto-save done");
+#else /* not MSDOS */
+ printf ("Auto-save done\n");
+#endif /* not MSDOS */
+ }
while (c != '\n') c = getchar ();
+#ifdef MSDOS
+ printf ("\r\nAbort? (y or n) ");
+#else /* not MSDOS */
#ifdef VMS
printf ("Abort (and enter debugger)? (y or n) ");
#else /* not VMS */
printf ("Abort (and dump core)? (y or n) ");
#endif /* not VMS */
+#endif /* not MSDOS */
fflush (stdout);
if (((c = getchar ()) & ~040) == 'Y')
abort ();
while (c != '\n') c = getchar ();
+#ifdef MSDOS
+ printf ("\r\nContinuing...\r\n");
+#else /* not MSDOS */
printf ("Continuing...\n");
+#endif /* not MSDOS */
fflush (stdout);
init_sys_modes ();
}
if (poll_suppress_count == 0)
abort ();
#endif
+#ifdef MULTI_FRAME
+ if (XTYPE (internal_last_event_frame) == Lisp_Frame
+ && XFRAME (internal_last_event_frame) != selected_frame)
+ Fhandle_switch_frame (make_lispy_switch_frame (internal_last_event_frame));
+#endif
_longjmp (getcjmp, 1);
}
if (!NILP (quit)
&& (XTYPE (quit) != Lisp_Int
|| XINT (quit) < 0 || XINT (quit) > 0400))
- error ("set-input-mode: QUIT must be an ASCII character.");
+ error ("set-input-mode: QUIT must be an ASCII character");
+
+#ifdef POLL_FOR_INPUT
+ stop_polling ();
+#endif
reset_sys_modes ();
#ifdef SIGIO
quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
init_sys_modes ();
+
+#ifdef POLL_FOR_INPUT
+ poll_suppress_count = 1;
+ start_polling ();
+#endif
return Qnil;
}
val[0] = interrupt_input ? Qt : Qnil;
val[1] = flow_control ? Qt : Qnil;
val[2] = meta_key == 2 ? make_number (0) : meta_key == 1 ? Qt : Qnil;
- XSETINT (val[3], quit_char);
+ XFASTINT (val[3]) = quit_char;
- return Flist (val, sizeof (val) / sizeof (val[0]));
+ return Flist (sizeof (val) / sizeof (val[0]), val);
}
\f
syms_of_keyboard ()
{
+ Qdisabled_command_hook = intern ("disabled-command-hook");
+ staticpro (&Qdisabled_command_hook);
+
Qself_insert_command = intern ("self-insert-command");
staticpro (&Qself_insert_command);
Qdisabled = intern ("disabled");
staticpro (&Qdisabled);
+ Qundefined = intern ("undefined");
+ staticpro (&Qundefined);
+
Qpre_command_hook = intern ("pre-command-hook");
staticpro (&Qpre_command_hook);
Qpost_command_hook = intern ("post-command-hook");
staticpro (&Qpost_command_hook);
+ Qcommand_hook_internal = intern ("command-hook-internal");
+ staticpro (&Qcommand_hook_internal);
+
Qfunction_key = intern ("function-key");
staticpro (&Qfunction_key);
Qmouse_click = intern ("mouse-click");
this_command_keys = Fmake_vector (make_number (40), Qnil);
staticpro (&this_command_keys);
+ Qextended_command_history = intern ("extended-command-history");
+ Fset (Qextended_command_history, Qnil);
+ staticpro (&Qextended_command_history);
+
kbd_buffer_frame_or_window
= Fmake_vector (make_number (KBD_BUFFER_SIZE), Qnil);
staticpro (&kbd_buffer_frame_or_window);
defsubr (&Scurrent_input_mode);
defsubr (&Sexecute_extended_command);
- DEFVAR_LISP ("disabled-command-hook", &Vdisabled_command_hook,
- "Value is called instead of any command that is disabled\n\
-\(has a non-nil `disabled' property).");
-
DEFVAR_LISP ("last-command-char", &last_command_char,
"Last input event that was part of a command.");
Polling is automatically disabled in all other cases.");
polling_period = 2;
+ DEFVAR_LISP ("double-click-time", &Vdouble_click_time,
+ "*Maximum time between mouse clicks to make a double-click.\n\
+Measured in milliseconds. nil means disable double-click recognition;\n\
+t means double-clicks have no time limit and are detected\n\
+by position only.");
+ Vdouble_click_time = make_number (500);
+
DEFVAR_INT ("num-input-keys", &num_input_keys,
"*Number of complete keys read from the keyboard so far.");
num_input_keys = 0;
Vlast_event_frame = Qnil;
#endif
- DEFVAR_LISP ("help-char", &help_char,
+ DEFVAR_LISP ("help-char", &Vhelp_char,
"Character to recognize as meaning Help.\n\
When it is read, do `(eval help-form)', and display result if it's a string.\n\
If the value of `help-form' is nil, this char can be read normally.");
- XSET (help_char, Lisp_Int, Ctl ('H'));
+ XSET (Vhelp_char, Lisp_Int, Ctl ('H'));
DEFVAR_LISP ("help-form", &Vhelp_form,
- "Form to execute when character help-char is read.\n\
+ "Form to execute when character `help-char' is read.\n\
If the form returns a string, that string is displayed.\n\
If `help-form' is nil, the help char is not recognized.");
Vhelp_form = Qnil;
+ DEFVAR_LISP ("prefix-help-command", &Vprefix_help_command,
+ "Command to run when `help-char' character follows a prefix key.\n\
+This command is used only when there is no actual binding\n\
+for that character after that prefix key.");
+ Vprefix_help_command = Qnil;
+
DEFVAR_LISP ("top-level", &Vtop_level,
"Form to evaluate when Emacs starts up.\n\
Useful to set before you dump a modified Emacs.");
If string is of length N, character codes N and up are untranslated.");
Vkeyboard_translate_table = Qnil;
+ DEFVAR_LISP ("key-translation-map", &Vkey_translation_map,
+ "Keymap of key translations that can override keymaps.\n\
+This keymap works like `function-key-map', but comes after that,\n\
+and applies even for keys that have ordinary bindings.");
+ Vkey_translation_map = Qnil;
+
+ DEFVAR_BOOL ("cannot-suspend", &cannot_suspend,
+ "Non-nil means to always spawn a subshell instead of suspending,\n\
+even if the operating system has support for stopping a process.");
+ cannot_suspend = 0;
+
DEFVAR_BOOL ("menu-prompting", &menu_prompting,
"Non-nil means prompt with menus when appropriate.\n\
This is done when reading from a keymap that has a prompt string,\n\
\n\
Note that the character ?\C-@, equivalent to the integer zero, does\n\
not count as a control character; rather, it counts as a character\n\
-with no modifiers; thus, setting extra_keyboard_modifiers to zero\n\
+with no modifiers; thus, setting `extra-keyboard-modifiers' to zero\n\
cancels any modification.");
extra_keyboard_modifiers = 0;
Buffer modification stores t in this variable.");
Vdeactivate_mark = Qnil;
+ DEFVAR_LISP ("command-hook-internal", &Vcommand_hook_internal,
+ "Temporary storage of pre-command-hook or post-command-hook.");
+ Vcommand_hook_internal = Qnil;
+
DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
"Normal hook run before each command is executed.");
Vpre_command_hook = Qnil;
DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
- "Normal hook run before each command is executed.");
+ "Normal hook run after each command is executed.");
Vpost_command_hook = Qnil;
DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
"t means menu bar, specified Lucid style, needs to be recomputed.");
Vlucid_menu_bar_dirty_flag = Qnil;
+
+ DEFVAR_LISP ("menu-bar-final-items", &Vmenu_bar_final_items,
+ "List of menu bar items to move to the end of the menu bar.\n\
+The elements of the list are event types that may have menu bar bindings.");
+ Vmenu_bar_final_items = Qnil;
+
+ DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
+ "Keymap that overrides all other local keymaps.\n\
+If this variable is non-nil, it is used as a keymap instead of the\n\
+buffer's local map, and the minor mode keymaps and text property keymaps.");
+ Voverriding_local_map = Qnil;
+
+ DEFVAR_BOOL ("track-mouse", &do_mouse_tracking,
+ "*Non-nil means generate motion events for mouse motion.");
+
+ DEFVAR_LISP ("system-key-alist", &Vsystem_key_alist,
+ "Alist of system-specific X windows key symbols.\n\
+Each element should have the form (N . SYMBOL) where N is the\n\
+numeric keysym code (sans the \"system-specific\" bit 1<<28)\n\
+and SYMBOL is its name.");
+ Vmenu_bar_final_items = Qnil;
}
keys_of_keyboard ()