7

I'm having problems with getting my KeyBoardFocusManger to work with my full screen Window. No matter what, it just wont get keyboard input. I used a System.exit(0) and a println() to look for any call to the keypressed/released/typed method, but no errors are thrown. I've tried KeyListeners; but after I read this, I changed to a KeyboardFocusManager, and the same thing still happens. I'm really getting desperate; from what I can judge, the Window is not getting focus of the keyboard?

Here is my main:

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            // Determine if full-screen mode is supported directly
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            if (gs.isFullScreenSupported()) {
                Frame frame = new Frame(gs.getDefaultConfiguration());
                SpaceInvaderUI spaceInvaderUI = new SpaceInvaderUI(frame);
                // Enter full-screen mode
                gs.setFullScreenWindow(spaceInvaderUI);
            } else {
                JOptionPane.showMessageDialog(null, "Does not support full screen!", "Error 0x01", JOptionPane.ERROR_MESSAGE);
                System.exit(1);
            }
        }
    });
}

and here is the UI which contains the KeyBoardFocusManger, and is added in addListeners() method:

class SpaceInvaderUI extends Window {

    private JPanel drawingPanel;
    private Image background;
    private JButton btnExit;

    public SpaceInvaderUI(Frame frame) {
        super(frame);
        try {
            background = ImageIO.read(getClass().getResourceAsStream("background.png"));
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, "Could not extract resource: " + ex.getMessage(), "Error 0x02", JOptionPane.ERROR_MESSAGE);
            System.exit(2);
        }
        createWindow();
    }

    private void createComponents() throws HeadlessException {
        drawingPanel = new DrawingPanel(background, this);
        btnExit = new JButton("Exit");
    }

    private void createWindow() {
        createComponents();
        addListeners();
        addComponentsToWindow();
    }

    private void addComponentsToWindow() {
        add(drawingPanel, BorderLayout.CENTER);
        add(btnExit, BorderLayout.SOUTH);
    }

    private void addListeners() {
        KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        manager.addKeyEventDispatcher(new MyDispatcher());
        btnExit.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                System.exit(0);
            }
        });
    }

    private class MyDispatcher implements KeyEventDispatcher {

        @Override
        public boolean dispatchKeyEvent(KeyEvent e) {
            if (e.getID() == KeyEvent.KEY_PRESSED) {
                System.out.println("pressed");
                System.exit(0);
            } else if (e.getID() == KeyEvent.KEY_RELEASED) {
                System.out.println("released");
                System.exit(0);
            } else if (e.getID() == KeyEvent.KEY_TYPED) {
                System.out.println("Typed");
                System.exit(0);
            }
            return false;
        }
    }
}

The exit button is just because I got tired of killing my app via taskmanager. Finally here is my panel on which the game will take place and my background is painted on:

public class DrawingPanel extends JPanel {

    private final Image background;
    private final SpaceInvaderUI invaderUI;

    DrawingPanel(Image background, SpaceInvaderUI invaderUI) {
        this.background = background;
        this.invaderUI = invaderUI;
    }

    @Override
    protected void paintComponent(Graphics grphcs) {
        super.paintComponent(grphcs);
        grphcs.drawImage(background.getScaledInstance((int) invaderUI.getWidth(), (int) invaderUI.getHeight(), Image.SCALE_SMOOTH), 0, 0, this);
    }
}

Thank you in advance.

EDIT: I have now tried using a keybinding on my drawingPanel but still nothing happens when I press f2:

class SpaceInvaderUI extends Window {

    private JPanel drawingPanel;
    private Image background;
    private JButton btnExit;

    public SpaceInvaderUI(Frame frame) {
        super(frame);
        try {
            background = ImageIO.read(getClass().getResourceAsStream("background.png"));
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(null, "Could not extract resource: " + ex.getMessage(), "Error 0x02", JOptionPane.ERROR_MESSAGE);
            System.exit(2);
        }
        createWindow();
    }

