ROBOKiTTY
ROBOKiTTY

Reputation: 116

KeyEventDispatcher doesn't catch tab when alt is pressed

I started writing a custom KeyAdaptor so that releasing the alt key would fire an event highlighting the first item in the menu bar, to simulate how native Windows programs usually work. Then I noticed that when I alt-tab out and release alt, the program would lose focus and simultaneously highlight the menu item, which causes the defocused program to flash a notification.

I found this behaviour annoying, so I tried to disable the alt release event when tab is pressed. I then found out that since tab is a focus traversal key, it's consumed by the focus system. So I read about KeyEventDispatcher, which pre-listens for key events, and switched to that. Now it does detect tab presses, but not when the alt key is down. Why does this happen, and how do I work around it?

private class KeyController implements KeyEventDispatcher {
    //true == pressed, false == not pressed
    private boolean[] keyStates = new boolean[256];
    private boolean ignoreNextAltRelease = false;

    private void keyReleased(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_ALT) {
            if (!ignoreNextAltRelease) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        menuBar.getMenu(0).doClick();
                    }
                });
            }
            ignoreNextAltRelease = false;
        }
    }

    private void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_TAB) {
            if (keyStates[KeyEvent.VK_ALT]) {
                ignoreNextAltRelease = true;
            }
        }
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent e) {
        if (e.getID() == KeyEvent.KEY_PRESSED) {
            keyStates[e.getKeyCode()] = true;
            keyPressed(e);
        }
        else if (e.getID() == KeyEvent.KEY_RELEASED) {
            keyStates[e.getKeyCode()] = false;
            keyReleased(e);
        }

        return false;
    }

When I have alt pressed down and then press tab, the keyPressed method is never called on tab, but when tab is released, the keyReleased method is called on tab. When I release both keys simultaneously, the keyReleased method is called on both alt and tab.

Upvotes: 0

Views: 253

Answers (1)

nhaggen
nhaggen

Reputation: 443

Under macOS, there is the com.apple.eawt.AppForegroundListener which will tell you when the App is moved to background (which happens when the user presses CMD + TAB, which in turn corresponds to ALT + TAB under Windows). An AppForegroundEvent is fired when the App is moved to background (i.e. another App is active) or when it is moved to foreground again.

I suppose under Windows there would be a similar package that allows to keep track of those events that are handled on OS basis.

com.apple.eawt itself seems to be no longer available since Java 9, so have a look around the net to see more up-to-date implementations.

If your intention is to handle the ALT + TAB key in your application, you should implement appMovedToBackground(AppForegroundEvent e), detect whether the app was moved to background by ALT + TAB or by clicking on another applications icon/window (guess that will be the hard part). Then put your application to foreground again and do whatever you intended to do with the ALT + TAB key-Event.

Upvotes: 1

Related Questions