diff src/event-stream.c @ 175:2d532a89d707 r20-3b14

Import from CVS: tag r20-3b14
author cvs
date Mon, 13 Aug 2007 09:50:14 +0200
parents 8eaf7971accc
children 6075d714658b
line wrap: on
line diff
--- a/src/event-stream.c	Mon Aug 13 09:49:11 2007 +0200
+++ b/src/event-stream.c	Mon Aug 13 09:50:14 2007 +0200
@@ -38,6 +38,14 @@
 #include <config.h>
 #include "lisp.h"
 
+#ifdef HAVE_X_WINDOWS
+#include "console-x.h"		/* for menu accelerators ... */
+#include "gui-x.h"
+#include "../lwlib/lwlib.h"
+#else
+#define lw_menu_active	0
+#endif
+
 #include "buffer.h"
 #include "commands.h"
 #include "device.h"
@@ -193,6 +201,33 @@
 int recent_keys_ring_size;
 int recent_keys_ring_index;
 
+/* prefix key(s) that must match in order to activate menu.
+   This is ugly.  fix me.
+   */
+Lisp_Object Vmenu_accelerator_prefix;
+
+/* list of modifier keys to match accelerator for top level menus */
+Lisp_Object Vmenu_accelerator_modifiers;
+
+/* whether menu accelerators are enabled */
+Lisp_Object Vmenu_accelerator_enabled;
+
+/* keymap for auxillary menu accelerator functions */
+Lisp_Object Vmenu_accelerator_map;
+
+Lisp_Object Qmenu_force;
+Lisp_Object Qmenu_fallback;
+Lisp_Object Qmenu_quit;
+Lisp_Object Qmenu_up;
+Lisp_Object Qmenu_down;
+Lisp_Object Qmenu_left;
+Lisp_Object Qmenu_right;
+Lisp_Object Qmenu_select;
+Lisp_Object Qmenu_escape;
+
+/* this is in keymap.c */
+extern Lisp_Object Fmake_keymap (Lisp_Object name);
+
 #ifdef DEBUG_XEMACS
 int debug_emacs_events;
 #endif
