Bug 208626 - [KeyBindings] Mnemonic gets hidden if there is existing Alt key binding
Summary: [KeyBindings] Mnemonic gets hidden if there is existing Alt key binding
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.2.2   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.7 M5   Edit
Assignee: Paul Webster CLA
QA Contact: Paul Webster CLA
URL:
Whiteboard:
Keywords: helpwanted
: 286806 (view as bug list)
Depends on:
Blocks:
 
Reported: 2007-11-02 18:22 EDT by Jamie Liu CLA
Modified: 2017-04-26 05:53 EDT (History)
8 users (show)

See Also:


Attachments
toplevel removal v01 (1.30 KB, patch)
2011-01-05 14:15 EST, Paul Webster CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jamie Liu CLA 2007-11-02 18:22:25 EDT
Build ID:  M20070212-1330

Steps To Reproduce:
1. Create a plugin for eclipse that includes a key binding for "M1+S" (ie. Alt+S) where S is any letter that is used as a mnemonic in one of the top level menus.  Since eclipse uses "S" as the mnemonic for Help > &Software Updates, "S" is sufficient.
2. Launch the plugin as part of Eclipse IDE
3. Press Alt+H to bring down the Help menu (to go along with our example in #1)
BUG: Notice "Software Updates" is missing its mnemonic.


More information:
The code after "if (callback.isAcceleratorInUse(SWT.ALT | character))" inside Eclipse's MenuManager.java removes the mnemonic, but it seems like Eclipse should be checking "isAcceleratorInUse" only for top level menumanagers like File,Edit,...,Help, etc.  :

  /* (non-Javadoc)
     * @see org.eclipse.jface.action.IContributionItem#update(java.lang.String)
     */
    public void update(String property) {
        IContributionItem items[] = getItems();

        for (int i = 0; i < items.length; i++) {
			items[i].update(property);
		}

        if (menu != null && !menu.isDisposed() && menu.getParentItem() != null
                && IAction.TEXT.equals(property)) {
            String text = getOverrides().getText(this);

            if (text == null) {
				text = getMenuText();
			}

            if (text != null) {
                ExternalActionManager.ICallback callback = ExternalActionManager
                        .getInstance().getCallback();

                if (callback != null) {
                    int index = text.indexOf('&');

                    if (index >= 0 && index < text.length() - 1) {
                        char character = Character.toUpperCase(text
                                .charAt(index + 1));

                        if (callback.isAcceleratorInUse(SWT.ALT | character)) {
                            if (index == 0) {
								text = text.substring(1);
							} else {
								text = text.substring(0, index)
                                        + text.substring(index + 1);
							}
                        }
                    }
                }

                menu.getParentItem().setText(text);
            }
        }
    }
Comment 1 Raji Akella CLA 2008-02-27 16:52:12 EST
Any status on this bug?
Comment 2 Paul Webster CLA 2008-02-27 19:31:23 EST
I'd consider any contributions for M6 (API) or M7 (non-API)

PW
Comment 3 Paul Webster CLA 2008-04-03 15:26:58 EDT
After a little more investigation, to fix it either of the 3 ways we've thought of involves API (no go right now) and a lot of changes in the workbench, or some kind of goofy hack "only remove accelerators if your MenuItem parent Menu is the Shell MenuBar" or something like that. I don't believe either approach will be reliable in all usecases.  Also, either way it would change the MenuManager behaviour in M7 (which is risky from an impact point of view).

A 3.5 fix would be to make that behaviour optional in MenuManager with API and off by default early in 3.5, and to have the WorkbenchActionBuilder contributed MenuManagers and actionSets/editorActions contributed MenuManagers turn it on (if I can find MenuManagers in the correct place).

PW
Comment 4 Mike Wilson CLA 2008-04-08 08:56:38 EDT
I'd like us to work with the SWT team to make sure we understand what the correct platform behavior is, and make sure that we aren't getting in the way of that. The current behavior (i.e. turning off mnemonics) seems odd to me, in general. If we're going to fix this, we should fix it properly.
Comment 5 Raji Akella CLA 2008-10-22 12:10:51 EDT
Requesting update on this bugzilla.

Comment 6 Paul Webster CLA 2008-10-22 12:43:20 EDT
I'll have a look at this in M4
PW
Comment 7 Boris Bokowski CLA 2010-04-21 15:01:57 EDT
We may just take out the code that removes the mnemonics.
Comment 8 Paul Webster CLA 2010-04-22 13:34:53 EDT
While looking for a more general solution, we looked at just removing this code.

On windows, it turns out that you can remove the "mnemonic removal code" and you get 2 possibly acceptable behaviours:

1) ALT+H will execute the command
2) F10 (or ALT) highlights the menu bar and 'H' will drop down the Help menu.

downside: you see the mnemonic, so the visual indicator doesn't match the behaviour.

This code was needed on linux, however.  If we don't remove the mnemonic, then ALT+H would always open the Help menu.  I haven't looked at the Mac yet.

Silenio, Felipe, do you have any feelings about what would be a proper cross-platform behaviour?  Windows seems to continue with a lot more UI processing that GTK+ does when a Menu is open.

PW
Comment 9 Silenio Quarti CLA 2010-04-22 15:19:50 EDT
I believe GTK and Windows work the same way here (Cocoa and Carbon do not count, because there is no mnemonics on these platforms). The SWT.KeyDown filter will not be called for mnemonics of items in the menu bar, but it will be call for mnemonics of items in drop down menus.

