33

I would like to listen for key combinations such as Control+S without adding key listeners to each component in my Swing application. How can I achieve this?

Nathan
  • 8,093
  • 8
  • 50
  • 76
diolemo
  • 2,621
  • 2
  • 21
  • 28

3 Answers3

65

It is possible.

KeyboardFocusManager.getCurrentKeyboardFocusManager()
  .addKeyEventDispatcher(new KeyEventDispatcher() {
      @Override
      public boolean dispatchKeyEvent(KeyEvent e) {
        System.out.println("Got key event!");
        return false;
      }
});

That will grab all key events. Returning false allows the keyboard focus manager to resume normal key event dispatching to the various components.

If you want to catch key combos, you can keep a set of "pressed keys." Whenever a key is pressed, add it to the set and check what keys are already in the set. When a key is released, remove it from the set.

Matt Wonlaw
  • 12,146
  • 5
  • 42
  • 44
  • I think freshwire is still going to have to put listeners in each of the components though. Then as the `KeyEventDispatcher` sends out events, the components can listen for certain events and do their component-specific action. This actually sounds like it will be extra work. – jbranchaud Mar 17 '11 at 20:54
  • @Treebranch he just wants to catch a global ctr+s... This will work fine. – Matt Wonlaw Mar 17 '11 at 23:57
  • Okay, I agree. I was assuming freshwire would then want to push the events to the component level, but I suppose that isn't necessarily the case. – jbranchaud Mar 18 '11 at 02:11
  • KeyboardFocusManager in fact grabs all key events, whereas AWTEventListener doesn't react on all events. If you need to listen zu key event like F11 to toggel to fullscreen, KeyboardFocusManager is definitely better. AWTEventListener seems to only listen zu Component events. But when no component has focus, AWTEventListener doesn't get notified of key events. – haferblues Jan 14 '13 at 10:54
  • 4
    This code returns all events for each key press i.e. for one key press, a KEY_PRESSED, KEY_RELEASED and a KEY_TYPED event will occur. To filter further to give one event, it is possible to add code if (KeyEvent.KEY_PRESSED == e.getID()) { ... } to filter for KEY_PRESSED events for example. – John Deverall Dec 10 '14 at 20:44
  • @haferblues I get the same behavior from KeyboardFocusManager, if no component has focus, no events will be delivered. – Anders Lindén May 29 '16 at 19:19
0

Very simple my friend: All you have to do is create a class KeyEventDispatcher and register to KeyboardFocusManager C.1

Then parse and extract state and key info see: C.2 Strangely enough though, you have to get the KEY STATE via ThatEvent.getID();

SEEMS LIKE A MISSNOMER TO ME.

///////////////////////////////////////////////////////////////////////////////////////////   C.1)
         KeyDispatcher        ThisKeyDispatcher  = new KeyDispatcher();

         KeyboardFocusManager ThisKbFocusMngr = KeyboardFocusManager 
                                              . getCurrentKeyboardFocusManager();

         ThisKbFocusMngr                      . addKeyEventDispatcher(ThisKeyDispatcher);
         return ThisKeyDispatcher;

///////////////////////////////////////////////////////////////////////////////////////////   
C.2
public static class KeyDispatcher implements KeyEventDispatcher {

  public boolean dispatchKeyEvent(final KeyEvent ThatEvent) {

     KeyboardFocusManager ThisKbFocusMngr    = null;
     Component            ThisComponent      = null;
     Container            ThisRoot           = null;
     Window               ThisWindow         = null;
     int                  ThisKeyStateEvent  = 0;

     try {
        ThisKbFocusMngr       = KeyboardFocusManager  . getCurrentKeyboardFocusManager();
        ThisComponent         = ThisKbFocusMngr       . getFocusOwner();
        ThisRoot              = ThisKbFocusMngr       . getCurrentFocusCycleRoot();
        ThisWindow            = ThisKbFocusMngr       . getActiveWindow();
        ThisKeyStateEvent     = ThatEvent.getID();   // i.e.  KeyEvent.KEY_RELEASED

        if(false                           == ThatEvent.isConsumed()) {
           boolean       RetBool          = false;
           if((KeyEvent.VK_BACK           == ThatEvent.getKeyCode())) {
              RetBool                      = true;
           } else {
              RetBool                      = m_CallSomeoneEvent(ThatEvent);
           }
           if(RetBool) {
              ThatEvent.consume();
              return true;
           }
        }
     }
     catch( Throwable e ) {
        LogThis(". ", e);
     }
     return false;
  }
}
alony
  • 10,725
  • 3
  • 39
  • 46
Denis Co
  • 77
  • 2
  • 12
    Thanks for the answer but I already accepted an answer over a year ago. How does your answer differ from the accepted answer? It has a lot of extra code that seems to have no purpose in the context of my question. – diolemo Jun 04 '12 at 20:58
0

I don't think there is a way to add a "global" key listener like you are wanting to do. This forum post with a similar question backs me up. You are just going to have to add them to each component. This should only need to be done once though, so I guess you can just get it over with and move on.

jbranchaud
  • 5,909
  • 9
  • 45
  • 70
  • 1
    *I don't think there is a way to add a "global" key listener like you are wanting to do* It's just wrong `Toolkit.addAWTEventListener` and you can listen anything, besides it was mentioned you can add event to addKeyEventDispatcher and you can add accel keys and so on – bestsss Mar 17 '11 at 20:46
  • @bestsss I think you misunderstood. I am not talking about the type of events that are being listened to, but the component(s) over which the listener works. – jbranchaud Mar 17 '11 at 20:50
  • 1
    after getting the global event, get the focused component? – bestsss Mar 17 '11 at 20:53