/* Keyboard and mouse input; editor command loop.
- Copyright (C) 1985,86,87,88,89,93,94,95 Free Software Foundation, Inc.
+ Copyright (C) 1985,86,87,88,89,93,94,95,96 Free Software Foundation, Inc.
This file is part of GNU Emacs.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* Allow config.h to undefine symbols found here. */
#include <signal.h>
#include "xterm.h"
#endif
+#ifdef HAVE_NTGUI
+#include "w32term.h"
+#endif /* HAVE_NTGUI */
+
/* Include systime.h after xterm.h to avoid double inclusion of time.h. */
#include "systime.h"
/* File descriptor to use for input. */
extern int input_fd;
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
/* Make all keyboard buffers much bigger when using X windows. */
#define KBD_BUFFER_SIZE 4096
#else /* No X-windows, character input */
Lisp_Object this_command_keys;
int this_command_key_count;
+/* Record values of this_command_key_count and echo_length ()
+ before this command was read. */
+static int before_command_key_count;
+static int before_command_echo_length;
+/* Values of before_command_key_count and before_command_echo_length
+ saved by reset-this-command-lengths. */
+static int before_command_key_count_1;
+static int before_command_echo_length_1;
+/* Flag set by reset-this-command-lengths,
+ saying to reset the lengths when add_command_key is called. */
+static int before_command_restore_flag;
+
extern int minbuf_level;
extern struct backtrace *backtrace_list;
/* True while displaying for echoing. Delays C-g throwing. */
static int echoing;
+/* True means we can start echoing at the next input pause
+ even though there is something in the echo area. */
+static char *ok_to_echo_at_next_pause;
+
/* Nonzero means disregard local maps for the menu bar. */
static int inhibit_local_menu_bar_menus;
/* Character to recognize as the help char. */
Lisp_Object Vhelp_char;
+/* List of other event types to recognize as meaning "help". */
+Lisp_Object Vhelp_event_list;
+
/* Form to execute when help char is typed. */
Lisp_Object Vhelp_form;
/* List of items that should move to the end of the menu bar. */
Lisp_Object Vmenu_bar_final_items;
+/* Non-nil means show the equivalent key-binding for
+ any M-x command that has one.
+ The value can be a length of time to show the message for.
+ If the value is non-nil and not a number, we wait 2 seconds. */
+Lisp_Object Vsuggest_key_bindings;
+
/* Character that causes a quit. Normally C-g.
If we are running on an ordinary terminal, this must be an ordinary
/* If non-nil, Voverriding_local_map applies to the menu bar. */
Lisp_Object Voverriding_local_map_menu_flag;
+/* Keymap that defines special misc events that should
+ be processed immediately at a low level. */
+Lisp_Object Vspecial_event_map;
+
/* Current depth in recursive edits. */
int command_loop_level;
int last_auto_save;
-/* Last command executed by the editor command loop, not counting
- commands that set the prefix argument. */
-
-Lisp_Object last_command;
-
/* The command being executed by the command loop.
- Commands may set this, and the value set will be copied into last_command
- instead of the actual command. */
+ Commands may set this, and the value set will be copied into
+ current_kboard->Vlast_command instead of the actual command. */
Lisp_Object this_command;
/* The value of point when the last command was executed. */
Lisp_Object Qforward_char;
Lisp_Object Qbackward_char;
Lisp_Object Qundefined;
-Lisp_Object Qdigit_argument, Qnegative_argument;
/* 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;
+/* Another keymap that maps key sequences into key sequences.
+ This one takes precedence over ordinary definitions. */
+extern Lisp_Object Vkey_translation_map;
/* Non-nil means deactivate the mark at end of this command. */
Lisp_Object Vdeactivate_mark;
Lisp_Object Qrecompute_lucid_menubar, Qactivate_menubar_hook;
/* 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 Qpre_command_hook, Vpre_command_hook;
+Lisp_Object Qpost_command_hook, Vpost_command_hook;
Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal;
+/* Hook run after a command if there's no more input soon. */
+Lisp_Object Qpost_command_idle_hook, Vpost_command_idle_hook;
+
+/* Delay time in microseconds before running post-command-idle-hook. */
+int post_command_idle_delay;
/* List of deferred actions to be performed at a later time.
The precise format isn't relevant here; we just check whether it is nil. */
dequeuing functions? Such a flag could be screwed up by interrupts
at inopportune times. */
-/* If this flag is a frame, we check mouse_moved to see when the
+/* If this flag is non-nil, we check mouse_moved to see when the
mouse moves, and motion events will appear in the input stream.
Otherwise, mouse motion is ignored. */
static Lisp_Object do_mouse_tracking;
-#ifdef HAVE_MOUSE
-/* The window system handling code should set this if the mouse has
- moved since the last call to the mouse_position_hook. Calling that
- hook should clear this. Code assumes that if this is set, it can
- call mouse_position_hook to get the promised position, so don't set
- it unless you're prepared to substantiate the claim! */
-int mouse_moved;
-#endif /* HAVE_MOUSE */
-
/* Symbols to head events. */
Lisp_Object Qmouse_movement;
Lisp_Object Qscroll_bar_movement;
/* Symbols to denote kinds of events. */
Lisp_Object Qfunction_key;
Lisp_Object Qmouse_click;
+Lisp_Object Qtimer_event;
/* Lisp_Object Qmouse_movement; - also an event header */
/* Properties of event headers. */
Lisp_Object recursive_edit_unwind (), command_loop ();
Lisp_Object Fthis_command_keys ();
Lisp_Object Qextended_command_history;
+EMACS_TIME timer_check ();
+
+extern char *x_get_keysym_name ();
Lisp_Object Qpolling_period;
+/* List of absolute timers. Appears in order of next scheduled event. */
+Lisp_Object Vtimer_list;
+
+/* List of idle time timers. Appears in order of next scheduled event. */
+Lisp_Object Vtimer_idle_list;
+
+/* Incremented whenever a timer is run. */
+int timers_run;
+
extern Lisp_Object Vprint_level, Vprint_length;
/* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
/* Nonzero while interrupts are temporarily deferred during redisplay. */
int interrupts_deferred;
-/* nonzero means use ^S/^Q for flow control. */
+/* Nonzero means use ^S/^Q for flow control. */
int flow_control;
/* Allow m- file to inhibit use of FIONREAD. */
#endif
#endif
-/* If we support X Windows, turn on the code to poll periodically
+/* If we support a window system, turn on the code to poll periodically
to detect C-g. It isn't actually used when doing interrupt input. */
-#ifdef HAVE_X_WINDOWS
+#ifdef HAVE_WINDOW_SYSTEM
#define POLL_FOR_INPUT
#endif
+
+/* Non-nil enables Column Number mode. */
+Lisp_Object Vcolumn_number_mode;
\f
/* Global variable declarations. */
current_kboard->echo_after_prompt = len;
- echo ();
+ echo_now ();
}
/* Add C to the echo string, if echoing is going on.
}
if (current_kboard->echoptr == current_kboard->echobuf
- && EQ (c, Vhelp_char))
+ && help_char_p (c))
{
strcpy (ptr, " (Type ? for further options)");
ptr += strlen (ptr);
*ptr = 0;
current_kboard->echoptr = ptr;
- echo ();
+ echo_now ();
}
}
current_kboard->echoptr[0] = '-';
current_kboard->echoptr[1] = 0;
- echo ();
+ echo_now ();
}
/* Display the current echo string, and begin echoing if not already
doing so. */
-echo ()
+echo_now ()
{
if (!current_kboard->immediate_echo)
{
current_kboard->immediate_echo = 0;
current_kboard->echoptr = current_kboard->echobuf;
current_kboard->echo_after_prompt = -1;
+ ok_to_echo_at_next_pause = 0;
}
/* Return the length of the current echo string. */
{
int size = XVECTOR (this_command_keys)->size;
+ /* If reset-this-command-length was called recently, obey it now.
+ See the doc string of that function for an explanation of why. */
+ if (before_command_restore_flag)
+ {
+ this_command_key_count = before_command_key_count_1;
+ echo_truncate (before_command_echo_length_1);
+ before_command_restore_flag = 0;
+ }
+
if (this_command_key_count >= size)
{
Lisp_Object new_keys;
Vstandard_output = Qt;
Vstandard_input = Qt;
Vexecuting_macro = Qnil;
- clear_prefix_arg ();
+ current_kboard->Vprefix_arg = Qnil;
cancel_echoing ();
/* Avoid unquittable loop if data contains a circular list. */
old_level = Vprint_level;
old_length = Vprint_length;
- XSETFASTINT(Vprint_level, 10);
- XSETFASTINT(Vprint_length, 10);
- cmd_error_internal (data, 0);
+ XSETFASTINT (Vprint_level, 10);
+ XSETFASTINT (Vprint_length, 10);
+ cmd_error_internal (data, NULL);
Vprint_level = old_level;
Vprint_length = old_length;
Lisp_Object data;
char *context;
{
- Lisp_Object errmsg, tail, errname, file_error;
Lisp_Object stream;
- struct gcpro gcpro1;
- int i;
Vquit_flag = Qnil;
Vinhibit_quit = Qt;
if (context != 0)
write_string_1 (context, -1, stream);
- errname = Fcar (data);
-
- if (EQ (errname, Qerror))
- {
- data = Fcdr (data);
- if (!CONSP (data)) data = Qnil;
- errmsg = Fcar (data);
- file_error = Qnil;
- }
- else
- {
- errmsg = Fget (errname, Qerror_message);
- file_error = Fmemq (Qfile_error,
- Fget (errname, Qerror_conditions));
- }
-
- /* Print an error message including the data items.
- This is done by printing it into a scratch buffer
- and then making a copy of the text in the buffer. */
-
- if (!CONSP (data)) data = Qnil;
- tail = Fcdr (data);
- GCPRO1 (tail);
-
- /* For file-error, make error message by concatenating
- all the data items. They are all strings. */
- if (!NILP (file_error) && !NILP (tail))
- errmsg = XCONS (tail)->car, tail = XCONS (tail)->cdr;
-
- if (STRINGP (errmsg))
- Fprinc (errmsg, stream);
- else
- write_string_1 ("peculiar error", -1, stream);
-
- for (i = 0; CONSP (tail); tail = Fcdr (tail), i++)
- {
- write_string_1 (i ? ", " : ": ", 2, stream);
- if (!NILP (file_error))
- Fprinc (Fcar (tail), stream);
- else
- Fprin1 (Fcar (tail), stream);
- }
- UNGCPRO;
+ print_error_message (data, stream);
/* If the window system or terminal frame hasn't been initialized
yet, or we're in -batch mode, this error should cause Emacs to exit. */
Lisp_Object Fcommand_execute ();
static int read_key_sequence ();
-static void safe_run_hooks ();
+void safe_run_hooks ();
Lisp_Object
command_loop_1 ()
int was_locked = single_kboard;
#endif
+ current_kboard->Vprefix_arg = Qnil;
Vdeactivate_mark = Qnil;
waiting_for_input = 0;
cancel_echoing ();
throw to top level. */
/* Note that the value cell will never directly contain nil
if the symbol is a local variable. */
- if (!NILP (XSYMBOL (Qpost_command_hook)->value) && !NILP (Vrun_hooks))
+ if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
safe_run_hooks (Qpost_command_hook);
if (!NILP (Vdeferred_action_list))
call0 (Vdeferred_action_function);
+ if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
+ {
+ if (NILP (Vunread_command_events)
+ && NILP (Vexecuting_macro)
+ && !NILP (sit_for (0, post_command_idle_delay, 0, 1)))
+ safe_run_hooks (Qpost_command_idle_hook);
+ }
+
/* Do this after running Vpost_command_hook, for consistency. */
- last_command = this_command;
+ current_kboard->Vlast_command = this_command;
while (1)
{
/* If minibuffer on and echo area in use,
wait 2 sec and redraw minibuffer. */
- if (minibuf_level && echo_area_glyphs)
+ if (minibuf_level && echo_area_glyphs
+ && EQ (minibuf_window, echo_area_window))
{
/* Bind inhibit-quit to t so that C-g gets read in
rather than quitting back to the minibuffer. */
Fsit_for (make_number (2), Qnil, Qnil);
unbind_to (count, Qnil);
- echo_area_glyphs = 0;
- no_direct = 1;
+ /* Clear the echo area. */
+ message2 (0);
+
+ /* If a C-g came in before, treat it as input now. */
if (!NILP (Vquit_flag))
{
Vquit_flag = Qnil;
&& !NILP (Ffboundp (Qrecompute_lucid_menubar)))
call0 (Qrecompute_lucid_menubar);
+ before_command_key_count = this_command_key_count;
+ before_command_echo_length = echo_length ();
+
+ this_command = Qnil;
+
/* Read next key sequence; i gets its length. */
i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
Qnil, 0, 1);
last_point_position = PT;
XSETBUFFER (last_point_position_buffer, prev_buffer);
- /* If we're building a prefix argument, override minus and digits. */
- if (current_kboard->prefix_partial && i == 1 && NATNUMP (keybuf[0]))
- {
- if (XFASTINT (keybuf[0]) == '-'
- && NILP (current_kboard->prefix_value))
- cmd = Qnegative_argument;
- else if (XFASTINT (keybuf[0]) >= '0' && XFASTINT (keybuf[0]) <= '9')
- cmd = Qdigit_argument;
- }
-
/* Execute the command. */
this_command = cmd;
/* Note that the value cell will never directly contain nil
if the symbol is a local variable. */
- if (!NILP (XSYMBOL (Qpre_command_hook)->value) && !NILP (Vrun_hooks))
+ if (!NILP (Vpre_command_hook) && !NILP (Vrun_hooks))
safe_run_hooks (Qpre_command_hook);
if (NILP (this_command))
bitch_at_user ();
current_kboard->defining_kbd_macro = Qnil;
update_mode_lines = 1;
- clear_prefix_arg ();
+ current_kboard->Vprefix_arg = Qnil;
}
else
{
- current_prefix_partial = current_kboard->prefix_partial;
- if (current_kboard->prefix_partial)
- finalize_prefix_arg ();
-
- if (NILP (Vprefix_arg) && ! no_direct)
+ if (NILP (current_kboard->Vprefix_arg) && ! no_direct)
{
/* Recognize some common commands in common situations and
do them directly. */
if (EQ (this_command, Qforward_char) && PT < ZV)
{
- struct Lisp_Vector *dp
+ struct Lisp_Char_Table *dp
= window_display_table (XWINDOW (selected_window));
lose = FETCH_CHAR (PT);
SET_PT (PT + 1);
&& !windows_or_buffers_changed
&& EQ (current_buffer->selective_display, Qnil)
&& !detect_input_pending ()
+ && NILP (Vcolumn_number_mode)
&& NILP (Vexecuting_macro))
no_redisplay = direct_output_forward_char (1);
goto directly_done;
}
else if (EQ (this_command, Qbackward_char) && PT > BEGV)
{
- struct Lisp_Vector *dp
+ struct Lisp_Char_Table *dp
= window_display_table (XWINDOW (selected_window));
SET_PT (PT - 1);
lose = FETCH_CHAR (PT);
&& !windows_or_buffers_changed
&& EQ (current_buffer->selective_display, Qnil)
&& !detect_input_pending ()
+ && NILP (Vcolumn_number_mode)
&& NILP (Vexecuting_macro))
no_redisplay = direct_output_forward_char (-1);
goto directly_done;
|| windows_or_buffers_changed
|| !EQ (current_buffer->selective_display, Qnil)
|| detect_input_pending ()
+ || !NILP (Vcolumn_number_mode)
|| !NILP (Vexecuting_macro));
value = internal_self_insert (c, 0);
if (value)
if (!lose
&& (PT == ZV || FETCH_CHAR (PT) == '\n'))
{
- struct Lisp_Vector *dp
+ struct Lisp_Char_Table *dp
= window_display_table (XWINDOW (selected_window));
int lose = c;
/* Here for a command that isn't executed directly */
nonundocount = 0;
- if (NILP (Vprefix_arg))
+ if (NILP (current_kboard->Vprefix_arg))
Fundo_boundary ();
- Fcommand_execute (this_command, Qnil);
+ Fcommand_execute (this_command, Qnil, Qnil, Qnil);
}
directly_done: ;
/* Note that the value cell will never directly contain nil
if the symbol is a local variable. */
- if (!NILP (XSYMBOL (Qpost_command_hook)->value) && !NILP (Vrun_hooks))
+ if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
safe_run_hooks (Qpost_command_hook);
if (!NILP (Vdeferred_action_list))
safe_run_hooks (Qdeferred_action_function);
+ if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
+ {
+ if (NILP (Vunread_command_events)
+ && NILP (Vexecuting_macro)
+ && !NILP (sit_for (0, post_command_idle_delay, 0, 1)))
+ safe_run_hooks (Qpost_command_idle_hook);
+ }
+
/* If there is a prefix argument,
- 1) We don't want last_command to be ``universal-argument''
- (that would be dumb), so don't set last_command,
+ 1) We don't want Vlast_command to be ``universal-argument''
+ (that would be dumb), so don't set Vlast_command,
2) we want to leave echoing on so that the prefix will be
echoed as part of this key sequence, so don't call
cancel_echoing, and
3) we want to leave this_command_key_count non-zero, so that
read_char will realize that it is re-reading a character, and
- not echo it a second time. */
- if (NILP (Vprefix_arg) && !current_kboard->prefix_partial)
+ not echo it a second time.
+
+ If the command didn't actually create a prefix arg,
+ but is merely a frame event that is transparent to prefix args,
+ then the above doesn't apply. */
+ if (NILP (current_kboard->Vprefix_arg) || CONSP (last_command_char))
{
- last_command = this_command;
+ current_kboard->Vlast_command = this_command;
cancel_echoing ();
this_command_key_count = 0;
}
finalize:
/* Install chars successfully executed in kbd macro. */
- if (!NILP (current_kboard->defining_kbd_macro) && NILP (Vprefix_arg)
- && !current_kboard->prefix_partial)
+ if (!NILP (current_kboard->defining_kbd_macro)
+ && NILP (current_kboard->Vprefix_arg))
finalize_kbd_macro_chars ();
#ifdef MULTI_KBOARD
to be nil. Also inhibit quits, so that C-g won't cause the hook
to mysteriously evaporate. */
-static void
+void
safe_run_hooks (hook)
Lisp_Object hook;
{
int count = specpdl_ptr - specpdl;
specbind (Qinhibit_quit, hook);
- internal_condition_case (safe_run_hooks_1, Qerror, safe_run_hooks_error);
+ internal_condition_case (safe_run_hooks_1, Qt, safe_run_hooks_error);
unbind_to (count, Qnil);
}
input_poll_signal (signalnum) /* If we don't have an argument, */
int signalnum; /* some compilers complain in signal calls. */
{
+ /* This causes the call to start_polling at the end
+ to do its job. It also arranges for a quit or error
+ from within read_avail_input to resume polling. */
+ poll_suppress_count++;
if (interrupt_input_blocked == 0
&& !waiting_for_input)
read_avail_input (0);
- signal (SIGALRM, input_poll_signal);
- alarm (polling_period);
+ /* Turn on the SIGALRM handler and request another alarm. */
+ start_polling ();
}
#endif
jmp_buf local_getcjmp;
jmp_buf save_jump;
int key_already_recorded = 0;
+ Lisp_Object tem, save;
Lisp_Object also_record;
also_record = Qnil;
+ before_command_key_count = this_command_key_count;
+ before_command_echo_length = echo_length ();
+
+ retry:
+
if (CONSP (Vunread_command_events))
{
c = XCONS (Vunread_command_events)->car;
Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+ /* Undo what read_char_x_menu_prompt did when it unread
+ additional keys returned by Fx_popup_menu. */
+ if (CONSP (c)
+ && (SYMBOLP (XCONS (c)->car) || INTEGERP (XCONS (c)->car))
+ && NILP (XCONS (c)->cdr))
+ c = XCONS (c)->car;
+
if (this_command_key_count == 0)
goto reread_first;
else
goto reread;
}
+ /* If there is no function key translated before
+ reset-this-command-lengths takes effect, forget about it. */
+ before_command_restore_flag = 0;
+
if (!NILP (Vexecuting_macro))
{
#ifdef MULTI_FRAME
/* Message turns off echoing unless more keystrokes turn it on again. */
if (echo_area_glyphs && *echo_area_glyphs
- && echo_area_glyphs != current_kboard->echobuf)
+ && echo_area_glyphs != current_kboard->echobuf
+ && ok_to_echo_at_next_pause != echo_area_glyphs)
cancel_echoing ();
else
/* If already echoing, continue. */
goto non_reread;
}
+ timer_start_idle ();
+
/* If in middle of key sequence and minibuffer not active,
start echoing if enough time elapses. */
&& this_command_key_count > 0
&& ! noninteractive
&& echo_keystrokes > 0
- && (echo_area_glyphs == 0 || *echo_area_glyphs == 0))
+ && (echo_area_glyphs == 0 || *echo_area_glyphs == 0
+ || ok_to_echo_at_next_pause == echo_area_glyphs))
{
Lisp_Object tem0;
This is because we are probably about to display a menu,
and we don't want to delay before doing so. */
if (EVENT_HAS_PARAMETERS (prev_event))
- echo ();
+ echo_now ();
else
{
save_getcjmp (save_jump);
tem0 = sit_for (echo_keystrokes, 0, 1, 1);
restore_getcjmp (save_jump);
if (EQ (tem0, Qt))
- echo ();
+ echo_now ();
}
}
&& XINT (Vauto_save_timeout) > 0)
{
Lisp_Object tem0;
- int delay = delay_level * XFASTINT (Vauto_save_timeout) / 4;
save_getcjmp (save_jump);
restore_getcjmp (local_getcjmp);
- tem0 = sit_for (delay, 0, 1, 1);
+ tem0 = sit_for (delay_level * XFASTINT (Vauto_save_timeout) / 4,
+ 0, 1, 1);
restore_getcjmp (save_jump);
if (EQ (tem0, Qt))
= XCONS (current_kboard->kbd_queue)->cdr;
if (NILP (current_kboard->kbd_queue))
current_kboard->kbd_queue_has_data = 0;
- input_pending = readable_events ();
+ input_pending = readable_events (0);
#ifdef MULTI_FRAME
if (EVENT_HAS_PARAMETERS (c)
&& EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qswitch_frame))
non_reread:
+ /* Now that we have read an event, Emacs is not idle--
+ unless the event was a timer event. */
+ if (! (CONSP (c) && EQ (XCONS (c)->car, Qtimer_event)))
+ timer_stop_idle ();
+
start_polling ();
if (NILP (c))
if (key_already_recorded)
return c;
+ /* Process special events within read_char
+ and loop around to read another event. */
+ save = Vquit_flag;
+ Vquit_flag = Qnil;
+ tem = get_keyelt (access_keymap (get_keymap_1 (Vspecial_event_map, 0, 0),
+ c, 0, 0), 1);
+ Vquit_flag = save;
+
+ if (!NILP (tem))
+ {
+ int was_locked = single_kboard;
+
+ last_input_char = c;
+ Fcommand_execute (tem, Qnil, Fvector (1, &last_input_char), Qt);
+
+ /* Resume allowing input from any kboard, if that was true before. */
+ if (!was_locked)
+ any_kboard_state ();
+
+ goto retry;
+ }
+
/* Wipe the echo area. */
echo_area_glyphs = 0;
if (STRINGP (Vkeyboard_translate_table)
&& XSTRING (Vkeyboard_translate_table)->size > XFASTINT (c))
XSETINT (c, XSTRING (Vkeyboard_translate_table)->data[XFASTINT (c)]);
+ else if ((VECTORP (Vkeyboard_translate_table)
+ && XVECTOR (Vkeyboard_translate_table)->size > XFASTINT (c))
+ || CHAR_TABLE_P (Vkeyboard_translate_table))
+ {
+ Lisp_Object d;
+ d = Faref (Vkeyboard_translate_table, c);
+ /* nil in keyboard-translate-table means no translation. */
+ if (!NILP (d))
+ c = d;
+ }
}
/* If this event is a mouse click in the menu bar,
from_macro:
reread_first:
+ before_command_key_count = this_command_key_count;
+ before_command_echo_length = echo_length ();
/* Don't echo mouse motion events. */
if (echo_keystrokes
echo_char (c);
if (! NILP (also_record))
echo_char (also_record);
+ /* Once we reread a character, echoing can happen
+ the next time we pause to read a new one. */
+ ok_to_echo_at_next_pause = echo_area_glyphs;
}
/* Record this character as part of the current key. */
num_input_chars++;
/* Process the help character specially if enabled */
- if (EQ (c, Vhelp_char) && !NILP (Vhelp_form))
+ if (!NILP (Vhelp_form) && help_char_p (c))
{
Lisp_Object tem0;
count = specpdl_ptr - specpdl;
return c;
}
+/* Return 1 if should recognize C as "the help character". */
+
+int
+help_char_p (c)
+ Lisp_Object c;
+{
+ Lisp_Object tail;
+
+ if (EQ (c, Vhelp_char))
+ return 1;
+ for (tail = Vhelp_event_list; CONSP (tail); tail = XCONS (tail)->cdr)
+ if (EQ (c, XCONS (tail)->car))
+ return 1;
+ return 0;
+}
+
/* Record the input event C in various ways. */
static void
if (XUINT (c) < 0x100)
putc (XINT (c), dribble);
else
- fprintf (dribble, " 0x%x", XUINT (c));
+ fprintf (dribble, " 0x%x", (int) XUINT (c));
}
else
{
input has been processed. If the only input available was
the sort that we have just disabled, then we need to call
redisplay. */
- if (!readable_events ())
+ if (!readable_events (1))
{
redisplay_preserve_echo_area ();
- get_input_pending (&input_pending);
+ get_input_pending (&input_pending, 1);
}
}
}
record_unwind_protect (tracking_off, do_mouse_tracking);
- XSETFRAME (do_mouse_tracking, selected_frame);
+ do_mouse_tracking = Qt;
val = Fprogn (args);
return unbind_to (count, val);
}
+/* If mouse has moved on some frame, return one of those frames.
+ Return 0 otherwise. */
+
+static FRAME_PTR
+some_mouse_moved ()
+{
+ Lisp_Object tail, frame;
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ if (XFRAME (frame)->mouse_moved)
+ return XFRAME (frame);
+ }
+
+ return 0;
+}
+
#endif /* HAVE_MOUSE */
\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. */
+ kbd_buffer_get_event retrieves them. */
/* 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 ()
+readable_events (do_timers_now)
+ int do_timers_now;
{
+ timer_check (do_timers_now);
if (kbd_fetch_ptr != kbd_store_ptr)
return 1;
#ifdef HAVE_MOUSE
- if (FRAMEP (do_mouse_tracking) && mouse_moved)
+ if (!NILP (do_mouse_tracking) && some_mouse_moved ())
return 1;
#endif
if (single_kboard)
return;
}
}
+ /* Don't insert two buffer_switch_event's in a row.
+ Just ignore the second one. */
+ else if (event->kind == buffer_switch_event
+ && kbd_fetch_ptr != kbd_store_ptr
+ && kbd_store_ptr->kind == buffer_switch_event)
+ return;
if (kbd_store_ptr - kbd_buffer == KBD_BUFFER_SIZE)
kbd_store_ptr = kbd_buffer;
{
register int c;
Lisp_Object obj;
+ EMACS_TIME next_timer_delay;
if (noninteractive)
{
if (kbd_fetch_ptr != kbd_store_ptr)
break;
#ifdef HAVE_MOUSE
- if (FRAMEP (do_mouse_tracking) && mouse_moved)
+ if (!NILP (do_mouse_tracking) && some_mouse_moved ())
break;
#endif
if (kbd_fetch_ptr != kbd_store_ptr)
break;
#ifdef HAVE_MOUSE
- if (FRAMEP (do_mouse_tracking) && mouse_moved)
+ if (!NILP (do_mouse_tracking) && some_mouse_moved ())
break;
#endif
{
and process it again. */
copy = *event;
kbd_fetch_ptr = event + 1;
+ input_pending = readable_events (0);
x_handle_selection_request (©);
#else
/* We're getting selection request events, but we don't have
else if (event->kind == selection_clear_event)
{
#ifdef HAVE_X11
- x_handle_selection_clear (event);
+ struct input_event copy;
+
+ /* Remove it from the buffer before processing it. */
+ copy = *event;
kbd_fetch_ptr = event + 1;
+ input_pending = readable_events (0);
+ x_handle_selection_clear (©);
#else
/* We're getting selection request events, but we don't have
a window system. */
abort ();
#endif
}
-#ifdef HAVE_X11
+#if defined (HAVE_X11) || defined (HAVE_NTGUI)
else if (event->kind == delete_window_event)
{
/* Make an event (delete-frame (FRAME)). */
XSETBUFFER (obj, current_buffer);
kbd_fetch_ptr = event + 1;
}
+#ifdef USE_X_TOOLKIT
+ else if (event->kind == menu_bar_activate_event)
+ {
+ kbd_fetch_ptr = event + 1;
+ input_pending = readable_events (0);
+ x_activate_menubar (XFRAME (event->frame_or_window));
+ }
+#endif
/* Just discard these, by returning nil.
With MULTI_KBOARD, these events are used as placeholders
when we need to randomly delete events from the queue.
if (NILP (obj))
{
obj = make_lispy_event (event);
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
/* If this was a menu selection, then set the flag to inhibit
writing to last_nonmenu_event. Don't do this if the event
we're returning is (menu-bar), though; that indicates the
}
#ifdef HAVE_MOUSE
/* Try generating a mouse motion event. */
- else if (FRAMEP (do_mouse_tracking) && mouse_moved)
+ else if (!NILP (do_mouse_tracking) && some_mouse_moved ())
{
- FRAME_PTR f = XFRAME (do_mouse_tracking);
+ FRAME_PTR f = some_mouse_moved ();
Lisp_Object bar_window;
enum scroll_bar_part part;
Lisp_Object x, y;
something for us to read! */
abort ();
- input_pending = readable_events ();
+ input_pending = readable_events (0);
#ifdef MULTI_FRAME
Vlast_event_frame = internal_last_event_frame;
then return, without reading any user-visible events. */
void
-swallow_events ()
+swallow_events (do_display)
+ int do_display;
{
+ int old_timers_run;
+
while (kbd_fetch_ptr != kbd_store_ptr)
{
struct input_event *event;
{
#ifdef HAVE_X11
struct input_event copy;
+
+ /* Remove it from the buffer before processing it,
+ since otherwise swallow_events called recursively could see it
+ and process it again. */
copy = *event;
kbd_fetch_ptr = event + 1;
+ input_pending = readable_events (0);
x_handle_selection_request (©);
#else
/* We're getting selection request events, but we don't have
else if (event->kind == selection_clear_event)
{
#ifdef HAVE_X11
- x_handle_selection_clear (event);
+ struct input_event copy;
+
+ /* Remove it from the buffer before processing it, */
+ copy = *event;
+
kbd_fetch_ptr = event + 1;
+ input_pending = readable_events (0);
+ x_handle_selection_clear (©);
#else
/* We're getting selection request events, but we don't have
a window system. */
abort ();
#endif
}
+ else if (event->kind == timer_event)
+ {
+ Lisp_Object tem, lisp_event;
+ int was_locked = single_kboard;
+
+ tem = get_keymap_1 (Vspecial_event_map, 0, 0);
+ tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
+ 1);
+ lisp_event = Fcons (Qtimer_event,
+ Fcons (Fcdr (event->frame_or_window), Qnil));
+ kbd_fetch_ptr = event + 1;
+ if (kbd_fetch_ptr == kbd_store_ptr)
+ input_pending = 0;
+ Fcommand_execute (tem, Qnil, Fvector (1, &lisp_event), Qt);
+ timers_run++;
+ if (do_display)
+ redisplay_preserve_echo_area ();
+
+ /* Resume allowing input from any kboard, if that was true before. */
+ if (!was_locked)
+ any_kboard_state ();
+ }
else
break;
}
- get_input_pending (&input_pending);
+ old_timers_run = timers_run;
+ get_input_pending (&input_pending, 1);
+
+ if (timers_run != old_timers_run && do_display)
+ redisplay_preserve_echo_area ();
+}
+\f
+static EMACS_TIME timer_idleness_start_time;
+
+/* Record the start of when Emacs is idle,
+ for the sake of running idle-time timers. */
+
+timer_start_idle ()
+{
+ Lisp_Object timers;
+
+ /* If we are already in the idle state, do nothing. */
+ if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+ return;
+
+ EMACS_GET_TIME (timer_idleness_start_time);
+
+ /* Mark all idle-time timers as once again candidates for running. */
+ for (timers = Vtimer_idle_list; CONSP (timers); timers = XCONS (timers)->cdr)
+ {
+ Lisp_Object timer;
+
+ timer = XCONS (timers)->car;
+
+ if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+ continue;
+ XVECTOR (timer)->contents[0] = Qnil;
+ }
+}
+
+/* Record that Emacs is no longer idle, so stop running idle-time timers. */
+
+timer_stop_idle ()
+{
+ EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
+}
+
+/* This is only for debugging. */
+struct input_event last_timer_event;
+
+/* Check whether a timer has fired. To prevent larger problems we simply
+ disregard elements that are not proper timers. Do not make a circular
+ timer list for the time being.
+
+ Returns the number of seconds to wait until the next timer fires. If a
+ timer is triggering now, return zero seconds.
+ If no timer is active, return -1 seconds.
+
+ If a timer is ripe now, either queue a timer-event,
+ or call the timer's handler function here if DO_IT_NOW is nonzero. */
+
+EMACS_TIME
+timer_check (do_it_now)
+ int do_it_now;
+{
+ EMACS_TIME nexttime;
+ EMACS_TIME now, idleness_now;
+ Lisp_Object timers, idle_timers, chosen_timer;
+ /* Nonzero if we generate some events. */
+ int events_generated = 0;
+ struct gcpro gcpro1, gcpro2, gcpro3;
+
+ EMACS_SET_SECS (nexttime, -1);
+ EMACS_SET_USECS (nexttime, -1);
+
+ /* Always consider the ordinary timers. */
+ timers = Vtimer_list;
+ /* Consider the idle timers only if Emacs is idle. */
+ if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+ idle_timers = Vtimer_idle_list;
+ else
+ idle_timers = Qnil;
+ chosen_timer = Qnil;
+ GCPRO3 (timers, idle_timers, chosen_timer);
+
+ if (CONSP (timers) || CONSP (idle_timers))
+ {
+ EMACS_GET_TIME (now);
+ if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+ EMACS_SUB_TIME (idleness_now, now, timer_idleness_start_time);
+ }
+
+ while (CONSP (timers) || CONSP (idle_timers))
+ {
+ int triggertime = EMACS_SECS (now);
+ Lisp_Object *vector;
+ Lisp_Object timer, idle_timer;
+ EMACS_TIME timer_time, idle_timer_time;
+ EMACS_TIME difference, timer_difference, idle_timer_difference;
+
+ /* Skip past invalid timers and timers already handled. */
+ if (!NILP (timers))
+ {
+ timer = XCONS (timers)->car;
+ if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+ {
+ timers = XCONS (timers)->cdr;
+ continue;
+ }
+ vector = XVECTOR (timer)->contents;
+
+ if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
+ || !INTEGERP (vector[3])
+ || ! NILP (vector[0]))
+ {
+ timers = XCONS (timers)->cdr;
+ continue;
+ }
+ }
+ if (!NILP (idle_timers))
+ {
+ timer = XCONS (idle_timers)->car;
+ if (!VECTORP (timer) || XVECTOR (timer)->size != 8)
+ {
+ idle_timers = XCONS (idle_timers)->cdr;
+ continue;
+ }
+ vector = XVECTOR (timer)->contents;
+
+ if (!INTEGERP (vector[1]) || !INTEGERP (vector[2])
+ || !INTEGERP (vector[3])
+ || ! NILP (vector[0]))
+ {
+ idle_timers = XCONS (idle_timers)->cdr;
+ continue;
+ }
+ }
+
+ /* Set TIMER, TIMER_TIME and TIMER_DIFFERENCE
+ based on the next ordinary timer.
+ TIMER_DIFFERENCE is the distance in time from NOW to when
+ this timer becomes ripe (negative if it's already ripe). */
+ if (!NILP (timers))
+ {
+ timer = XCONS (timers)->car;
+ vector = XVECTOR (timer)->contents;
+ EMACS_SET_SECS (timer_time,
+ (XINT (vector[1]) << 16) | (XINT (vector[2])));
+ EMACS_SET_USECS (timer_time, XINT (vector[3]));
+ EMACS_SUB_TIME (timer_difference, timer_time, now);
+ }
+
+ /* Set IDLE_TIMER, IDLE_TIMER_TIME and IDLE_TIMER_DIFFERENCE
+ based on the next idle timer. */
+ if (!NILP (idle_timers))
+ {
+ idle_timer = XCONS (idle_timers)->car;
+ vector = XVECTOR (idle_timer)->contents;
+ EMACS_SET_SECS (idle_timer_time,
+ (XINT (vector[1]) << 16) | (XINT (vector[2])));
+ EMACS_SET_USECS (idle_timer_time, XINT (vector[3]));
+ EMACS_SUB_TIME (idle_timer_difference, idle_timer_time, idleness_now);
+ }
+
+ /* Decide which timer is the next timer,
+ and set CHOSEN_TIMER, VECTOR and DIFFERENCE accordingly.
+ Also step down the list where we found that timer. */
+
+ if (! NILP (timers) && ! NILP (idle_timers))
+ {
+ EMACS_TIME temp;
+ EMACS_SUB_TIME (temp, timer_difference, idle_timer_difference);
+ if (EMACS_TIME_NEG_P (temp))
+ {
+ chosen_timer = timer;
+ timers = XCONS (timers)->cdr;
+ difference = timer_difference;
+ }
+ else
+ {
+ chosen_timer = idle_timer;
+ idle_timers = XCONS (idle_timers)->cdr;
+ difference = idle_timer_difference;
+ }
+ }
+ else if (! NILP (timers))
+ {
+ chosen_timer = timer;
+ timers = XCONS (timers)->cdr;
+ difference = timer_difference;
+ }
+ else
+ {
+ chosen_timer = idle_timer;
+ idle_timers = XCONS (idle_timers)->cdr;
+ difference = idle_timer_difference;
+ }
+ vector = XVECTOR (chosen_timer)->contents;
+
+ /* If timer is rupe, run it if it hasn't been run. */
+ if (EMACS_TIME_NEG_P (difference)
+ || (EMACS_SECS (difference) == 0
+ && EMACS_USECS (difference) == 0))
+ {
+ if (NILP (vector[0]))
+ {
+ /* Mark the timer as triggered to prevent problems if the lisp
+ code fails to reschedule it right. */
+ vector[0] = Qt;
+
+ /* Run the timer or queue a timer event. */
+ if (do_it_now)
+ {
+ Lisp_Object tem, event;
+ int was_locked = single_kboard;
+
+ tem = get_keymap_1 (Vspecial_event_map, 0, 0);
+ tem = get_keyelt (access_keymap (tem, Qtimer_event, 0, 0),
+ 1);
+ event = Fcons (Qtimer_event, Fcons (chosen_timer, Qnil));
+ Fcommand_execute (tem, Qnil, Fvector (1, &event), Qt);
+ timers_run++;
+
+ /* Resume allowing input from any kboard, if that was true before. */
+ if (!was_locked)
+ any_kboard_state ();
+
+ /* Since we have handled the event,
+ we don't need to tell the caller to wake up and do it. */
+ }
+ else
+ {
+ /* Generate a timer event so the caller will handle it. */
+ struct input_event event;
+
+ event.kind = timer_event;
+ event.modifiers = 0;
+ event.x = event.y = Qnil;
+ event.timestamp = triggertime;
+ /* Store the timer in the frame slot. */
+ event.frame_or_window
+ = Fcons (Fselected_frame (), chosen_timer);
+ kbd_buffer_store_event (&event);
+
+ last_timer_event = event;
+
+ /* Tell caller to handle this event right away. */
+ events_generated = 1;
+ EMACS_SET_SECS (nexttime, 0);
+ EMACS_SET_USECS (nexttime, 0);
+
+ /* Don't queue more than one event at once.
+ When Emacs is ready for another, it will
+ queue the next one. */
+ UNGCPRO;
+ return nexttime;
+ }
+ }
+ }
+ else
+ /* When we encounter a timer that is still waiting,
+ return the amount of time to wait before it is ripe. */
+ {
+ UNGCPRO;
+ /* But if we generated an event,
+ tell the caller to handle it now. */
+ if (events_generated)
+ return nexttime;
+ return difference;
+ }
+ }
+
+ /* No timers are pending in the future. */
+ /* Return 0 if we generated an event, and -1 if not. */
+ UNGCPRO;
+ return nexttime;
}
\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;
"dead-abovedot",
};
+#ifdef HAVE_NTGUI
+#define FUNCTION_KEY_OFFSET 0x0
+
+char *lispy_function_keys[] =
+ {
+ 0, /* 0 */
+
+ 0, /* VK_LBUTTON 0x01 */
+ 0, /* VK_RBUTTON 0x02 */
+ "cancel", /* VK_CANCEL 0x03 */
+ 0, /* VK_MBUTTON 0x04 */
+
+ 0, 0, 0, /* 0x05 .. 0x07 */
+
+ "backspace", /* VK_BACK 0x08 */
+ "tab", /* VK_TAB 0x09 */
+
+ 0, 0, /* 0x0A .. 0x0B */
+
+ "clear", /* VK_CLEAR 0x0C */
+ "return", /* VK_RETURN 0x0D */
+
+ 0, 0, /* 0x0E .. 0x0F */
+
+ "shift", /* VK_SHIFT 0x10 */
+ "control", /* VK_CONTROL 0x11 */
+ "menu", /* VK_MENU 0x12 */
+ "pause", /* VK_PAUSE 0x13 */
+ "capital", /* VK_CAPITAL 0x14 */
+
+ 0, 0, 0, 0, 0, 0, /* 0x15 .. 0x1A */
+
+ 0, /* VK_ESCAPE 0x1B */
+
+ 0, 0, 0, 0, /* 0x1C .. 0x1F */
+
+ 0, /* VK_SPACE 0x20 */
+ "prior", /* VK_PRIOR 0x21 */
+ "next", /* VK_NEXT 0x22 */
+ "end", /* VK_END 0x23 */
+ "home", /* VK_HOME 0x24 */
+ "left", /* VK_LEFT 0x25 */
+ "up", /* VK_UP 0x26 */
+ "right", /* VK_RIGHT 0x27 */
+ "down", /* VK_DOWN 0x28 */
+ "select", /* VK_SELECT 0x29 */
+ "print", /* VK_PRINT 0x2A */
+ "execute", /* VK_EXECUTE 0x2B */
+ "snapshot", /* VK_SNAPSHOT 0x2C */
+ "insert", /* VK_INSERT 0x2D */
+ "delete", /* VK_DELETE 0x2E */
+ "help", /* VK_HELP 0x2F */
+
+ /* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, /* 0x3A .. 0x40 */
+
+ /* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ "lwindow", /* VK_LWIN 0x5B */
+ "rwindow", /* VK_RWIN 0x5C */
+ "apps", /* VK_APPS 0x5D */
+
+ 0, 0, /* 0x5E .. 0x5F */
+
+ "kp-0", /* VK_NUMPAD0 0x60 */
+ "kp-1", /* VK_NUMPAD1 0x61 */
+ "kp-2", /* VK_NUMPAD2 0x62 */
+ "kp-3", /* VK_NUMPAD3 0x63 */
+ "kp-4", /* VK_NUMPAD4 0x64 */
+ "kp-5", /* VK_NUMPAD5 0x65 */
+ "kp-6", /* VK_NUMPAD6 0x66 */
+ "kp-7", /* VK_NUMPAD7 0x67 */
+ "kp-8", /* VK_NUMPAD8 0x68 */
+ "kp-9", /* VK_NUMPAD9 0x69 */
+ "kp-multiply", /* VK_MULTIPLY 0x6A */
+ "kp-add", /* VK_ADD 0x6B */
+ "kp-separator", /* VK_SEPARATOR 0x6C */
+ "kp-subtract", /* VK_SUBTRACT 0x6D */
+ "kp-decimal", /* VK_DECIMAL 0x6E */
+ "kp-divide", /* VK_DIVIDE 0x6F */
+ "f1", /* VK_F1 0x70 */
+ "f2", /* VK_F2 0x71 */
+ "f3", /* VK_F3 0x72 */
+ "f4", /* VK_F4 0x73 */
+ "f5", /* VK_F5 0x74 */
+ "f6", /* VK_F6 0x75 */
+ "f7", /* VK_F7 0x76 */
+ "f8", /* VK_F8 0x77 */
+ "f9", /* VK_F9 0x78 */
+ "f10", /* VK_F10 0x79 */
+ "f11", /* VK_F11 0x7A */
+ "f12", /* VK_F12 0x7B */
+ "f13", /* VK_F13 0x7C */
+ "f14", /* VK_F14 0x7D */
+ "f15", /* VK_F15 0x7E */
+ "f16", /* VK_F16 0x7F */
+ "f17", /* VK_F17 0x80 */
+ "f18", /* VK_F18 0x81 */
+ "f19", /* VK_F19 0x82 */
+ "f20", /* VK_F20 0x83 */
+ "f21", /* VK_F21 0x84 */
+ "f22", /* VK_F22 0x85 */
+ "f23", /* VK_F23 0x86 */
+ "f24", /* VK_F24 0x87 */
+
+ 0, 0, 0, 0, /* 0x88 .. 0x8B */
+ 0, 0, 0, 0, /* 0x8C .. 0x8F */
+
+ "kp-numlock", /* VK_NUMLOCK 0x90 */
+ "scroll", /* VK_SCROLL 0x91 */
+
+ "kp-space", /* VK_NUMPAD_CLEAR 0x92 */
+ "kp-enter", /* VK_NUMPAD_ENTER 0x93 */
+ "kp-prior", /* VK_NUMPAD_PRIOR 0x94 */
+ "kp-next", /* VK_NUMPAD_NEXT 0x95 */
+ "kp-end", /* VK_NUMPAD_END 0x96 */
+ "kp-home", /* VK_NUMPAD_HOME 0x97 */
+ "kp-left", /* VK_NUMPAD_LEFT 0x98 */
+ "kp-up", /* VK_NUMPAD_UP 0x99 */
+ "kp-right", /* VK_NUMPAD_RIGHT 0x9A */
+ "kp-down", /* VK_NUMPAD_DOWN 0x9B */
+ "kp-insert", /* VK_NUMPAD_INSERT 0x9C */
+ "kp-delete", /* VK_NUMPAD_DELETE 0x9D */
+
+ 0, 0, /* 0x9E .. 0x9F */
+
+ /*
+ * VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
+ * Used only as parameters to GetAsyncKeyState() and GetKeyState().
+ * No other API or message will distinguish left and right keys this way.
+ */
+ /* 0xA0 .. 0xEF */
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* 0xF0 .. 0xF5 */
+
+ 0, 0, 0, 0, 0, 0,
+
+ "attn", /* VK_ATTN 0xF6 */
+ "crsel", /* VK_CRSEL 0xF7 */
+ "exsel", /* VK_EXSEL 0xF8 */
+ "ereof", /* VK_EREOF 0xF9 */
+ "play", /* VK_PLAY 0xFA */
+ "zoom", /* VK_ZOOM 0xFB */
+ "noname", /* VK_NONAME 0xFC */
+ "pa1", /* VK_PA1 0xFD */
+ "oem_clear", /* VK_OEM_CLEAR 0xFE */
+ };
+
+#else
+
+#define FUNCTION_KEY_OFFSET 0xff00
+
/* You'll notice that this table is arranged to be conveniently
indexed by X Windows keysym values. */
static char *lispy_function_keys[] =
0, 0, 0, 0, 0, 0, 0, "delete"
};
+#endif /* HAVE_NTGUI */
+
static char *lispy_mouse_names[] =
{
"mouse-1", "mouse-2", "mouse-3", "mouse-4", "mouse-5"
{
/* 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,
+ if (NILP (current_kboard->system_key_syms))
+ current_kboard->system_key_syms = Fcons (Qnil, Qnil);
+ return modify_event_symbol (event->code,
event->modifiers,
Qfunction_key,
current_kboard->Vsystem_key_alist,
- 0, &system_key_syms, 0xffffff);
+ 0, ¤t_kboard->system_key_syms,
+ (unsigned)-1);
}
- return modify_event_symbol (event->code - 0xff00,
+ return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
event->modifiers,
Qfunction_key, Qnil,
lispy_function_keys, &func_key_syms,
/ sizeof (lispy_function_keys[0])));
break;
+ case timer_event:
+ return Fcons (Qtimer_event, Fcons (Fcdr (event->frame_or_window), Qnil));
+
#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. */
return Qnil;
pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
- &column, &row, 0, 1);
+ &column, &row, NULL, 1);
#ifndef USE_X_TOOLKIT
/* In the non-toolkit version, clicks on the menu bar
(In the toolkit version, the toolkit handles the menu bar
and Emacs doesn't know about it until after the user
makes a selection.) */
- if (row >= 0 && row < FRAME_MENU_BAR_LINES (f))
+ if (row >= 0 && row < FRAME_MENU_BAR_LINES (f)
+ && (event->modifiers & down_modifier))
{
Lisp_Object items, item;
int hpos;
int i;
+#if 0
/* Activate the menu bar on the down event. If the
up event comes in before the menu code can deal with it,
just ignore it. */
if (! (event->modifiers & down_modifier))
return Qnil;
+#endif
item = Qnil;
items = FRAME_MENU_BAR_ITEMS (f);
}
#endif /* HAVE_MOUSE */
-#ifdef USE_X_TOOLKIT
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
case menu_bar_event:
/* The event value is in the cdr of the frame_or_window slot. */
if (!CONSP (event->frame_or_window))
#endif
{
/* It's in a frame; which window on that frame? */
- pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row, 0, 1);
+ pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row,
+ NULL, 1);
window = window_from_coordinates (frame, column, row, &area);
}
else
static char *modifier_names[] =
{
"up", "down", "drag", "click", "double", "triple", 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, "alt", "super", "hyper", "shift", "control", "meta"
};
#define NUM_MOD_NAMES (sizeof (modifier_names) / sizeof (modifier_names[0]))
Lisp_Object name_alist;
char **name_table;
Lisp_Object *symbol_table;
- int table_size;
+ unsigned int table_size;
{
Lisp_Object value;
Lisp_Object symbol_int;
- XSETINT (symbol_int, symbol_num);
+ /* Get rid of the "vendor-specific" bit here. */
+ XSETINT (symbol_int, symbol_num & 0xffffff);
/* Is this a request for a valid symbol? */
if (symbol_num < 0 || symbol_num >= table_size)
else if (name_table[symbol_num])
value = intern (name_table[symbol_num]);
+#ifdef HAVE_WINDOW_SYSTEM
+ if (NILP (value))
+ {
+ char *name = x_get_keysym_name (symbol_num);
+ if (name)
+ value = intern (name);
+ }
+#endif
+
if (NILP (value))
{
char buf[20];
such as (ctrl meta backspace), into the usual representation of that
event type as a number or a symbol. */
-Lisp_Object
-convert_event_type_list (event)
- Lisp_Object event;
+DEFUN ("event-convert-list", Fevent_convert_list, Sevent_convert_list, 1, 1, 0,
+ "Convert the event description list EVENT-DESC to an event type.\n\
+EVENT-DESC should contain one base event type (a character or symbol)\n\
+and zero or more modifier names (control, meta, hyper, super, shift, alt,\n\
+drag, down, double or triple).\n\
+The return value is an event type (a character or symbol) which\n\
+has the same base event type and all the specified modifiers.")
+ (event_desc)
+ Lisp_Object event_desc;
{
Lisp_Object base;
int modifiers = 0;
Lisp_Object rest;
base = Qnil;
- rest = event;
+ rest = event_desc;
while (CONSP (rest))
{
Lisp_Object elt;
/* 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.) */
+ (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)
+get_input_pending (addr, do_timers_now)
int *addr;
+ int do_timers_now;
{
/* First of all, have we already counted some input? */
- *addr = !NILP (Vquit_flag) || readable_events ();
+ *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
/* 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 ();
+ *addr = !NILP (Vquit_flag) || readable_events (do_timers_now);
}
/* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary. */
if (n_to_read > sizeof cbuf)
n_to_read = sizeof cbuf;
#else /* no FIONREAD */
-#if defined(USG) || defined(DGUX)
+#if defined (USG) || defined (DGUX)
/* Read some input if available, but don't wait. */
n_to_read = sizeof cbuf;
fcntl (input_fd, F_SETFL, O_NDELAY);
do
{
#ifdef MSDOS
- cbuf[0] = dos_keyread();
+ cbuf[0] = dos_keyread ();
nread = 1;
#else
nread = read (input_fd, cbuf, n_to_read);
reinvoke_input_signal ()
{
#ifdef SIGIO
- kill (0, SIGIO);
+ kill (getpid (), SIGIO);
#endif
}
{
Lisp_Object *tmaps;
- /* Should overriding-local-map apply, here? */
+ /* Should overriding-terminal-local-map and overriding-local-map apply? */
if (!NILP (Voverriding_local_map_menu_flag))
{
- if (NILP (Voverriding_local_map))
- {
- /* Yes, and it is nil. Use just global map. */
- nmaps = 1;
- maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
- }
- else
- {
- /* Yes, and it is non-nil. Use it and the global map. */
- nmaps = 2;
- maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
- maps[0] = Voverriding_local_map;
- }
+ /* Yes, use them (if non-nil) as well as the global map. */
+ maps = (Lisp_Object *) alloca (3 * sizeof (maps[0]));
+ nmaps = 0;
+ if (!NILP (current_kboard->Voverriding_terminal_local_map))
+ maps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
+ if (!NILP (Voverriding_local_map))
+ maps[nmaps++] = Voverriding_local_map;
}
else
{
/* No, so use major and minor mode keymaps. */
- nmaps = current_minor_maps (0, &tmaps) + 2;
- maps = (Lisp_Object *) alloca (nmaps * sizeof (maps[0]));
- bcopy (tmaps, maps, (nmaps - 2) * sizeof (maps[0]));
+ nmaps = current_minor_maps (NULL, &tmaps);
+ maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0]));
+ bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
#ifdef USE_TEXT_PROPERTIES
- maps[nmaps-2] = get_local_map (PT, current_buffer);
+ maps[nmaps++] = get_local_map (PT, current_buffer);
#else
- maps[nmaps-2] = current_buffer->keymap;
+ maps[nmaps++] = current_buffer->keymap;
#endif
}
- maps[nmaps-1] = current_global_map;
+ maps[nmaps++] = current_global_map;
}
/* Look up in each map the dummy prefix key `menu-bar'. */
if (mapno >= nmaps)
return Qnil;
-#if (defined (HAVE_X_WINDOWS) && defined (HAVE_X_MENU)) || defined (MSDOS)
+#ifdef HAVE_MENUS
/* If we got to this point via a mouse click,
use a real menu for mouse selection. */
if (EVENT_HAS_PARAMETERS (prev_event)
value = Fx_popup_menu (prev_event, Flist (nmaps1, realmaps));
if (CONSP (value))
{
+ Lisp_Object tem;
+
+ /* If we got multiple events, unread all but
+ the first.
+ There is no way to prevent those unread events
+ from showing up later in last_nonmenu_event.
+ So turn symbol and integer events into lists,
+ to indicate that they came from a mouse menu,
+ so that when present in last_nonmenu_event
+ they won't confuse things. */
+ for (tem = XCONS (value)->cdr; !NILP (tem);
+ tem = XCONS (tem)->cdr)
+ if (SYMBOLP (XCONS (tem)->car)
+ || INTEGERP (XCONS (tem)->car))
+ XCONS (tem)->car
+ = Fcons (XCONS (tem)->car, Qnil);
+
/* If we got more than one event, put all but the first
onto this list to be read later.
Return just the first event now. */
*used_mouse_menu = 1;
return value;
}
-#endif /* (HAVE_X_WINDOWS && HAVE_X_MENU) || MSDOS */
+#endif /* HAVE_MENUS */
return Qnil ;
}
+/* Buffer in use so far for the minibuf prompts for menu keymaps.
+ We make this bigger when necessary, and never free it. */
+static char *read_char_minibuf_menu_text;
+/* Size of that buffer. */
+static int read_char_minibuf_menu_width;
+
static Lisp_Object
read_char_minibuf_menu_prompt (commandflag, nmaps, maps)
int commandflag ;
register Lisp_Object name;
int nlength;
int width = FRAME_WIDTH (selected_frame) - 4;
- char *menu = (char *) alloca (width + 4);
int idx = -1;
int nobindings = 1;
Lisp_Object rest, vector;
+ char *menu;
if (! menu_prompting)
return Qnil;
+ /* Make sure we have a big enough buffer for the menu text. */
+ if (read_char_minibuf_menu_text == 0)
+ {
+ read_char_minibuf_menu_width = width + 4;
+ read_char_minibuf_menu_text = (char *) xmalloc (width + 4);
+ }
+ else if (width + 4 > read_char_minibuf_menu_width)
+ {
+ read_char_minibuf_menu_width = width + 4;
+ read_char_minibuf_menu_text
+ = (char *) xrealloc (read_char_minibuf_menu_text, width + 4);
+ }
+ menu = read_char_minibuf_menu_text;
+
/* Get the menu name from the first map that has one (a prompt string). */
for (mapno = 0; mapno < nmaps; mapno++)
{
else
{
/* An ordinary element. */
- if ( idx < 0 )
- s = Fcar_safe (Fcdr_safe (elt)); /* alist */
+ Lisp_Object event;
+
+ if (idx < 0)
+ {
+ s = Fcar_safe (Fcdr_safe (elt)); /* alist */
+ event = Fcar_safe (elt);
+ }
else
- s = Fcar_safe(elt); /* vector */
- if (!STRINGP (s))
- /* 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 + 2 < width
- || !notfirst)
{
- int thiswidth;
+ s = Fcar_safe (elt); /* vector */
+ XSETINT (event, idx);
+ }
- /* Punctuate between strings. */
- if (notfirst)
+ /* Ignore the element if it has no prompt string. */
+ if (STRINGP (s) && INTEGERP (event))
+ {
+ /* 1 if the char to type matches the string. */
+ int char_matches;
+ Lisp_Object upcased_event, downcased_event;
+ Lisp_Object desc;
+
+ upcased_event = Fupcase (event);
+ downcased_event = Fdowncase (event);
+ char_matches = (XINT (upcased_event) == XSTRING (s)->data[0]
+ || XINT (downcased_event) == XSTRING (s)->data[0]);
+ if (! char_matches)
+ desc = Fsingle_key_description (event);
+
+ /* If we have room for the prompt string, add it to this line.
+ If this is the first on the line, always add it. */
+ if ((XSTRING (s)->size + i + 2
+ + (char_matches ? 0 : XSTRING (desc)->size + 3))
+ < width
+ || !notfirst)
{
- strcpy (menu + i, ", ");
- i += 2;
+ int thiswidth;
+
+ /* Punctuate between strings. */
+ if (notfirst)
+ {
+ strcpy (menu + i, ", ");
+ i += 2;
+ }
+ notfirst = 1;
+ nobindings = 0 ;
+
+ /* If the char to type doesn't match the string's
+ first char, explicitly show what char to type. */
+ if (! char_matches)
+ {
+ /* Add as much of string as fits. */
+ thiswidth = XSTRING (desc)->size;
+ if (thiswidth + i > width)
+ thiswidth = width - i;
+ bcopy (XSTRING (desc)->data, menu + i, thiswidth);
+ i += thiswidth;
+ strcpy (menu + i, " = ");
+ i += 3;
+ }
+
+ /* Add as much of string as fits. */
+ thiswidth = XSTRING (s)->size;
+ if (thiswidth + i > width)
+ thiswidth = width - i;
+ bcopy (XSTRING (s)->data, menu + i, thiswidth);
+ i += thiswidth;
+ menu[i] = 0;
+ }
+ else
+ {
+ /* If this element does not fit, end the line now,
+ and save the element for the next line. */
+ strcpy (menu + i, "...");
+ break;
}
- notfirst = 1;
- nobindings = 0 ;
-
- /* Add as much of string as fits. */
- thiswidth = XSTRING (s)->size;
- if (thiswidth + i > width)
- thiswidth = width - i;
- bcopy (XSTRING (s)->data, menu + i, thiswidth);
- i += thiswidth;
- menu[i] = 0;
- }
- else
- {
- /* If this element does not fit, end the line now,
- and save the element for the next line. */
- strcpy (menu + i, "...");
- break;
}
/* Move past this element. */
If KEY has no bindings in any of the CURRENT maps, NEXT is left
unmodified.
- NEXT may == CURRENT. */
+ NEXT may be the same array as CURRENT. */
static int
follow_key (key, nmaps, current, defs, next)
int nmaps;
{
int i, first_binding;
+ int did_meta = 0;
/* If KEY is a meta ASCII character, treat it like meta-prefix-char
- followed by the corresponding non-meta character. */
+ followed by the corresponding non-meta character.
+ Put the results into DEFS, since we are going to alter that anyway.
+ Do not alter CURRENT or NEXT. */
if (INTEGERP (key) && (XINT (key) & CHAR_META))
{
for (i = 0; i < nmaps; i++)
if (! NILP (current[i]))
{
- next[i] =
- get_keyelt (access_keymap (current[i], meta_prefix_char, 1, 0));
+ Lisp_Object def;
+ def = 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
disappear. */
- next[i] = get_keymap_1 (next[i], 0, 1);
+ defs[i] = get_keymap_1 (def, 0, 1);
}
else
- next[i] = Qnil;
+ defs[i] = Qnil;
- current = next;
+ did_meta = 1;
XSETINT (key, XFASTINT (key) & ~CHAR_META);
}
{
if (! NILP (current[i]))
{
- defs[i] = get_keyelt (access_keymap (current[i], key, 1, 0));
+ Lisp_Object map;
+ if (did_meta)
+ map = defs[i];
+ else
+ map = current[i];
+
+ defs[i] = get_keyelt (access_keymap (map, key, 1, 0));
if (! NILP (defs[i]))
first_binding = i;
}
int function_key_possible = 0;
int key_translation_possible = 0;
+ /* Save the status of key translation before each step,
+ so that we can restore this after downcasing. */
+ Lisp_Object prev_fkey_map;
+ Lisp_Object prev_fkey_start;
+ Lisp_Object prev_fkey_end;
+
+ Lisp_Object prev_keytran_map;
+ Lisp_Object prev_keytran_start;
+ Lisp_Object prev_keytran_end;
+
int junk;
last_nonmenu_event = Qnil;
{
Lisp_Object *maps;
- if (!NILP (Voverriding_local_map))
+ if (!NILP (current_kboard->Voverriding_terminal_local_map)
+ || !NILP (Voverriding_local_map))
{
- nmaps = 2;
- if (nmaps > nmaps_allocated)
+ if (3 > nmaps_allocated)
{
- submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
- defs = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
- nmaps_allocated = nmaps;
+ submaps = (Lisp_Object *) alloca (3 * sizeof (submaps[0]));
+ defs = (Lisp_Object *) alloca (3 * sizeof (defs[0]));
+ nmaps_allocated = 3;
}
- submaps[0] = Voverriding_local_map;
+ nmaps = 0;
+ if (!NILP (current_kboard->Voverriding_terminal_local_map))
+ submaps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
+ if (!NILP (Voverriding_local_map))
+ submaps[nmaps++] = Voverriding_local_map;
}
else
{
- nmaps = current_minor_maps (0, &maps) + 2;
- if (nmaps > nmaps_allocated)
+ nmaps = current_minor_maps (0, &maps);
+ if (nmaps + 2 > nmaps_allocated)
{
- submaps = (Lisp_Object *) alloca (nmaps * sizeof (submaps[0]));
- defs = (Lisp_Object *) alloca (nmaps * sizeof (defs[0]));
- nmaps_allocated = nmaps;
+ submaps = (Lisp_Object *) alloca ((nmaps+2) * sizeof (submaps[0]));
+ defs = (Lisp_Object *) alloca ((nmaps+2) * sizeof (defs[0]));
+ nmaps_allocated = nmaps + 2;
}
- bcopy (maps, submaps, (nmaps - 2) * sizeof (submaps[0]));
+ bcopy (maps, submaps, nmaps * sizeof (submaps[0]));
#ifdef USE_TEXT_PROPERTIES
- submaps[nmaps-2] = orig_local_map;
+ submaps[nmaps++] = orig_local_map;
#else
- submaps[nmaps-2] = current_buffer->keymap;
+ submaps[nmaps++] = current_buffer->keymap;
#endif
}
- submaps[nmaps-1] = current_global_map;
+ submaps[nmaps++] = current_global_map;
}
/* Find an accurate initial value for first_binding. */
int echo_local_start, keys_local_start, local_first_binding;
if (t >= bufsize)
- error ("key sequence too long");
+ error ("Key sequence too long");
if (INTERACTIVE)
echo_local_start = echo_length ();
if (CONSP (start) && CONSP (XCONS (start)->cdr))
{
pos = POSN_BUFFER_POSN (start);
- if (INTEGERP (pos))
+ if (INTEGERP (pos)
+ && XINT (pos) >= BEG && XINT (pos) <= Z)
{
map_here = get_local_map (XINT (pos), current_buffer);
if (!EQ (map_here, orig_local_map))
if (SYMBOLP (posn))
{
if (t + 1 >= bufsize)
- error ("key sequence too long");
+ error ("Key sequence too long");
keybuf[t] = posn;
keybuf[t+1] = key;
mock_input = t + 2;
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);
+ error ("Key sequence too long");
keybuf[t] = posn;
keybuf[t+1] = key;
Lisp_Object head;
head = EVENT_HEAD (key);
- if (EQ (head, Vhelp_char))
+ if (help_char_p (head) && t > 0)
{
read_key_sequence_cmd = Vprefix_help_command;
keybuf[t++] = key;
if (!used_mouse_menu)
last_nonmenu_event = key;
+ prev_fkey_map = fkey_map;
+ prev_fkey_start = fkey_start;
+ prev_fkey_end = fkey_end;
+
+ prev_keytran_map = keytran_map;
+ prev_keytran_start = keytran_start;
+ prev_keytran_end = keytran_end;
+
/* 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
t = fkey_start + len;
if (t >= bufsize)
- error ("key sequence too long");
+ error ("Key sequence too long");
if (VECTORP (fkey_next))
bcopy (XVECTOR (fkey_next)->contents,
t = keytran_start + len;
if (t >= bufsize)
- error ("key sequence too long");
+ error ("Key sequence too long");
if (VECTORP (keytran_next))
bcopy (XVECTOR (keytran_next)->contents,
&& UPPERCASEP (XINT (key) & 0x3ffff))
|| (XINT (key) & shift_modifier)))
{
+ Lisp_Object new_key;
+
original_uppercase = key;
original_uppercase_position = t - 1;
- if (XINT (key) & shift_modifier)
- XSETINT (key, XINT (key) & ~shift_modifier);
+ if (XINT (new_key) & shift_modifier)
+ XSETINT (new_key, XINT (key) & ~shift_modifier);
else
- XSETINT (key, (DOWNCASE (XINT (key) & 0x3ffff)
- | (XINT (key) & ~0x3ffff)));
+ XSETINT (new_key, (DOWNCASE (XINT (key) & 0x3ffff)
+ | (XINT (key) & ~0x3ffff)));
- keybuf[t - 1] = key;
+ /* We have to do this unconditionally, regardless of whether
+ the lower-case char is defined in the keymaps, because they
+ might get translated through function-key-map. */
+ keybuf[t - 1] = new_key;
mock_input = t;
+
+ fkey_map = prev_fkey_map;
+ fkey_start = prev_fkey_start;
+ fkey_end = prev_fkey_end;
+
+ keytran_map = prev_keytran_map;
+ keytran_start = prev_keytran_start;
+ keytran_end = prev_keytran_end;
+
goto replay_sequence;
}
/* If KEY is not defined in any of the keymaps,
Lisp_Object breakdown;
int modifiers;
- original_uppercase = key;
- original_uppercase_position = t - 1;
-
breakdown = parse_modifiers (key);
modifiers = XINT (XCONS (XCONS (breakdown)->cdr)->car);
if (modifiers & shift_modifier)
{
+ Lisp_Object new_key;
+
+ original_uppercase = key;
+ original_uppercase_position = t - 1;
+
modifiers &= ~shift_modifier;
- key = apply_modifiers (modifiers,
- XCONS (breakdown)->car);
+ new_key = apply_modifiers (modifiers,
+ XCONS (breakdown)->car);
- keybuf[t - 1] = key;
+ keybuf[t - 1] = new_key;
mock_input = t;
+
+ fkey_map = prev_fkey_map;
+ fkey_start = prev_fkey_start;
+ fkey_end = prev_fkey_end;
+
+ keytran_map = prev_keytran_map;
+ keytran_start = prev_keytran_start;
+ keytran_end = prev_keytran_end;
+
goto replay_sequence;
}
}
unread_switch_frame = delayed_switch_frame;
unbind_to (count, Qnil);
- if (dont_downcase_last && t - 1 == original_uppercase_position)
+ /* Don't downcase the last character if the caller says don't.
+ Don't downcase it if the result is undefined, either. */
+ if ((dont_downcase_last || first_binding >= nmaps)
+ && t - 1 == original_uppercase_position)
keybuf[t - 1] = original_uppercase;
/* Occasionally we fabricate events, perhaps by expanding something
return make_event_array (i, keybuf);
}
\f
-DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 2, 0,
+DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0,
"Execute CMD as an editor command.\n\
CMD must be a symbol that satisfies the `commandp' predicate.\n\
Optional second arg RECORD-FLAG non-nil\n\
means unconditionally put this command in `command-history'.\n\
-Otherwise, that is done only if an arg is read using the minibuffer.")
- (cmd, record)
- Lisp_Object cmd, record;
+Otherwise, that is done only if an arg is read using the minibuffer.\n\
+The argument KEYS specifies the value to use instead of (this-command-keys)\n\
+when reading the arguments; if it is nil, (this_command_key_count) is used.\n\
+The argument SPECIAL, if non-nil, means that this command is executing\n\
+a special event, so ignore the prefix argument and don't clear it.")
+ (cmd, record_flag, keys, special)
+ Lisp_Object cmd, record_flag, keys, special;
{
register Lisp_Object final;
register Lisp_Object tem;
struct backtrace backtrace;
extern int debug_on_next_call;
- prefixarg = Vprefix_arg;
- clear_prefix_arg ();
- Vcurrent_prefix_arg = prefixarg;
debug_on_next_call = 0;
+ if (NILP (special))
+ {
+ prefixarg = current_kboard->Vprefix_arg;
+ Vcurrent_prefix_arg = prefixarg;
+ current_kboard->Vprefix_arg = Qnil;
+ }
+ else
+ prefixarg = Qnil;
+
if (SYMBOLP (cmd))
{
tem = Fget (cmd, Qdisabled);
if (!NILP (tem) && !NILP (Vrun_hooks))
- return call1 (Vrun_hooks, Qdisabled_command_hook);
+ {
+ tem = Fsymbol_value (Qdisabled_command_hook);
+ if (!NILP (tem))
+ return call1 (Vrun_hooks, Qdisabled_command_hook);
+ }
}
while (1)
/* If requested, place the macro in the command history. For
other sorts of commands, call-interactively takes care of
this. */
- if (!NILP (record))
+ if (!NILP (record_flag))
Vcommand_history
= Fcons (Fcons (Qexecute_kbd_macro,
Fcons (final, Fcons (prefixarg, Qnil))),
backtrace.nargs = 1;
backtrace.evalargs = 0;
- tem = Fcall_interactively (cmd, record);
+ tem = Fcall_interactively (cmd, record_flag, keys);
backtrace_list = backtrace.next;
return tem;
Vobarray, Qcommandp,
Qt, Qnil, Qextended_command_history);
+ if (STRINGP (function) && XSTRING (function)->size == 0)
+ error ("No command name given");
+
/* Set this_command_keys to the concatenation of saved_keys and
function, followed by a RET. */
{
UNGCPRO;
function = Fintern (function, Qnil);
- Vprefix_arg = prefixarg;
+ current_kboard->Vprefix_arg = prefixarg;
this_command = function;
- return Fcommand_execute (function, Qt);
+ /* If enabled, show which key runs this command. */
+ if (!NILP (Vsuggest_key_bindings)
+ && SYMBOLP (function))
+ {
+ Lisp_Object bindings;
+
+ bindings = Fwhere_is_internal (function, Voverriding_local_map,
+ Qt, Qnil);
+
+ if (!NILP (bindings))
+ {
+ message ("You can run the command `%s' by typing %s",
+ XSYMBOL (function)->name->data,
+ XSTRING (Fkey_description (bindings))->data);
+ Fsit_for ((NUMBERP (Vsuggest_key_bindings)
+ ? Vsuggest_key_bindings : make_number (2)),
+ Qnil, Qnil);
+ }
+ }
+
+ return Fcommand_execute (function, Qt, Qnil, Qnil);
+}
+
+/* Find the set of keymaps now active.
+ Store into *MAPS_P a vector holding the various maps
+ and return the number of them. The vector was malloc'd
+ and the caller should free it. */
+
+int
+current_active_maps (maps_p)
+ Lisp_Object **maps_p;
+{
+ Lisp_Object *tmaps, *maps;
+ int nmaps;
+
+ /* Should overriding-terminal-local-map and overriding-local-map apply? */
+ if (!NILP (Voverriding_local_map_menu_flag))
+ {
+ /* Yes, use them (if non-nil) as well as the global map. */
+ maps = (Lisp_Object *) xmalloc (3 * sizeof (maps[0]));
+ nmaps = 0;
+ if (!NILP (current_kboard->Voverriding_terminal_local_map))
+ maps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
+ if (!NILP (Voverriding_local_map))
+ maps[nmaps++] = Voverriding_local_map;
+ }
+ else
+ {
+ /* No, so use major and minor mode keymaps. */
+ nmaps = current_minor_maps (NULL, &tmaps);
+ maps = (Lisp_Object *) xmalloc ((nmaps + 2) * sizeof (maps[0]));
+ bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
+#ifdef USE_TEXT_PROPERTIES
+ maps[nmaps++] = get_local_map (PT, current_buffer);
+#else
+ maps[nmaps++] = current_buffer->keymap;
+#endif
+ }
+ maps[nmaps++] = current_global_map;
+
+ *maps_p = maps;
+ return nmaps;
}
\f
+/* Return nonzero if input events are pending. */
detect_input_pending ()
{
if (!input_pending)
- get_input_pending (&input_pending);
+ get_input_pending (&input_pending, 0);
+
+ return input_pending;
+}
+
+/* Return nonzero if input events are pending.
+ Execute timers immediately; don't make events for them. */
+
+detect_input_pending_run_timers (do_display)
+ int do_display;
+{
+ int old_timers_run = timers_run;
+
+ if (!input_pending)
+ get_input_pending (&input_pending, 1);
+
+ if (old_timers_run != timers_run && do_display)
+ redisplay_preserve_echo_area ();
return input_pending;
}
if (!NILP (Vunread_command_events) || unread_command_char != -1)
return (Qt);
- return detect_input_pending () ? Qt : Qnil;
+ get_input_pending (&input_pending, 1);
+ return input_pending > 0 ? Qt : Qnil;
}
DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
XVECTOR (this_command_keys)->contents);
}
+DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
+ Sreset_this_command_lengths, 0, 0, 0,
+ "Used for complicated reasons in `universal-argument-other-key'.\n\
+\n\
+`universal-argument-other-key' rereads the event just typed.\n\
+It then gets translated through `function-key-map'.\n\
+The translated event gets included in the echo area and in\n\
+the value of `this-command-keys' in addition to the raw original event.\n\
+That is not right.\n\
+\n\
+Calling this function directs the translated event to replace\n\
+the original event, so that only one version of the event actually\n\
+appears in the echo area and in the value of `this-command-keys.'.")
+ ()
+{
+ before_command_restore_flag = 1;
+ before_command_key_count_1 = before_command_key_count;
+ before_command_echo_length_1 = before_command_echo_length;
+}
+
DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
"Return the current depth in recursive edits.")
()
(file)
Lisp_Object file;
{
- if (NILP (file))
+ if (dribble)
{
- if (dribble)
- {
- fclose (dribble);
- dribble = 0;
- }
+ fclose (dribble);
+ dribble = 0;
}
- else
+ if (!NILP (file))
{
file = Fexpand_file_name (file, Qnil);
dribble = fopen (XSTRING (file)->data, "w");
+ if (dribble == 0)
+ report_file_error ("Opening dribble", Fcons (file, Qnil));
}
return Qnil;
}
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')
+ /* It doesn't work to autosave while GC is in progress;
+ the code used for auto-saving doesn't cope with the mark bit. */
+ if (!gc_in_progress)
{
- Fdo_auto_save (Qt, Qnil);
+ printf ("Auto-save? (y or n) ");
+ fflush (stdout);
+ if (((c = getchar ()) & ~040) == 'Y')
+ {
+ Fdo_auto_save (Qt, Qnil);
#ifdef MSDOS
- printf ("\r\nAuto-save done");
+ printf ("\r\nAuto-save done");
#else /* not MSDOS */
- printf ("Auto-save done\n");
+ printf ("Auto-save done\n");
#endif /* not MSDOS */
+ }
+ while (c != '\n') c = getchar ();
}
- while (c != '\n') c = getchar ();
+ else
+ {
+ /* During GC, it must be safe to reenable quitting again. */
+ Vinhibit_quit = Qnil;
+#ifdef MSDOS
+ printf ("\r\n");
+#endif /* not MSDOS */
+ printf ("Garbage collection in progress; cannot auto-save now\r\n");
+ printf ("but will instead do a real quit after garbage collection ends\r\n");
+ fflush (stdout);
+ }
+
#ifdef MSDOS
printf ("\r\nAbort? (y or n) ");
#else /* not MSDOS */
Vunread_command_events = Qnil;
unread_command_char = -1;
+#if 0 /* Currently, sit_for is called from read_char without turning
+ off polling. And that can call set_waiting_for_input.
+ It seems to be harmless. */
#ifdef POLL_FOR_INPUT
/* May be > 1 if in recursive minibuffer. */
if (poll_suppress_count == 0)
abort ();
#endif
+#endif
#ifdef MULTI_FRAME
if (FRAMEP (internal_last_event_frame)
&& XFRAME (internal_last_event_frame) != selected_frame)
- Fhandle_switch_frame (make_lispy_switch_frame (internal_last_event_frame));
+ do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
+ Qnil, 0);
#endif
_longjmp (getcjmp, 1);
stop_polling ();
#endif
+#ifndef MSDOS
+ /* this causes startup screen to be restored and messes with the mouse */
reset_sys_modes ();
+#endif
+
#ifdef SIGIO
/* Note SIGIO has been undef'd if FIONREAD is missing. */
-#ifdef NO_SOCK_SIGIO
if (read_socket_hook)
- interrupt_input = 0; /* No interrupts if reading from a socket. */
- else
+ {
+ /* When using X, don't give the user a real choice,
+ because we haven't implemented the mechanisms to support it. */
+#ifdef NO_SOCK_SIGIO
+ interrupt_input = 0;
+#else /* not NO_SOCK_SIGIO */
+ interrupt_input = 1;
#endif /* NO_SOCK_SIGIO */
+ }
+ else
interrupt_input = !NILP (interrupt);
#else /* not SIGIO */
interrupt_input = 0;
#endif /* not SIGIO */
+
/* Our VMS input only works by interrupts, as of now. */
#ifdef VMS
interrupt_input = 1;
#endif
+
flow_control = !NILP (flow);
if (NILP (meta))
meta_key = 0;
/* Don't let this value be out of range. */
quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
+#ifndef MSDOS
init_sys_modes ();
+#endif
#ifdef POLL_FOR_INPUT
poll_suppress_count = 1;
init_kboard (kb)
KBOARD *kb;
{
- kb->prefix_factor = Qnil;
- kb->prefix_value = Qnil;
- kb->prefix_sign = 1;
- kb->prefix_partial = 0;
+ kb->Voverriding_terminal_local_map = Qnil;
+ kb->Vlast_command = Qnil;
+ kb->Vprefix_arg = Qnil;
kb->kbd_queue = Qnil;
kb->kbd_queue_has_data = 0;
kb->immediate_echo = 0;
kb->Vlast_kbd_macro = Qnil;
kb->reference_count = 0;
kb->Vsystem_key_alist = Qnil;
+ kb->system_key_syms = Qnil;
kb->Vdefault_minibuffer_frame = Qnil;
}
/*
* Destroy the contents of a kboard object, but not the object itself.
- * We use this just before deleteing it, or if we're going to initialize
+ * We use this just before deleting it, or if we're going to initialize
* it a second time.
*/
static void
quit_char = Ctl ('g');
Vunread_command_events = Qnil;
unread_command_char = -1;
+ EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
total_keys = 0;
recent_keys_index = 0;
kbd_fetch_ptr = kbd_buffer;
Qundefined = intern ("undefined");
staticpro (&Qundefined);
- Qdigit_argument = intern ("digit-argument");
- staticpro (&Qdigit_argument);
-
- Qnegative_argument = intern ("negative-argument");
- staticpro (&Qnegative_argument);
-
Qpre_command_hook = intern ("pre-command-hook");
staticpro (&Qpre_command_hook);
Qpost_command_hook = intern ("post-command-hook");
staticpro (&Qpost_command_hook);
+ Qpost_command_idle_hook = intern ("post-command-idle-hook");
+ staticpro (&Qpost_command_idle_hook);
+
Qdeferred_action_function = intern ("deferred-action-function");
staticpro (&Qdeferred_action_function);
staticpro (&Qfunction_key);
Qmouse_click = intern ("mouse-click");
staticpro (&Qmouse_click);
+ Qtimer_event = intern ("timer-event");
+ staticpro (&Qtimer_event);
Qmenu_enable = intern ("menu-enable");
staticpro (&Qmenu_enable);
func_key_syms = Qnil;
staticpro (&func_key_syms);
- system_key_syms = Qnil;
- staticpro (&system_key_syms);
-
mouse_syms = Qnil;
staticpro (&mouse_syms);
unread_switch_frame = Qnil;
staticpro (&unread_switch_frame);
+ defsubr (&Sevent_convert_list);
defsubr (&Sread_key_sequence);
defsubr (&Srecursive_edit);
#ifdef HAVE_MOUSE
defsubr (&Scommand_execute);
defsubr (&Srecent_keys);
defsubr (&Sthis_command_keys);
+ defsubr (&Sreset_this_command_lengths);
defsubr (&Ssuspend_emacs);
defsubr (&Sabort_recursive_edit);
defsubr (&Sexit_recursive_edit);
turns into this character followed by foo.");
XSETINT (meta_prefix_char, 033);
- DEFVAR_LISP ("last-command", &last_command,
+ DEFVAR_KBOARD ("last-command", Vlast_command,
"The last command executed. Normally a symbol with a function definition,\n\
but can be whatever was found in the keymap, or whatever the variable\n\
`this-command' was set to by that command.\n\
\n\
The value `kill-region' is special; it means that the previous command\n\
was a kill command.");
- last_command = Qnil;
DEFVAR_LISP ("this-command", &this_command,
"The command now being executed.\n\
If the value of `help-form' is nil, this char can be read normally.");
XSETINT (Vhelp_char, Ctl ('H'));
+ DEFVAR_LISP ("help-event-list", &Vhelp_event_list,
+ "List of input events to recognize as meaning Help.\n\
+These work just like the value of `help-char' (see that).");
+ Vhelp_event_list = Qnil;
+
DEFVAR_LISP ("help-form", &Vhelp_form,
"Form to execute when character `help-char' is read.\n\
If the form returns a string, that string is displayed.\n\
Vtop_level = Qnil;
DEFVAR_LISP ("keyboard-translate-table", &Vkeyboard_translate_table,
- "String used as translate table for keyboard input, or nil.\n\
+ "Translate table for keyboard input, or nil.\n\
Each character is looked up in this string and the contents used instead.\n\
-If string is of length N, character codes N and up are untranslated.");
+The value may be a string, a vector, or a char-table.\n\
+If it is a string or vector of length N,\n\
+character codes N and up are untranslated.\n\
+In a vector or a char-table, an element which is nil means \"no translation\".");
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.");
DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
"Normal hook run before each command is executed.\n\
-While the hook is run, its value is temporarily set to nil\n\
-to avoid an unbreakable infinite loop if a hook function gets an error.\n\
-As a result, a hook function cannot straightforwardly alter the value of\n\
-`pre-command-hook'. See the Emacs Lisp manual for a way of\n\
-implementing hook functions that alter the set of hook functions.");
+Errors running the hook are caught and ignored.");
Vpre_command_hook = Qnil;
DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
"Normal hook run after each command is executed.\n\
-While the hook is run, its value is temporarily set to nil\n\
-to avoid an unbreakable infinite loop if a hook function gets an error.\n\
-As a result, a hook function cannot straightforwardly alter the value of\n\
-`post-command-hook'. See the Emacs Lisp manual for a way of\n\
-implementing hook functions that alter the set of hook functions.");
+Errors running the hook are caught and ignored.");
Vpost_command_hook = Qnil;
+ DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
+ "Normal hook run after each command is executed, if idle.\n\
+Errors running the hook are caught and ignored.");
+ Vpost_command_idle_hook = Qnil;
+
+ DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay,
+ "Delay time before running `post-command-idle-hook'.\n\
+This is measured in microseconds.");
+ post_command_idle_delay = 100000;
+
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;
The elements of the list are event types that may have menu bar bindings.");
Vmenu_bar_final_items = Qnil;
+ DEFVAR_KBOARD ("overriding-terminal-local-map",
+ Voverriding_terminal_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.");
+
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\
and the minor mode maps regardless of `overriding-local-map'.");
Voverriding_local_map_menu_flag = Qnil;
+ DEFVAR_LISP ("special-event-map", &Vspecial_event_map,
+ "Keymap defining bindings for special events to execute at low level.");
+ Vspecial_event_map = Fcons (intern ("keymap"), Qnil);
+
DEFVAR_LISP ("track-mouse", &do_mouse_tracking,
"*Non-nil means generate motion events for mouse motion.");
This function is called with no arguments after each command\n\
whenever `deferred-action-list' is non-nil.");
Vdeferred_action_function = Qnil;
+
+ DEFVAR_LISP ("suggest-key-bindings", &Vsuggest_key_bindings,
+ "Non-nil means show the equivalent key-binding when M-x command has one.\n\
+The value can be a length of time to show the message for.\n\
+If the value is non-nil and not a number, we wait 2 seconds.");
+ Vsuggest_key_bindings = Qt;
+
+ DEFVAR_LISP ("column-number-mode", &Vcolumn_number_mode,
+ "Non-nil enables display of the current column number in the mode line.");
+ Vcolumn_number_mode = Qnil;
+
+ DEFVAR_LISP ("timer-list", &Vtimer_list,
+ "List of active absolute time timers in order of increasing time");
+ Vtimer_list = Qnil;
+
+ DEFVAR_LISP ("timer-idle-list", &Vtimer_idle_list,
+ "List of active idle-time timers in order of increasing time");
+ Vtimer_idle_list = Qnil;
}
keys_of_keyboard ()
initial_define_key (meta_map, Ctl ('C'), "exit-recursive-edit");
initial_define_key (global_map, Ctl (']'), "abort-recursive-edit");
initial_define_key (meta_map, 'x', "execute-extended-command");
+
+ initial_define_lispy_key (Vspecial_event_map, "delete-frame",
+ "handle-delete-frame");
+ initial_define_lispy_key (Vspecial_event_map, "iconify-frame",
+ "ignore-event");
+ initial_define_lispy_key (Vspecial_event_map, "make-frame-visible",
+ "ignore-event");
}