@@ -652,7 +687,8 @@
     return;
 
   if (minibuf_level == 0
-      && echo_keystrokes > 0)
+      && echo_keystrokes > 0
+      && !lw_menu_active)
     {
       if (!no_snooze)
 	{
@@ -2163,6 +2199,8 @@
       goto RETURN;
     case button_release_event:
     case misc_user_event:
+      /* don't echo menu accelerator keys */
+      reset_key_echo (command_builder, 1);
       goto EXECUTE_KEY;
     case button_press_event:	/* key or mouse input can trigger prompting */
       goto STORE_AND_EXECUTE_KEY;
@@ -2533,7 +2571,6 @@
 	case pointer_motion_event:
 	case magic_event:
           {
-          EXECUTE_INTERNAL:
             execute_internal_event (event);
             break;
           }
@@ -2603,7 +2640,6 @@
 	case pointer_motion_event:
 	case magic_event:
           {
-          EXECUTE_INTERNAL:
             execute_internal_event (event);
             break;
           }
@@ -2745,7 +2781,6 @@
 	     happened above. */
 	default:
 	  {
-	  EXECUTE_INTERNAL:
 	    execute_internal_event (event);
 	    break;
 	  }
@@ -2986,6 +3021,503 @@
   return event_binding (event0, 1);
 }
 
+#ifdef HAVE_X_WINDOWS
+static void
+menu_move_up (void)
+{
+  widget_value *current, *prev;
+  widget_value *entries;
+  
+  current = lw_get_entries (False);
+  entries = lw_get_entries (True);
+  prev = NULL;
+  if (current != entries)
+    {
+      while (entries != current)
+	{
+	  if (entries->name /*&& entries->enabled*/) prev = entries;
+	  entries = entries->next;
+	  assert (entries);
+	}
+    }
+
+  if (!prev)
+    /* move to last item */
+    {
+      while (entries->next)
+	{
+	  if (entries->name /*&& entries->enabled*/) prev = entries;
+	  entries = entries->next;
+	}
+      if (prev)
+	{
+	  if (entries->name /*&& entries->enabled*/)
+	    prev = entries;
+	}
+      else
+	{
+	  /* no selectable items in this menu, pop up to previous level */
+	  lw_pop_menu ();
+	  return;
+	}
+    }
+  lw_set_item (prev);
+}
+
+static void
+menu_move_down (void)
+{
+  widget_value *current;
+  widget_value *new;
+  
+  current = lw_get_entries (False);
+  new = current;
+  
+  while (new->next)
+    {
+      new = new->next;
+      if (new->name /*&& new->enabled*/) break;
+    }
+  
+  if (new==current||!(new->name/*||new->enabled*/))
+    {
+      new = lw_get_entries (True);
+      while (new!=current)
+	{
+	  if (new->name /*&& new->enabled*/) break;
+	  new = new->next;
+	}
+      if (new==current&&!(new->name /*|| new->enabled*/))
+	{
+	  lw_pop_menu ();
+	  return;
+	}
+    }
+  
+  lw_set_item (new);
+}
+
+static void
+menu_move_left (void)
+{
+  int level = lw_menu_level ();
+  int l = level;
+  widget_value *current;
+  
+  while (level >= 3)
+    {
+      --level;
+      lw_pop_menu ();
+    }
+  menu_move_up ();
+  current = lw_get_entries (False);
+  if (l > 2 && current->contents)
+    lw_push_menu (current->contents);
+}
+
+static void
+menu_move_right (void)
+{
+  int level = lw_menu_level ();
+  int l = level;
+  widget_value *current;
+  
+  while (level >= 3)
+    {
+      --level;
+      lw_pop_menu ();
+    }
+  menu_move_down ();
+  current = lw_get_entries (False);
+  if (l > 2 && current->contents)
+    lw_push_menu (current->contents);
+}
+
+static void
+menu_select_item (widget_value *val)
+{
+  if (val == NULL)
+    val = lw_get_entries (False);
+  
+  /* is match a submenu? */
+  
+  if (val->contents)
+    {
+      /* enter the submenu */
+      
+      lw_set_item (val);
+      lw_push_menu (val->contents);
+    }
+  else
+    {
+      /* Execute the menu entry by calling the menu's `select'
+	 callback function
+	 */
+      lw_kill_menus (val);
+    }
+}
+
+static Lisp_Object
+command_builder_operate_menu_accelerator (struct command_builder *builder)
+{
+  /* this function can GC */
+  
+  struct console *con = XCONSOLE (Vselected_console);
+  Lisp_Object evee = builder->most_current_event;
+  Lisp_Object binding;
+  widget_value *entries;
+  
+  extern int lw_menu_accelerate; /* lwlib.c */
+
+#if 0
+  {
+    int i;
+    Lisp_Object t;
+    char buf[50];
+    
+    t = builder->current_events;
+    i = 0;
+    while (!NILP (t))
+      {
+	i++;
+	sprintf(buf,"OPERATE (%d): ",i);
+	write_c_string (buf,Qexternal_debugging_output);
+	print_internal (t, Qexternal_debugging_output, 1);
+	write_c_string ("\n", Qexternal_debugging_output);
+	t = XEVENT_NEXT (t);
+      }
+  }
+#endif
+  
+  /* menu accelerator keys don't go into keyboard macros */
+  if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro))
+    con->kbd_macro_ptr = con->kbd_macro_end;
+  
+  /* don't echo menu accelerator keys */
+  /*reset_key_echo (builder, 1);*/
+  
+  if (!lw_menu_accelerate)
+    {
+      /* `convert' mouse display to keyboard display
+	 by entering the open submenu
+	 */
+      entries = lw_get_entries (False);
+      if (entries->contents)
+	{
+	  lw_push_menu (entries->contents);
+	  lw_display_menu (CurrentTime);
+	}
+    }
+  
+  /* compare event to the current menu accelerators */
+  
+  entries=lw_get_entries (True);
+  
+  while (entries)
+    {
+      Lisp_Object accel;
+      VOID_TO_LISP (accel, entries->accel);
+      if (entries->name && !NILP (accel))
+	{
+	  if (event_matches_key_specifier_p (XEVENT (evee), accel))
+	    {
+	      /* a match! */
+	      
+	      menu_select_item (entries);
+	      
+	      if (lw_menu_active) lw_display_menu (CurrentTime);
+	      
+	      reset_this_command_keys (Vselected_console, 1);
+	      /*reset_command_builder_event_chain (builder);*/
+	      return Vmenu_accelerator_map;
+	    }
+	}
+      entries = entries->next;
+    }
+  
+  /* try to look up event in menu-accelerator-map */
+  
+  binding = event_binding_in (evee, Vmenu_accelerator_map, 1);
+  
+  if (NILP (binding))
+    {
+      /* beep at user for undefined key */
+      return Qnil;
+    }
+  else
+    {
+      if (EQ (binding, Qmenu_quit))
+	{
+	  /* turn off menus and set quit flag */
+	  lw_kill_menus (NULL);
+	  Vquit_flag = Qt;
+	}
+      else if (EQ (binding, Qmenu_up))
+	{
+	  int level = lw_menu_level ();
+	  if (level > 2)
+	    menu_move_up ();
+	}
+      else if (EQ (binding, Qmenu_down))
+	{
+	  int level = lw_menu_level ();
+	  if (level > 2)
+	    menu_move_down ();
+	  else
+	    menu_select_item (NULL);
+	}
+      else if (EQ (binding, Qmenu_left))
+	{
+	  int level = lw_menu_level ();
+	  if (level > 3)
+	    {
+	      lw_pop_menu ();
+	      lw_display_menu (CurrentTime);
+	    }
+	  else
+	    menu_move_left ();
+	}
+      else if (EQ (binding, Qmenu_right))
+	{
+	  int level = lw_menu_level ();
+	  if (level > 2 &&
+	      lw_get_entries (False)->contents)
+	    {
+	      widget_value *current = lw_get_entries (False);
+	      if (current->contents)
+		menu_select_item (NULL);
+	    }
+	  else
+	    menu_move_right ();
+	}
+      else if (EQ (binding, Qmenu_select))
+	menu_select_item (NULL);
+      else if (EQ (binding, Qmenu_escape))
+	{
+	  int level = lw_menu_level ();
+	  
+	  if (level > 2)
+	    {
+	      lw_pop_menu ();
+	      lw_display_menu (CurrentTime);
+	    }
+	  else
+	    {
+	      /* turn off menus quietly */
+	      lw_kill_menus (NULL);
+	    }
+	}
+      else if (KEYMAPP (binding))
+	{
+	  /* prefix key */
+	  reset_this_command_keys (Vselected_console, 1);
+	  /*reset_command_builder_event_chain (builder);*/
+	  return binding;
+	}
+      else
+	{
+	  /* turn off menus and execute binding */
+	  lw_kill_menus (NULL);
+	  reset_this_command_keys (Vselected_console, 1);
+	  /*reset_command_builder_event_chain (builder);*/
+	  return binding;
+	}
+    }
+  
+  if (lw_menu_active) lw_display_menu (CurrentTime);
+  
+  reset_this_command_keys (Vselected_console, 1);
+  /*reset_command_builder_event_chain (builder);*/
+  
+  return Vmenu_accelerator_map;
+}
+
+static Lisp_Object
+menu_accelerator_junk_on_error (Lisp_Object errordata, Lisp_Object ignored)
+{
+  Vmenu_accelerator_prefix = Qnil;
+  Vmenu_accelerator_modifiers = Qnil;
+  Vmenu_accelerator_enabled = Qnil;
+  if (!NILP (errordata))
+    {
+      Lisp_Object args[2];
+      
+      args[0] = build_string ("Error in menu accelerators (setting to nil)");
+      /* #### This should call
+	 (with-output-to-string (display-error errordata))
+	 but that stuff is all in Lisp currently. */
+      args[1] = errordata;
+      warn_when_safe_lispobj
+	(Qerror, Qwarning,
+	 emacs_doprnt_string_lisp ((CONST Bufbyte *) "%s: %s",
+				   Qnil, -1, 2, args));
+    }
+  
+  return Qnil;
+}
+
+static Lisp_Object
+menu_accelerator_safe_compare (Lisp_Object event0)
+{
+  if (CONSP (Vmenu_accelerator_prefix))
+    {
+      Lisp_Object t;
+      t=Vmenu_accelerator_prefix;
+      while (!NILP (t)
+	     && !NILP (event0)
+	     && event_matches_key_specifier_p (XEVENT (event0), Fcar (t)))
+	{
+	  t = Fcdr (t);
+	  event0 = XEVENT_NEXT (event0);
+	}
+      if (!NILP (t))
+	return Qnil;
+    }
+  else if (NILP (event0))
+    return Qnil;
+  else if (event_matches_key_specifier_p (XEVENT (event0), Vmenu_accelerator_prefix))
+    event0 = XEVENT_NEXT (event0);
+  else
+    return Qnil;
+  return event0;
+}
+
+static Lisp_Object
+menu_accelerator_safe_mod_compare (Lisp_Object cons)
+{
+  return (event_matches_key_specifier_p (XEVENT (XCAR (cons)), XCDR (cons))
+	  ? Qt
+	  : Qnil);
+}
+
+static Lisp_Object
+command_builder_find_menu_accelerator (struct command_builder *builder)
+{
+  /* this function can GC */
+  Lisp_Object event0 = builder->current_events;
+  struct console *con = XCONSOLE (Vselected_console);
+  struct frame *f = XFRAME (CONSOLE_SELECTED_FRAME (con));
+  Widget menubar_widget;
+  
+  /* compare entries in event0 against the menu prefix */
+  
+  if ((!CONSOLE_X_P (XCONSOLE (builder->console))) || NILP (event0) ||
+      XEVENT (event0)->event_type != key_press_event)
+    return Qnil;
+  
+  if (!NILP (Vmenu_accelerator_prefix))
+    {
+      event0 = condition_case_1 (Qerror,
+				 menu_accelerator_safe_compare,
+				 event0,
+				 menu_accelerator_junk_on_error,
+				 Qnil);
+    }
+  
+  if (NILP (event0))
+    return Qnil;
+  
+  menubar_widget = FRAME_X_MENUBAR_WIDGET (f);
+  if (menubar_widget
+      && CONSP (Vmenu_accelerator_modifiers))
+    {
+      Lisp_Object fake;
+      Lisp_Object last;
+      struct gcpro gcpro1;
+      Lisp_Object matchp;
+      
+      widget_value *val;
+      LWLIB_ID id = XPOPUP_DATA (f->menubar_data)->id;
+      
+      val = lw_get_all_values (id);
+      if (val)
+	{
+	  val = val->contents;
+	  
+	  fake = Fcopy_sequence (Vmenu_accelerator_modifiers);
+	  last = fake;
+	  
+	  while (!NILP (Fcdr (last)))
+	    last = Fcdr (last);
+	  
+	  Fsetcdr (last, Fcons (Qnil, Qnil));
+	  last = Fcdr (last);
+	}
+      
+      fake = Fcons (Qnil, fake);
+      
+      GCPRO1 (fake);
+
+      while (val)
+	{
+	  Lisp_Object accel;
+	  VOID_TO_LISP (accel, val->accel);
+	  if (val->name && !NILP (accel))
+	    {
+	      Fsetcar (last, accel);
+	      Fsetcar (fake, event0);
+	      matchp = condition_case_1 (Qerror,
+					 menu_accelerator_safe_mod_compare,
+					 fake,
+					 menu_accelerator_junk_on_error,
+					 Qnil);
+	      if (!NILP (matchp))
+		{
+		  /* we found one! */
+		  
+		  lw_set_menu (menubar_widget, val);
+		  /* yah - yet another hack.
+		     pretend emacs timestamp is the same as an X timestamp,
+		     which for the moment it is.  (read events.h)
+		     */
+		  lw_map_menu (XEVENT (event0)->timestamp);
+		  
+		  if (val->contents)
+		    lw_push_menu (val->contents);
+		  
+		  lw_display_menu (CurrentTime);
+		  
+		  /* menu accelerator keys don't go into keyboard macros */
+		  if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro))
+		    con->kbd_macro_ptr = con->kbd_macro_end;
+		  
+		  /* don't echo menu accelerator keys */
+		  /*reset_key_echo (builder, 1);*/
+		  reset_this_command_keys (Vselected_console, 1);
+		  UNGCPRO;
+		  
+		  return Vmenu_accelerator_map;
+		}
+	    }
+	  
+	  val = val->next;
+	}
+      
+      UNGCPRO;
+    }
+  return Qnil;
+}
+
+void
+event_menu_accelerate ()
+{
+  struct console *con = XCONSOLE (Vselected_console);
+  struct frame *f = XFRAME (CONSOLE_SELECTED_FRAME (con));
+  LWLIB_ID id = XPOPUP_DATA (f->menubar_data)->id;
+  widget_value *val = lw_get_all_values (id);
+  
+  val = val->contents;
+  lw_set_menu (FRAME_X_MENUBAR_WIDGET (f), val);
+  lw_map_menu (CurrentTime);
+  
+  lw_display_menu (CurrentTime);
+  
+  /* menu accelerator keys don't go into keyboard macros */
+  if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro))
+    con->kbd_macro_ptr = con->kbd_macro_end;
+}
+#endif /* HAVE_X_WINDOWS */
+
 /* See if we can do function-key-map or key-translation-map translation
    on the current events in the command builder.  If so, do this, and
    return the resulting binding, if any. */