    private void createComponents() throws HeadlessException {
        drawingPanel = new DrawingPanel(background, this);
        btnExit = new JButton("Exit");
    }

    private void createWindow() {
        createComponents();
        addListeners();
        addComponentsToWindow();
    }

    private void addComponentsToWindow() {
        add(drawingPanel, BorderLayout.CENTER);
        add(btnExit, BorderLayout.SOUTH);
    }

    private void addListeners() {
        Action exit = new AbstractAction() {

            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        };
        drawingPanel.getInputMap().put(KeyStroke.getKeyStroke("F2"),
                exit);
        btnExit.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                System.exit(0);
            }
        });
    }
}
Community
  • 1
  • 1
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138

2 Answers2

5

Why are you using AWT components in your Swing GUI? I fear (but don't know for sure) that by doing this, you may be losing some of the Swing functionality.

If you are only capturing select key select key strokes to control the game, consider using Key Bindings.

Edit:
No, the AWT components aren't at fault, but still probably should not be used.

Edit 2:
Your top level Window is not focused for some reason. Continuing to test code...

Edit 3:
Using a JFrame worked for me:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Test3 {
   public static void main(String[] args) {
      EventQueue.invokeLater(new Runnable() {

         @Override
         public void run() {
            GraphicsEnvironment ge = GraphicsEnvironment
                  .getLocalGraphicsEnvironment();
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            if (gs.isFullScreenSupported()) {
               SpaceInvaderUI spaceInvaderUI = new SpaceInvaderUI(gs.getDefaultConfiguration());
               gs.setFullScreenWindow(spaceInvaderUI);
            } else {
               JOptionPane.showMessageDialog(null,
                     "Does not support full screen!", "Error 0x01",
                     JOptionPane.ERROR_MESSAGE);
               System.exit(1);
            }
         }
      });
   }
}

// class SpaceInvaderUI extends JWindow {
class SpaceInvaderUI extends JFrame {

   private JPanel drawingPanel;
   private Image background;
   private JButton btnExit;

   public SpaceInvaderUI(GraphicsConfiguration gc) {
      super(gc);
      createWindow();
      addKeyBindings();
      setUndecorated(true);
   }

   private void addKeyBindings() {
      int condition = JPanel.WHEN_IN_FOCUSED_WINDOW;
      InputMap inputMap = drawingPanel.getInputMap(condition );
      ActionMap actionMap = drawingPanel.getActionMap();

      boolean released = false;
      KeyStroke upArrowKeyStrokePressed = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, released );
      String upArrowPressed = "up arrow pressed";
      inputMap.put(upArrowKeyStrokePressed , upArrowPressed);
      actionMap.put(upArrowPressed, new AbstractAction() {

         @Override
         public void actionPerformed(ActionEvent arg0) {
            System.out.println("up arrow pressed");
         }
      });

      released = true;
      String upArrowReleased = "up arrow released";
      KeyStroke upArrowKeyStrokeReleased = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, released );
      inputMap.put(upArrowKeyStrokeReleased , upArrowReleased);
      actionMap.put(upArrowReleased , new AbstractAction() {

         @Override
         public void actionPerformed(ActionEvent arg0) {
            System.out.println("up arrow released");
         }
      });

   }

   private void createComponents() throws HeadlessException {
      drawingPanel = new DrawingPanel(background, this);
      btnExit = new JButton("Exit");
   }

   private void createWindow() {
      createComponents();
      addListeners();
      addComponentsToWindow();
   }

   private void addComponentsToWindow() {
      add(drawingPanel, BorderLayout.CENTER);
      add(btnExit, BorderLayout.SOUTH);
   }

   private void addListeners() {
//      KeyboardFocusManager manager = KeyboardFocusManager
//            .getCurrentKeyboardFocusManager();
//      manager.addKeyEventDispatcher(new MyDispatcher());
      btnExit.addActionListener(new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent ae) {
            System.exit(0);
         }
      });
   }
