/* Keyboard and mouse input; editor command loop.
- Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000, 2001
+ Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000, 01, 02
Free Software Foundation, Inc.
This file is part of GNU Emacs.
queue. That way, they'll be dequeued as dead frames or windows,
but still valid Lisp objects.
- If kbd_buffer[i].kind != no_event, then
+ If kbd_buffer[i].kind != NO_EVENT, then
AREF (kbd_buffer_gcpro, 2 * i) == kbd_buffer[i].frame_or_window.
AREF (kbd_buffer_gcpro, 2 * i + 1) == kbd_buffer[i].arg. */
static EMACS_TIME timer_idleness_start_time;
+/* After Emacs stops being idle, this saves the last value
+ of timer_idleness_start_time from when it was idle. */
+
+static EMACS_TIME timer_last_idleness_start_time;
+
\f
/* Global variable declarations. */
static int read_avail_input P_ ((int));
static void get_input_pending P_ ((int *, int));
+static void get_filtered_input_pending P_ ((int *, int, int));
static int readable_events P_ ((int));
+static int readable_filtered_events P_ ((int, int));
static Lisp_Object read_char_x_menu_prompt P_ ((int, Lisp_Object *,
Lisp_Object, int *));
static Lisp_Object read_char_x_menu_prompt ();
/* 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 (do_timers_now)
+readable_filtered_events (do_timers_now, filter_events)
int do_timers_now;
+ int filter_events;
{
if (do_timers_now)
timer_check (do_timers_now);
/* If the buffer contains only FOCUS_IN_EVENT events,
- report it as empty. */
+ and FILTER_EVENTS is nonzero, report it as empty. */
if (kbd_fetch_ptr != kbd_store_ptr)
{
- struct input_event *event;
-
- event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
- ? kbd_fetch_ptr
- : kbd_buffer);
+ int have_live_event = 1;
- while (event->kind == FOCUS_IN_EVENT)
- {
- event++;
- if (event == kbd_buffer + KBD_BUFFER_SIZE)
- event = kbd_buffer;
- if (event == kbd_store_ptr)
- return 0;
- }
- return 1;
+ if (filter_events)
+ {
+ struct input_event *event;
+
+ event = ((kbd_fetch_ptr < kbd_buffer + KBD_BUFFER_SIZE)
+ ? kbd_fetch_ptr
+ : kbd_buffer);
+
+ while (have_live_event && event->kind == FOCUS_IN_EVENT)
+ {
+ event++;
+ if (event == kbd_buffer + KBD_BUFFER_SIZE)
+ event = kbd_buffer;
+ if (event == kbd_store_ptr)
+ have_live_event = 0;
+ }
+ }
+ if (have_live_event) return 1;
}
#ifdef HAVE_MOUSE
return 0;
}
+/* 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 (do_timers_now)
+ int do_timers_now;
+{
+ return readable_filtered_events (do_timers_now, 0);
+}
+
/* Set this for debugging, to have a way to get out */
int stop_character;
kbd_buffer_store_event (event)
register struct input_event *event;
{
- if (event->kind == no_event)
+ if (event->kind == NO_EVENT)
abort ();
- if (event->kind == ascii_keystroke)
+ if (event->kind == ASCII_KEYSTROKE_EVENT)
{
register int c = event->code & 0377;
if (c == quit_char)
{
- static SIGTYPE interrupt_signal (int);
+ static SIGTYPE interrupt_signal P_ ((int));
#ifdef MULTI_KBOARD
KBOARD *kb;
struct input_event *sp;
if (event_to_kboard (sp) == kb)
{
- sp->kind = no_event;
+ sp->kind = NO_EVENT;
sp->frame_or_window = Qnil;
sp->arg = Qnil;
}
return;
}
}
- /* Don't insert two buffer_switch_event's in a row.
+ /* Don't insert two BUFFER_SWITCH_EVENT's in a row.
Just ignore the second one. */
- else if (event->kind == buffer_switch_event
+ else if (event->kind == BUFFER_SWITCH_EVENT
&& kbd_fetch_ptr != kbd_store_ptr
- && kbd_store_ptr->kind == buffer_switch_event)
+ && kbd_store_ptr->kind == BUFFER_SWITCH_EVENT)
return;
if (kbd_store_ptr - kbd_buffer == KBD_BUFFER_SIZE)
{
int idx;
-#if 0 /* The selection_request_event case looks bogus, and it's error
+#if 0 /* The SELECTION_REQUEST_EVENT case looks bogus, and it's error
prone to assign individual members for other events, in case
the input_event structure is changed. --2000-07-13, gerd. */
struct input_event *sp = kbd_store_ptr;
sp->kind = event->kind;
- if (event->kind == selection_request_event)
+ 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
\f
/* Discard any mouse events in the event buffer by setting them to
- no_event. */
+ NO_EVENT. */
void
discard_mouse_events ()
{
if (sp == kbd_buffer + KBD_BUFFER_SIZE)
sp = kbd_buffer;
- if (sp->kind == mouse_click
+ if (sp->kind == MOUSE_CLICK_EVENT
#ifdef WINDOWSNT
- || sp->kind == w32_scroll_bar_click
+ || sp->kind == W32_SCROLL_BAR_CLICK_EVENT
#endif
- || sp->kind == scroll_bar_click)
+ || sp->kind == SCROLL_BAR_CLICK_EVENT)
{
- sp->kind = no_event;
+ sp->kind = NO_EVENT;
}
}
}
/* Return non-zero if there are any real events waiting in the event
- buffer, not counting `no_event's.
+ buffer, not counting `NO_EVENT's.
- If DISCARD is non-zero, discard no_event events at the front of
+ If DISCARD is non-zero, discard NO_EVENT events at the front of
the input queue, possibly leaving the input queue empty if there
are no real input events. */
struct input_event *sp;
for (sp = kbd_fetch_ptr;
- sp != kbd_store_ptr && sp->kind == no_event;
+ sp != kbd_store_ptr && sp->kind == NO_EVENT;
++sp)
{
if (sp == kbd_buffer + KBD_BUFFER_SIZE)
if (discard)
kbd_fetch_ptr = sp;
- return sp != kbd_store_ptr && sp->kind != no_event;
+ return sp != kbd_store_ptr && sp->kind != NO_EVENT;
}
\f
int idx = 2 * (event - kbd_buffer);
ASET (kbd_buffer_gcpro, idx, Qnil);
ASET (kbd_buffer_gcpro, idx + 1, Qnil);
- event->kind = no_event;
+ event->kind = NO_EVENT;
}
/* These two kinds of events get special handling
and don't actually appear to the command loop.
We return nil for them. */
- if (event->kind == selection_request_event)
+ if (event->kind == SELECTION_REQUEST_EVENT)
{
#ifdef HAVE_X11
struct input_event copy;
#endif
}
- else if (event->kind == selection_clear_event)
+ else if (event->kind == SELECTION_CLEAR_EVENT)
{
#ifdef HAVE_X11
struct input_event copy;
#endif
}
#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (MAC_OS)
- else if (event->kind == delete_window_event)
+ else if (event->kind == DELETE_WINDOW_EVENT)
{
/* Make an event (delete-frame (FRAME)). */
obj = Fcons (event->frame_or_window, Qnil);
}
#endif
#if defined (HAVE_X11) || defined (HAVE_NTGUI)
- else if (event->kind == iconify_event)
+ else if (event->kind == ICONIFY_EVENT)
{
/* Make an event (iconify-frame (FRAME)). */
obj = Fcons (event->frame_or_window, Qnil);
obj = Fcons (Qiconify_frame, Fcons (obj, Qnil));
kbd_fetch_ptr = event + 1;
}
- else if (event->kind == deiconify_event)
+ else if (event->kind == DEICONIFY_EVENT)
{
/* Make an event (make-frame-visible (FRAME)). */
obj = Fcons (event->frame_or_window, Qnil);
kbd_fetch_ptr = event + 1;
}
#endif
- else if (event->kind == buffer_switch_event)
+ else if (event->kind == BUFFER_SWITCH_EVENT)
{
/* The value doesn't matter here; only the type is tested. */
XSETBUFFER (obj, current_buffer);
kbd_fetch_ptr = event + 1;
}
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS)
- else if (event->kind == menu_bar_activate_event)
+ else if (event->kind == MENU_BAR_ACTIVATE_EVENT)
{
kbd_fetch_ptr = event + 1;
input_pending = readable_events (0);
}
#endif
#ifdef WINDOWSNT
- else if (event->kind == language_change_event)
+ else if (event->kind == LANGUAGE_CHANGE_EVENT)
{
/* Make an event (language-change (FRAME CHARSET LCID)). */
obj = Fcons (event->modifiers, Qnil);
kbd_fetch_ptr = event + 1;
}
#endif
- else if (event->kind == save_session_event)
+ else if (event->kind == SAVE_SESSION_EVENT)
{
obj = Fcons (Qsave_session, Qnil);
kbd_fetch_ptr = event + 1;
(They shouldn't otherwise be found in the buffer,
but on some machines it appears they do show up
even without MULTI_KBOARD.) */
- /* On Windows NT/9X, no_event is used to delete extraneous
+ /* On Windows NT/9X, NO_EVENT is used to delete extraneous
mouse events during a popup-menu call. */
- else if (event->kind == no_event)
+ else if (event->kind == NO_EVENT)
kbd_fetch_ptr = event + 1;
else if (event->kind == HELP_EVENT)
{
/* These two kinds of events get special handling
and don't actually appear to the command loop. */
- if (event->kind == selection_request_event)
+ if (event->kind == SELECTION_REQUEST_EVENT)
{
#ifdef HAVE_X11
struct input_event copy;
#endif
}
- else if (event->kind == selection_clear_event)
+ else if (event->kind == SELECTION_CLEAR_EVENT)
{
#ifdef HAVE_X11
struct input_event copy;
EMACS_GET_TIME (timer_idleness_start_time);
+ timer_last_idleness_start_time = timer_idleness_start_time;
+
/* Mark all idle-time timers as once again candidates for running. */
for (timers = Vtimer_idle_list; CONSP (timers); timers = XCDR (timers))
{
switch (SWITCH_ENUM_CAST (event->kind))
{
/* A simple keystroke. */
- case ascii_keystroke:
+ case ASCII_KEYSTROKE_EVENT:
{
Lisp_Object lispy_c;
int c = event->code & 0377;
return lispy_c;
}
- case multibyte_char_keystroke:
+ case MULTIBYTE_CHAR_KEYSTROKE_EVENT:
{
Lisp_Object lispy_c;
/* A function key. The symbol may need to have modifier prefixes
tacked onto it. */
- case non_ascii_keystroke:
+ case NON_ASCII_KEYSTROKE_EVENT:
button_down_time = 0;
for (i = 0; i < sizeof (lispy_accent_codes) / sizeof (int); i++)
#ifdef HAVE_MOUSE
/* A mouse click. Figure out where it is, decide whether it's
a press, click or drag, and build the appropriate structure. */
- case mouse_click:
+ case MOUSE_CLICK_EVENT:
#ifndef USE_TOOLKIT_SCROLL_BARS
- case scroll_bar_click:
+ case SCROLL_BAR_CLICK_EVENT:
#endif
{
int button = event->code;
position = Qnil;
/* Build the position as appropriate for this mouse click. */
- if (event->kind == mouse_click)
+ if (event->kind == MOUSE_CLICK_EVENT)
{
int part;
struct frame *f = XFRAME (event->frame_or_window);
index of type `enum scroll_bar_part' which we can use as an
index in scroll_bar_parts to get the appropriate symbol. */
- case scroll_bar_click:
+ case SCROLL_BAR_CLICK_EVENT:
{
Lisp_Object position, head, window, portion_whole, part;
#endif /* USE_TOOLKIT_SCROLL_BARS */
#ifdef WINDOWSNT
- case w32_scroll_bar_click:
+ case W32_SCROLL_BAR_CLICK_EVENT:
{
int button = event->code;
int is_double;
Qnil));
}
}
- case mouse_wheel:
+ case MOUSE_WHEEL_EVENT:
{
int part;
FRAME_PTR f = XFRAME (event->frame_or_window);
}
#endif /* WINDOWSNT */
- case drag_n_drop:
+ case DRAG_N_DROP_EVENT:
{
int part;
FRAME_PTR f;
/* A user signal. */
return *lispy_user_signals[event->code];
- case save_session_event:
+ case SAVE_SESSION_EVENT:
return Qsave_session;
/* The 'kind' field of the event is something we don't recognize. */
but works even if FIONREAD does not exist.
(In fact, this may actually read some input.)
- If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe. */
+ If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.
+ If FILTER_EVENTS is nonzero, ignore internal events (FOCUS_IN_EVENT). */
static void
-get_input_pending (addr, do_timers_now)
+get_filtered_input_pending (addr, do_timers_now, filter_events)
int *addr;
int do_timers_now;
+ int filter_events;
{
/* First of all, have we already counted some input? */
- *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
+ *addr = (!NILP (Vquit_flag)
+ || readable_filtered_events (do_timers_now, filter_events));
/* If input is being read as it arrives, and we have none, there is none. */
if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
/* Try to read some input and see how much we get. */
gobble_input (0);
- *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
+ *addr = (!NILP (Vquit_flag)
+ || readable_filtered_events (do_timers_now, filter_events));
+}
+
+/* Store into *addr a value nonzero if terminal input chars are available.
+ Serves the purpose of ioctl (0, FIONREAD, addr)
+ but works even if FIONREAD does not exist.
+ (In fact, this may actually read some input.)
+
+ If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe. */
+
+static void
+get_input_pending (addr, do_timers_now)
+ int *addr;
+ int do_timers_now;
+{
+ get_filtered_input_pending (addr, do_timers_now, 0);
}
/* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary. */
#endif
}
-/* Put a buffer_switch_event in the buffer
+/* Put a BUFFER_SWITCH_EVENT in the buffer
so that read_key_sequence will notice the new current buffer. */
void
struct input_event event;
Lisp_Object tem;
- event.kind = buffer_switch_event;
+ event.kind = BUFFER_SWITCH_EVENT;
event.frame_or_window = Qnil;
event.arg = Qnil;
#endif /* no FIONREAD */
for (i = 0; i < nread; i++)
{
- buf[i].kind = ascii_keystroke;
+ buf[i].kind = ASCII_KEYSTROKE_EVENT;
buf[i].modifiers = 0;
if (meta_key == 1 && (cbuf[i] & 0x80))
buf[i].modifiers = meta_modifier;
kbd_buffer_store_event (&buf[i]);
/* Don't look at input that follows a C-g too closely.
This reduces lossage due to autorepeat on C-g. */
- if (buf[i].kind == ascii_keystroke
+ if (buf[i].kind == ASCII_KEYSTROKE_EVENT
&& buf[i].code == quit_char)
break;
}
struct buffer *starting_buffer;
- /* Nonzero if we seem to have got the beginning of a binding
- in function_key_map. */
- volatile int function_key_possible = 0;
- volatile int key_translation_possible = 0;
-
/* List of events for which a fake prefix key has been generated. */
volatile Lisp_Object fake_prefixed_keys = Qnil;
replay_sequence:
starting_buffer = current_buffer;
- function_key_possible = 0;
- key_translation_possible = 0;
first_unbound = bufsize + 1;
/* Build our list of keymaps.
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
- && keytran_start < t && key_translation_possible)
+ || (first_binding >= nmaps && fkey_start < t)
+ || (first_binding >= nmaps && keytran_start < t)
/* 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
keymap may have changed, so replay the sequence. */
if (BUFFERP (key))
{
+ EMACS_TIME initial_idleness_start_time
+ = timer_last_idleness_start_time;
+
+ /* Resume idle state, using the same start-time as before. */
+ timer_start_idle ();
+ timer_idleness_start_time = initial_idleness_start_time;
+
mock_input = t;
/* Reset the current buffer from the selected window
in case something changed the former and not the latter.
+ first_binding);
/* If KEY wasn't bound, we'll try some fallbacks. */
- if (first_binding >= nmaps)
+ if (first_binding < nmaps)
+ /* This is needed for the following scenario:
+ event 0: a down-event that gets dropped by calling replay_key.
+ event 1: some normal prefix like C-h.
+ After event 0, first_unbound is 0, after event 1 fkey_start
+ and keytran_start are both 1, so when we see that C-h is bound,
+ we need to update first_unbound. */
+ first_unbound = max (t + 1, first_unbound);
+ else
{
Lisp_Object head;
generate mouse events, so it's okay to zero
mock_input in that case too.
+ FIXME: The above paragraph seems just plain
+ wrong, if you consider things like
+ xterm-mouse-mode. -stef
+
Isn't this just the most wonderful code ever? */
if (t == last_real_key_start)
{
/* Record what part of this_command_keys is the current key sequence. */
this_single_command_key_start = this_command_key_count - t;
- /* If the sequence is unbound, see if we can hang a function key
- off the end of it. We only want to scan real keyboard input
- for function key sequences, so if mock_input says that we're
- re-reading old events, don't examine it. */
- if (first_binding >= nmaps
- && t >= mock_input)
+ if (first_binding < nmaps && NILP (submaps[first_binding]))
+ /* There is a binding and it's not a prefix.
+ There is thus no function-key in this sequence.
+ Moving fkey.start is important in this case to allow keytran.start
+ to go over the sequence before we return (since we keep the
+ invariant that keytran.end <= fkey.start). */
+ {
+ if (fkey_start < t)
+ (fkey_start = fkey_end = t, fkey_map = Vfunction_key_map);
+ }
+ else
+ /* If the sequence is unbound, see if we can hang a function key
+ off the end of it. */
{
Lisp_Object fkey_next;
/* Continue scan from fkey_end until we find a bound suffix.
- If we fail, increment fkey_start
- and start fkey_end from there. */
+ If we fail, increment fkey_start and start over from there. */
while (fkey_end < t)
{
Lisp_Object key;
key = keybuf[fkey_end++];
- fkey_next
- = access_keymap (fkey_map, key, 1, 0, 1);
+ fkey_next = access_keymap (fkey_map, key, 1, 0, 1);
/* Handle symbol with autoload definition. */
if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
array, then call the function with no args and use
its value instead. */
if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
- && fkey_end == t)
+ /* If there's a binding (i.e. first_binding >= nmaps)
+ we don't want to apply this function-key-mapping. */
+ && fkey_end == t && first_binding >= nmaps)
{
struct gcpro gcpro1, gcpro2, gcpro3;
Lisp_Object tem;
error ("Function in key-translation-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 ((VECTORP (fkey_next) || STRINGP (fkey_next))
- && fkey_end == t)
+ /* If there's a binding (i.e. first_binding >= nmaps)
+ we don't want to apply this function-key-mapping. */
+ && fkey_end == t && first_binding >= nmaps)
{
int len = XFASTINT (Flength (fkey_next));
{
fkey_end = ++fkey_start;
fkey_map = Vfunction_key_map;
- function_key_possible = 0;
}
}
}
- else if (NILP (submaps[first_binding]))
- /* There is a global binding and it's not a prefix.
- There is thus no function-key in this sequence.
- We can probably show that there can't be any afterwards either
- but I can't seem to find a clear reason why not, so I'll
- be conservative.
- Moving fkey.start is important in this case to allow keytran.start
- to go over the sequence before we return (since we keep the
- invariant that keytran.end <= fkey.start). */
- (fkey_start = max (fkey_start, t), fkey_end = max (fkey_end, t));
/* Look for this sequence in key-translation-map. */
{
error ("Function in key-translation-map returns invalid key sequence");
}
- key_translation_possible = ! NILP (keytran_next);
-
/* 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
{
keytran_end = ++keytran_start;
keytran_map = Vkey_translation_map;
- key_translation_possible = 0;
}
}
}
and cannot be part of a function key or translation,
and is an upper case letter
use the corresponding lower-case letter instead. */
- if (first_binding == nmaps && ! function_key_possible
- && ! key_translation_possible
+ if (first_binding >= nmaps
+ && fkey_start >= t && keytran_start >= t
&& INTEGERP (key)
&& ((((XINT (key) & 0x3ffff)
< XCHAR_TABLE (current_buffer->downcase_table)->size)
and cannot be part of a function key or translation,
and is a shifted function key,
use the corresponding unshifted function key instead. */
- if (first_binding == nmaps && ! function_key_possible
- && ! key_translation_possible
+ if (first_binding >= nmaps
+ && fkey_start >= t && keytran_start >= t
&& SYMBOLP (key))
{
Lisp_Object breakdown;
if (!NILP (Vunread_command_events) || unread_command_char != -1)
return (Qt);
- get_input_pending (&input_pending, 1);
+ get_filtered_input_pending (&input_pending, 1, 1);
return input_pending > 0 ? Qt : Qnil;
}
if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
kbd_fetch_ptr = kbd_buffer;
- if (kbd_fetch_ptr->kind == ascii_keystroke)
+ if (kbd_fetch_ptr->kind == ASCII_KEYSTROKE_EVENT)
stuff_char (kbd_fetch_ptr->code);
- kbd_fetch_ptr->kind = no_event;
+ kbd_fetch_ptr->kind = NO_EVENT;
idx = 2 * (kbd_fetch_ptr - kbd_buffer);
ASET (kbd_buffer_gcpro, idx, Qnil);
ASET (kbd_buffer_gcpro, idx + 1, Qnil);