@@ -3109,10 +3641,31 @@
       return list2 (fn, arg);
     }
 
-  else if (XEVENT_TYPE (evee) == misc_user_event)
+  
+  if (XEVENT_TYPE (evee) == misc_user_event)
     return Qnil;
 
-  result = command_builder_find_leaf_1 (builder);
+  /* if we're currently in a menu accelerator, check there for further events */
+#ifdef HAVE_X_WINDOWS
+  if (lw_menu_active)
+    {
+      result = command_builder_operate_menu_accelerator (builder);
+      return result;
+    }
+  else
+    {
+      result=Qnil;
+      if (EQ (Vmenu_accelerator_enabled, Qmenu_force))
+	result = command_builder_find_menu_accelerator (builder);
+      if (NILP (result))
+#endif
+	result = command_builder_find_leaf_1 (builder);
+#ifdef HAVE_X_WINDOWS
+      if (NILP (result)
+	  && EQ (Vmenu_accelerator_enabled, Qmenu_fallback))
+	result = command_builder_find_menu_accelerator (builder);
+    }
+#endif
 
   /* Check to see if we have a potential function-key-map match. */
   if (NILP (result))
@@ -3588,23 +4141,43 @@
 
     if (KEYMAPP (leaf))
       {
-	Lisp_Object prompt = Fkeymap_prompt (leaf, Qt);
-	if (STRINGP (prompt))
+	if (!lw_menu_active)
 	  {
-	    /* Append keymap prompt to key echo buffer */
-	    int buf_index = command_builder->echo_buf_index;
-	    Bytecount len = XSTRING_LENGTH (prompt);
-
-	    if (len + buf_index + 1 <= command_builder->echo_buf_length)
+	    Lisp_Object prompt = Fkeymap_prompt (leaf, Qt);
+	    if (STRINGP (prompt))
 	      {
-		Bufbyte *echo = command_builder->echo_buf + buf_index;
-		memcpy (echo, XSTRING_DATA (prompt), len);
-		echo[len] = 0;
+		/* Append keymap prompt to key echo buffer */
+		int buf_index = command_builder->echo_buf_index;
+		Bytecount len = XSTRING_LENGTH (prompt);
+
+		if (len + buf_index + 1 <= command_builder->echo_buf_length)
+		  {
+		    Bufbyte *echo = command_builder->echo_buf + buf_index;
+		    memcpy (echo, XSTRING_DATA (prompt), len);
+		    echo[len] = 0;
+		  }
+		maybe_echo_keys (command_builder, 1);
 	      }
-	    maybe_echo_keys (command_builder, 1);
+	    else
+	      maybe_echo_keys (command_builder, 0);
 	  }
-	else
-	  maybe_echo_keys (command_builder, 0);
+	else if (!NILP (Vquit_flag)) {
+	  Lisp_Object event = Fmake_event();
+	  struct Lisp_Event *e = XEVENT (event);
+	  struct console *con;
+	  int ch;
+	  
+	  /* if quit happened during menu acceleration, pretend we read it */
+	  con = XCONSOLE (Fselected_console ());
+	  
+	  ch = CONSOLE_QUIT_CHAR (con);
+	  
+	  character_to_event (ch, e, con, 1);
+	  e->channel = make_console (con);
+	  
+	  enqueue_command_event (event);
+	  Vquit_flag = Qnil;
+	}
       }
     else if (!NILP (leaf))
       {
@@ -4029,6 +4602,9 @@
 	  /* Huh? */
 	  Vthis_command = Qnil;
 
+	/* clear the echo area */
+	reset_key_echo (command_builder, 1);
+	
 	command_builder->self_insert_countdown = 0;
 	if (NILP (XCONSOLE (console)->prefix_arg)
 	    && NILP (Vexecuting_macro)
@@ -4298,6 +4874,17 @@
 	     "retry-undefined-key-binding-unshifted");
   defsymbol (&Qauto_show_make_point_visible,
 	     "auto-show-make-point-visible");
+
+  defsymbol (&Qmenu_force, "menu-force");
+  defsymbol (&Qmenu_fallback, "menu-fallback");
+  
+  defsymbol (&Qmenu_quit, "menu-quit");
+  defsymbol (&Qmenu_up, "menu-up");
+  defsymbol (&Qmenu_down, "menu-down");
+  defsymbol (&Qmenu_left, "menu-left");
+  defsymbol (&Qmenu_right, "menu-right");
+  defsymbol (&Qmenu_select, "menu-select");
+  defsymbol (&Qmenu_escape, "menu-escape");
 }
 
 void
