Subject: menu hotkeys and duplicates

From: Michael Han <[email-masked]>
Date: Sun, 07 Feb 1999 13:16:54 -0800

Hi, I don't really know why I thought of it (was there a feature
request recently?) but I thought it might be nice to be able to have
more than one menu item per hotkey in a menu. For long menus, or
automagically generated ones, it'd might be nice to be able to hotkey
to items w/o worrying about duplicates.

Anyway, I wrote a little patch which maybe we might like to put in
2.3? Here's the Changelog entry:

1999-02-07 Michael Han <[email-masked]>

        * fvwm/menus.c (menuShortcuts): Changed the hotkey handler from a flat
        once-over the menu to a "smarter" search that locates the next match
        and distinguishes between unique and non-unique hotkeys, doing a
        MENU_NEWITEM selection for non-uniques and retaining existing behavior
        for unique hotkeys.
        (AddToMenu): Commented out checks to prevent binding of duplicate
        hotkeys for what I think are obvious reasons.
        (FHotKeyUsedBefore): Noted that this function is now unused.

And attached is a patch. Context format diff against CVS from maybe
2/4/99. Thoughts anyone?
-- 
[email-masked]                         http://www.best.com/~mikehan/
coffee achiever                              San Francisco, California
"How can someone with glasses that thick be so stupid?" - Bart

*** fvwm/menus.c.2.1.12	Fri Feb  5 23:56:06 1999
--- fvwm/menus.c	Sun Feb  7 12:42:17 1999
***************
*** 444,460 ****
         isn't pressed */
      MenuItem *mi;
      char key;
!     /* Search menu for matching hotkey */
!     for (mi = menu->first; mi; mi = mi->next) {
!       key = tolower(mi->chHotkey);
!       if (keychar == key) {
! 	*pmiCurrent = mi;
! 	if (IS_POPUP_MENU_ITEM(mi))
! 	  return MENU_POPUP;
! 	else
! 	  return MENU_SELECTED;
        }
      }
    }
  
    switch(keysym)		/* Other special keyboard handling	*/
--- 444,482 ----
         isn't pressed */
      MenuItem *mi;
      char key;
!     int countHotkey = 0;	// Added by MMH [email-masked] 2/7/99
! 
!     /* MMH [email-masked] 2/7/99			*/
!     /* Multiple hotkeys per menu			*/
!     /* Search menu for matching hotkey;			*/
!     /* remember how many we found and where we found it	*/
!     for ( mi = ( miCurrent == menu->last ) ? menu->first : miCurrent->next;
! 	  mi != miCurrent;
! 	  mi = ( mi == menu->last ) ? menu->first : mi->next )
!     {
!       key = tolower( mi->chHotkey );
!       if ( keychar == key )
!       {
!         if ( ++countHotkey == 1 )
! 	  newItem = mi;
        }
      }
+     /* For multiple instances of a single hotkey, just move the selection */
+     if ( countHotkey > 1 )
+     {
+       *pmiCurrent = newItem;
+       return MENU_NEWITEM;
+     }
+     /* Do things the old way for unique hotkeys in the menu */
+     else if ( countHotkey = 1 )
+     {
+       *pmiCurrent = newItem;
+       if ( IS_POPUP_MENU_ITEM( newItem ) )
+ 	return MENU_POPUP;
+       else
+ 	return MENU_SELECTED;
+     }
+     /* MMH [email-masked] 2/7/99 */
    }
  
    switch(keysym)		/* Other special keyboard handling	*/
***************
*** 2475,2480 ****
--- 2497,2506 ----
   * used the given hotkey already
   * This means that it doesn't check the last element of the menu
   */
+ /* MMH [email-masked] 2/7/99				*/
+ /* Multiple hotkeys per menu				*/
+ /* My changes result in this code being superfluous.	*/
+ /* It's no longer necessary to check for dups.		*/
  int FHotKeyUsedBefore(MenuRoot *menu, char ch) {
    int f = FALSE;
    MenuItem *currentMenuItem = menu->first;
***************
*** 2812,2817 ****
--- 2838,2849 ----
        }
        ch = scanForHotkeys(tmp, 1);	/* [email-masked] */
        if (ch != '\0')
+         tmp->chHotkey = ch;
+ 	/* MMH [email-masked] 2/7/99				*/
+ 	/* Multiple hotkeys per menu				*/
+ 	/* Moved the hotkey setting out of the conditional	*/
+ 	/* block and commented out the check for duplicates	*/
+ 	/*
  	{
  	if (FHotKeyUsedBefore(menu,ch))
  	  {
***************
*** 2825,2830 ****
--- 2857,2864 ----
  	    tmp->chHotkey = ch;
  	  }
  	}
+ 	*/
+ 	/* MMH [email-masked] 2/7/99 */
        tmp->strlen = strlen(tmp->item);
      }
    else
***************
*** 2842,2847 ****
--- 2876,2887 ----
        if (tmp->hotkey == 0) {
          char ch = scanForHotkeys(tmp, -1);	/* [email-masked] */
  	if (ch != '\0')
+ 	  tmp->chHotkey = ch;
+ 	/* MMH [email-masked] 2/7/99				*/
+ 	/* Multiple hotkeys per menu				*/
+ 	/* Moved the hotkey setting out of the conditional	*/
+ 	/* block and commented out the check for duplicates	*/
+ 	/*
  	{
  	  if (FHotKeyUsedBefore(menu,ch))
  	  {
***************
*** 2855,2860 ****
--- 2895,2902 ----
  	    tmp->chHotkey = ch;
  	  }
  	}
+ 	*/
+ 	/* MMH [email-masked] 2/7/99 */
        }
        tmp->strlen2 = strlen(tmp->item2);
      }