This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

Bug 178156 - MenuSelectionManager and Keyboard listeners do not work for Mac OS X
Summary: MenuSelectionManager and Keyboard listeners do not work for Mac OS X
Status: NEW
Alias: None
Product: platform
Classification: Unclassified
Component: Window System (show other bugs)
Version: 6.x
Hardware: Macintosh (x86) Mac OS X
: P4 normal (vote)
Assignee: issues@platform
URL: https://sodbeans.svn.sourceforge.net/...
Keywords:
Depends on:
Blocks:
 
Reported: 2009-12-04 09:56 UTC by stefika
Modified: 2009-12-07 01:17 UTC (History)
2 users (show)

See Also:
Issue Type: DEFECT
Exception Reporter:


Attachments
Module which tries to log keyboard activity (or anything) from main menus - no selection output on Mac OS (8.46 KB, application/zip)
2009-12-04 10:07 UTC, _ tboudreau
Details

Note You need to log in before you can comment on or make changes to this bug.
Description stefika 2009-12-04 09:56:58 UTC
On Mac OSX, it does not appear to be possible to get KeyBoard events for when a menu is selected (e.g., navigated to with the mouse, but not clicked), while this does appear to work properly on Windows XP, windows 7, and Mac OSX outside of the NetBeans platform. Exact code to reproduce the problem follows, however, the URL provided links to the Sappy project, which would allow you to download and reproduce the problem exactly.

To reproduce, do the following:

1. Create an Installer in the NetBeans platform. Be sure to do the rest of the code after calling:

WindowManager manager = WindowManager.getDefault();
manager.invokeWhenUIReady(this);

else the dynamically generated Menus will not yet be loaded.

2. Try to make any kind of keyboard listener that can determine when a particular menu is selected. The following are several options for doing so, all of which work on Windows, and outside the platform, but none of which work on Mac OSX.

The easiest way to attempt to get KeyBoard events is using the MenuSelectionManager, like so:

final MenuSelectionManager menuManager = MenuSelectionManager.defaultManager();
        menuManager.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                Object o = e.getSource();
                if (o instanceof MenuSelectionManager) {
                    MenuSelectionManager manager = (MenuSelectionManager) o;
                    MenuElement[] elements = manager.getSelectedPath();
                    if (elements.length != 0) {
                        MenuElement element = elements[elements.length - 1];
                        if (element instanceof JMenu) {
                            JMenu m = (JMenu) element;
                            //do something with it
                        } else if (element instanceof JMenuItem) {
                            JMenuItem m = (JMenuItem) element;
                            //do something with it.
                        }
                    }
                }
            }
        });


Second, another way to try and get keyboard events, is to get the JLayeredPane from the RootPane of the main window, then pass it various kinds of Event Listeners. I have, literally, tried every possible combination of listeners. The only one that does work is the MenuListener in MenuBar$LazyMenu. However, the JMenuItem instances inside of a LazyMenu do not fire events at all, with the exception of MouseEvents and one or two unrelated events, which work fine for these items. Here is an example of code:

//run in event dispatch thread
            public void run() {
                windows = WindowManager.getDefault();
                Registry reg = windows.getRegistry();
                JFrame frame = (JFrame) windows.getMainWindow();
                JRootPane pane = frame.getRootPane();
                JLayeredPane layered = pane.getLayeredPane();
                Object[] comps = layered.getComponents();
                for (int i = 0; i < comps.length; i++) {
                    if (comps[i] instanceof MenuBar) {
                        MenuBar bar = (MenuBar) comps[i];
                        bar.waitFinished();
                        int num = bar.getMenuCount();
                        for (int j = 0; j < num; j++) {
                            Object o = bar.getMenu(j);
                            JMenu menu = (JMenu) o;
                            
//this next listener is the only one that works
//for getting access a keyboard event "selecting" 
//a menu item. Keyboard listeners, and others, do not work.
                            menu.addMenuListener(new MenuListener() {

                                public void menuSelected(MenuEvent e) {
                                    if (e.getSource() instanceof JMenu) {
                                        JMenu menu = (JMenu) e.getSource();

//similarly, here, if you then get the JMenuItem objects contained by
//menu items and add, literally, any possible combination of 
//event listeners, you cannot get access to keyboard selection events

                                    }
                                }

                                public void menuDeselected(MenuEvent e) {
                                }

                                public void menuCanceled(MenuEvent e) {
                                }
                            });
                        }
                    }
                }

            }
        });


And there is one additional method I tried to get access to when a keyboard event occurred, which is to set a timer and continually scan all menus in the platform to see if any MenuItem is considered "Armed" or "Selected." The Selected property seems to be insignificant on mac, while none of the internal menu items correctly say they are "Armed" when they are actually armed. Something like the following:

Timer timer = new Timer(100, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                menuManager.getSelectedPath(); //this returns 0 items, always
//you get similar results when you scan through all of the menus manually
//checking for whether something is armed/selected/etc.
            }
        }
        );

Finally, Tim Boudreau gave the very helpful suggestion to rip the processKey's methods outside of the NetBeans platform and put them into a normal swing app to see if that code is the problem. There are only two places in org.openide.awt.MenuBar where a .consume method mentioned (which could eat the events, if I'm understanding correctly). Those two places are in the MenuBar's processKeys and in the MenuBar$LazyMenu's process keys. However, I put both of those menus into a normal swing app (in appropriate sub-classes), and the event firing did actually work correctly, although I only tested with the MenuSelectionManager, not every combination of listener. This means that, at this point, my best guess is that the problem "could" be related to the Platform using vanilla JMenuItem objects instead of a custom component that overrides for mac, like is done for Menus, but that's just my best guess.
Comment 1 _ tboudreau 2009-12-04 10:07:49 UTC
Created attachment 92133 [details]
Module which tries to log keyboard activity (or anything) from main menus - no selection output on Mac OS

Attached a module which just brute-force listens on everything that could possibly be interesting from the contents of the main menu and logs it.  No logging about selection on Mac OS.