In the testcase below, if you press Alt+H, you get the "Got Alt+H key binding" print in the console. If you press Al+E, you do not.


import org.eclipse.swt.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

public class Snippet117  {
public static void main(String[] args) {
	Display display = new Display();
	Shell shell = new Shell(display);
	shell.setLayout(new FillLayout());
	final Text t = new Text(shell, SWT.BORDER | SWT.MULTI);
	t.setText ("here is some text to be selected");
	Menu bar = new Menu (shell, SWT.BAR);
	shell.setMenuBar (bar);
	MenuItem editItem = new MenuItem (bar, SWT.CASCADE);
	editItem.setText ("&Edit");
	Menu submenu = new Menu (shell, SWT.DROP_DOWN);
	editItem.setMenu (submenu);

	MenuItem item = new MenuItem (submenu, SWT.PUSH);
	item.addListener (SWT.Selection, new Listener () {
		public void handleEvent (Event e) {
			t.selectAll();
		}
	});
	item.setText ("Select All &Hi\tAlt+H");

	display.addFilter(SWT.KeyDown, new Listener() {
		public void handleEvent(Event event) {
			if ((event.stateMask & SWT.ALT) != 0 && event.keyCode == 'h') {
				System.out.println("Got Alt+H key binding");
			}
			if ((event.stateMask & SWT.ALT) != 0 && event.keyCode == 'e') {
				System.out.println("Got Alt+E key binding");
			}
		}
	});

	shell.setSize(200, 200);
	shell.open();
	while (!shell.isDisposed()) {
		if (!display.readAndDispatch())
			display.sleep();
	}
	display.dispose();
}
}
Comment 10 Paul Webster CLA 2010-08-11 12:52:24 EDT
*** Bug 286806 has been marked as a duplicate of this bug. ***
Comment 11 thomas menzel CLA 2010-08-21 05:38:22 EDT
hi folks,

as i have expressed in https://bugs.eclipse.org/bugs/show_bug.cgi?id=286806#c7:

i vote for keeping the mnemonic even in the top menu bar.
if that concerns too many people this could be made a preference for win systems.
Comment 12 Paul Webster CLA 2011-01-05 14:15:52 EST
Created attachment 186113 [details]
toplevel removal v01

Only remove the mnemonic for top level menus (i.e. their parent menu has SWT.Bar set)

PW
Comment 13 Paul Webster CLA 2011-01-05 14:42:32 EST
Released to HEAD
PW
Comment 14 Paul Webster CLA 2011-01-25 08:38:18 EST
In I20110124-1800
PW
Comment 15 thomas menzel CLA 2017-04-26 05:53:22 EDT
hi, i'm not sure if this got broken again or if the fix wasnt complete/ had limits -- at least this bug regarding mnemonic in top level menus still persists in neon and from the bug comments i wasnt able to know the intended behavior.

the behavior i see in neon is like this:

define a command with alt + <a Mnemonic of a top level menu item>, eg. alt+s
-> the Mnemonic for the source top level menu is gone and cannot be reached anymore. 

note: i understand that for top level menu items the behavior regarding key bindings is somewhat conflicting -- at least on windows.

on windows there are by default 3 ways to activate/navigate the menu bar (i know of) 
a) alt+<mnemonic> will open a top level menu item with the corresponding mnemonic
b) f10 and ALT pressed and released by themselves will activate the 1. menu item, but not open it. if u then press another key that is a mnemonic of a top level menu item, it will open it. hence the sequence of e.g. "alt, s" will open the source menu.   

so i understand the need to resolve the conflict for case a): u need to decide to either execute the bound command OR opening the top level menu. It seems that u have implemented the latter. 
however, the approach to drop the mnemonic on top level menu items on a conflict also breaks the navigation after style b) -- which IMO is not necessary. 
at the same time i recognize that if u keep the mnemonic -- and thus the visual feedback -- users might be puzzled that alt+s wont work.

since i'm one of the users that navigate after style b) i think it is worthwhile to differentiate the 2 navigation styles; after all, eclipse has support for key sequences, so why not apply this to menus as well?    

i propose this solution to allow conflicting alt+<mnemonic> command bindings like so:

variant a) (possibly easier to impl.)  
- indicate a conflicting bindings for menus as is done for other conflicts
- add this user preference (i suggest on the keybinding page, either globally or per keybinding): "resolve conflicting binding with top level menus" = (show conflict popup (default) | command | open level menu)
-- leave the mnemonic on the top level menus -- for the values: (show conflict popup (default) | open level menu)
-- remove the mnemonic on the top level menus -- for the value: command

variant b) more general approach 
- translate menu mnemonics to commands to open the respective menu item and show the in the key binding page
- handle them the same as all others items with the existing code 
e.g. for the source menu we have 3 bindings by default with scoope "in windows":
- f10, s
- alt, s
- alt +s 

when defining an alt+s bindging to another command the alt+s binding appears as a conflict and i can take the approriate measures.

note 1
with this approach we would still need to decide if we want to include sub menue item mnemonics, eg. 
alt, h, s -> Help/show contextual help      

note 2
as a side effect it becomes possible w/o writing/mod'ing plugins to (re)define custom mnemonics for arbitrary menu items

note 3
adding all menu items as commands to the command list might be too much, so a filter/switch between these views might be needed 

--- 
phew, this become much more elaborate than i thought at first and might warrant to become a new bug/enhancement