//
//   private class MyDispatcher implements KeyEventDispatcher {
//
//      @Override
//      public boolean dispatchKeyEvent(KeyEvent e) {
//         System.out.println("in dispatch. KeyEvent := " + e);
//         if (e.getID() == KeyEvent.KEY_PRESSED) {
//            System.out.println("pressed");
//            System.exit(0);
//         } else if (e.getID() == KeyEvent.KEY_RELEASED) {
//            System.out.println("released");
//            System.exit(0);
//         } else if (e.getID() == KeyEvent.KEY_TYPED) {
//            System.out.println("Typed");
//            System.exit(0);
//         }
//         return false;
//      }
//   }
}

class DrawingPanel extends JPanel {

   private final Image background;
   private final SpaceInvaderUI invaderUI;

   DrawingPanel(Image background, SpaceInvaderUI invaderUI) {
      this.background = background;
      this.invaderUI = invaderUI;
      setBackground(Color.pink);
   }

   @Override
   protected void paintComponent(Graphics grphcs) {
      super.paintComponent(grphcs);
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • aaaahhh How stupid of me, I was focused on adding keybindings to the `Window`, which obviously is impossible, never thought about adding it to my panel. Thanks a lot :) – David Kroukamp Jun 24 '12 at 16:25
  • Thank you It seems maybe I need to use a frame and just make it undecorated then set to full screen. – David Kroukamp Jun 24 '12 at 16:55
  • May I ask a question on KeyBinding ? Can we add, more than one key on the same `JComponent` by using `InputMap` and `ActionMap`, and use the same `AbstractAction` class ? – nIcE cOw Jun 24 '12 at 16:55
  • @nIcEcOw: yes, you can add as many keys as you'd like, and Actions can be shared. – Hovercraft Full Of Eels Jun 24 '12 at 16:57
  • But, say if each key is meant to perform a different task, is there a way to differentiate that in that class, as to which key has been pressed ? Like if I use `registerKeyboardAction()`, since it's obsolete now, in this I can specify an `ActionCommand` and differentiate that inside the same class, is there something similar here as well ? Shall I ask a question on this ? – nIcE cOw Jun 24 '12 at 17:02
  • @nIcEcOw: I don't think that you can get the KeyEvent information from the actionPerformed's ActionEvent object. I've sometimes used the same AbstractAction class, but have created unique objects with this class for the keys I'm capturing. – Hovercraft Full Of Eels Jun 24 '12 at 17:08
  • @nIcEcOw: HFOE is +1 correct, but I've cited an example [here](http://stackoverflow.com/a/11179296/230513) that may be useful. – trashgod Jun 24 '12 at 17:14
  • Ahha, THANKYOU again BOTH of you and KEEP SMILING :-). Seems like it's tough to incorporate what I am saying, in this [example](http://stackoverflow.com/questions/11171021/java-use-keystroke-with-arrow-key/11175795#11175795) I posted today, that means !! – nIcE cOw Jun 24 '12 at 17:20
  • @nIcEcOw: also take a look [here](http://stackoverflow.com/a/6887354/522444) and how I set up key bindings. – Hovercraft Full Of Eels Jun 24 '12 at 17:20
4

As shown in this related FullScreenTest, you can use the same Action instance for the button and the key binding.

Addendum: @nIcE cOw asks, Can we add more than one key on the same JComponent by using InputMap and ActionMap, and use the same AbstractAction class?

Yes, multiple key bindings are possible; I sometimes invoke doClick() to get the audio-visual feedback, as shown here.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • May I ask a question on KeyBinding ? Can we add, more than one key on the same `JComponent` by using `InputMap` and `ActionMap`, and use the same `AbstractAction` class ? – nIcE cOw Jun 24 '12 at 16:53
  • Thank you this seems like my only alternative if I cant get my version working – David Kroukamp Jun 24 '12 at 16:54