@@ -4616,12 +5203,82 @@
 */ );
   debug_emacs_events = 0;
 #endif
+
+  DEFVAR_LISP("menu-accelerator-prefix", &Vmenu_accelerator_prefix /*
+Prefix key(s) that must be typed before menu accelerators will be activated.
+Set this to a value acceptable by define-key.
+*/ );
+  Vmenu_accelerator_prefix = Qnil;
+
+  DEFVAR_LISP ("menu-accelerator-modifiers", &Vmenu_accelerator_modifiers /*
+Modifier keys which must be pressed to get to the top level menu accelerators.
+This is a list of modifier key symbols.  All modifier keys must be held down
+while a valid menu accelerator key is pressed in order for the top level
+menu to become active.
+
+See also menu-accelerator-enabled and menu-accelerator-prefix.
+*/ );
+  Vmenu_accelerator_modifiers = list1 (Qmeta);
+  
+  DEFVAR_LISP ("menu-accelerator-enabled", &Vmenu_accelerator_enabled /*
+Whether menu accelerator keys can cause the menubar to become active.
+If 'menu-force or 'menu-fallback, then menu accelerator keys can
+be used to activate the top level menu.  Once the menubar becomes active, the
+accelerator keys can be used regardless of the value of this variable.
+
+menu-force is used to indicate that the menu accelerator key takes
+precedence over bindings in the current keymap(s).  menu-fallback means
+that bindings in the current keymap take precedence over menu accelerator keys.
+Thus a top level menu with an accelerator of \"T\" would be activated on a
+keypress of Meta-t if menu-accelerator-enabled is menu-force.
+However, if menu-accelerator-enabled is menu-fallback, then
+Meta-t will not activate the menubar and will instead run the function
+transpose-words, to which it is normally bound.
+
+See also menu-accelerator-modifiers and menu-accelerator-prefix.
+*/ );
+  Vmenu_accelerator_enabled = Qnil;
 }
 
 void
 complex_vars_of_event_stream (void)
 {
   Vkeyboard_translate_table = Fmake_hashtable (make_int (100), Qnil);
+
+  DEFVAR_LISP ("menu-accelerator-map", &Vmenu_accelerator_map /*
+Keymap for use when the menubar is active.
+The actions menu-quit, menu-up, menu-down, menu-left, menu-right,
+menu-select and menu-escape can be mapped to keys in this map.
+
+menu-quit    Immediately deactivate the menubar and any open submenus without
+             selecting an item.
+menu-up      Move the menu cursor up one row in the current menu.  If the
+             move extends past the top of the menu, wrap around to the bottom.
+menu-down    Move the menu cursor down one row in the current menu.  If the
+             move extends past the bottom of the menu, wrap around to the top.
+             If executed while the cursor is in the top level menu, move down
+             into the selected menu.
+menu-left    Move the cursor from a submenu into the parent menu.  If executed
+             while the cursor is in the top level menu, move the cursor to the
+             left.  If the move extends past the left edge of the menu, wrap
+             around to the right edge.
+menu-right   Move the cursor into a submenu.  If the cursor is located in the
+             top level menu or is not currently on a submenu heading, then move
+             the cursor to the next top level menu entry.  If the move extends
+             past the right edge of the menu, wrap around to the left edge.
+menu-select  Activate the item under the cursor.  If the cursor is located on
+             a submenu heading, then move the cursor into the submenu.
+menu-escape  Pop up to the next level of menus.  Moves from a submenu into its
+             parent menu.  From the top level menu, this deactivates the
+             menubar.
+
+This keymap can also contain normal key-command bindings, in which case the
+menubar is deactivated and the corresponding command is executed.
+
+The action bindings used by the menu accelerator code are designed to mimic
+the actions of menu traversal keys in a commonly used PC operating system.
+*/ );
+  Vmenu_accelerator_map = Fmake_keymap(Qnil);
 }
 
 void