Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (483)
Games in Android Showcase (110)
games submitted by our members
Games in WIP (550)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  KeyListener and Linux 'erroneous' behaviour  (Read 1126 times)
0 Members and 1 Guest are viewing this topic.
Offline Virusakos

Senior Newbie





« Posted 2010-06-15 20:09:41 »

Hello everyone,

I am trying to develop a pong clone, using pure Java 2D (i.e. no additional libraries) and Swing/AWT.
Everything works fine for now apart from the following:
When I minimize the game's frame (a JFrame and no full screen exclusive mode yet), and leave it minimized for, say, 20 minutes, after restoring the frame it looks like the JPanel inside the JFrame does not receive key events through KeyListener.
I have also tried to use Frame as the top most window and Canvas instead of a JPanel, but I get the same behaviour.
The 'erroneous' (?) behaviour exists only in linux (specifically Linux Mint 8 with XFCE).

The KeyListener (which is added to the panel/canvas) adds key events to a queue (implemented with LinkedList) and my game loop retrieves the first key event in queue and processes it (if exists) in each game update cycle.
I added a FocusListener, a WindowFocusListener and a WindowListener to the frame so as when it gets the focus or gets activated (or deiconified), I transfer the focus to the panel/canvas (with requestFocusInWindow()).
I also added a FocusListener on the panel/canvas to see if it does gets the focus.

What I have seen as an 'erroneous' behaviour is that, after the frame has been minimized for 20 minutes and then restored, the focus seems to be transferred to the panel/canvas but the KeyListener does not seem to get any key events.

I would really appreciate if you can help me to solve this problem.
Also, I would really like not to use any game engine as of now.

Here is some code that might help you understand a little bit more of how my game works.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
public class Pong extends Frame implements FocusListener, WindowListener, WindowFocusListener {
   private final PongPanel pp;
   
   public Pong() {
      addFocusListener(this);
      addWindowListener(this);
      addWindowFocusListener(this);
     
      pp = new PongPanel(640, 480, 300, 5);
     
      setBounds(0, 0, 640, 480);
      setResizable(false);
      setLocationRelativeTo(null);
     
      add(pp);
     
      pack();
      setVisible(true);
     
      pp.requestFocusInWindow();
   }
   
   @Override
   public void focusGained(FocusEvent e) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            pp.requestFocusInWindow();
         }
      });
   }

   @Override
   public void focusLost(FocusEvent e) {}

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

   @Override
   public void windowGainedFocus(WindowEvent e) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            pp.requestFocusInWindow();
         }
      });
   }

   @Override
   public void windowLostFocus(WindowEvent e) {}

   @Override
   public void windowActivated(WindowEvent e) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            pp.requestFocusInWindow();
         }
      });
   }

   @Override
   public void windowClosed(WindowEvent e) {}

   @Override
   public void windowClosing(WindowEvent e) {}

   @Override
   public void windowDeactivated(WindowEvent e) {}

   @Override
   public void windowDeiconified(WindowEvent e) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            pp.requestFocusInWindow();
         }
      });
   }

   @Override
   public void windowIconified(WindowEvent e) {}

   @Override
   public void windowOpened(WindowEvent e) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            pp.requestFocusInWindow();
         }
      });
   }
}


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
public class PongPanel extends BasePanel implements FocusListener {
   public PongPanel(int width, int height, int updatesPerSecond, int maxFrameSkip) {
      super(width, height, updatesPerSecond, maxFrameSkip);
      addFocusListener(this);
   }

   @Override
   public void focusGained(FocusEvent e) {
      System.out.println("I have the focus");
   }

   @Override
   public void focusLost(FocusEvent e) {
      System.out.println("I lost the focus");
   }
}


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
public class BasePanel extends Canvas implements KeyListener, Runnable {   
   protected final int MAX_FRAMESKIP;
   protected final int PHEIGHT;
   protected final int PWIDTH;
   protected final int SKIP_TICKS;
   protected final int TICKS_PER_SECOND;

   protected boolean running;
   protected int loops;
   protected LinkedList<KeyEvent> keyEvents = new LinkedList<KeyEvent>();
   protected long nextGameTick = nextGameTick();
   protected Thread animator;
   
   public BasePanel(int width, int height, int updatesPerSecond, int maxFrameSkips) {
      super();
     
      TICKS_PER_SECOND = updatesPerSecond;
      SKIP_TICKS = 1000 / TICKS_PER_SECOND;
      MAX_FRAMESKIP = maxFrameSkips;
      PWIDTH = width;
      PHEIGHT = height;
     
      super.setPreferredSize(new Dimension(PWIDTH, PHEIGHT));
      super.setBounds(0, 0, PWIDTH, PHEIGHT);
      super.setIgnoreRepaint(true);
      super.setFocusable(true);
     
      super.addKeyListener(this);
   }
   
   public void addNotify() {
      super.addNotify();

      if (animator == null) {
         animator = new Thread(this);
      }
      startAnimator();
   }
   
   private void baseRender(float interpolation) {}
   private void baseUpdate() {}
   
   @Override
   public void keyPressed(final KeyEvent e) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            keyEvents.add(e);
         }
      });
   }

   @Override
   public void keyReleased(KeyEvent e) {}

   @Override
   public void keyTyped(KeyEvent e) {}
   
   public static final long nextGameTick() {
      return System.nanoTime() / 1000000L;
   }
   
   protected void processKeyEvents() {}
   protected void render(float interpolation) {}
   
   public void run() {
      while (running) {
         loops = 0;
         while (nextGameTick() > nextGameTick && loops < MAX_FRAMESKIP) {
            if (keyEvents.size() > 0) {
               processKeyEvents();
            }
            baseUpdate();
         }
         
         baseRender(0.0f);

         
         Thread.yield();
      }
   }
   
   private void startAnimator() {
      running = true;
      animator.start();
   }
   
   protected void update() {}
}


Kind Regards,
Charalampos
Offline Virusakos

Senior Newbie





« Reply #1 - Posted 2010-06-20 07:50:05 »

Looks like if I remove the key listener from the canvas/panel when the top frame is deactivated and then add it again when the top frame is activated then the 'erroneous' behaviour disappears.

Regards,
Charalampos
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 781
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #2 - Posted 2010-06-20 16:49:08 »

Looks like if I remove the key listener from the canvas/panel when the top frame is deactivated and then add it again when the top frame is activated then the 'erroneous' behaviour disappears.

Regards,
Charalampos

Interesting. You might want to file a bug-report to the AWT team.

http://bugreport.sun.com/bugreport/

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Virusakos

Senior Newbie





« Reply #3 - Posted 2010-06-20 17:23:01 »

Does it really sound like a Java bug?
I'm not 100% sure.
It might be my code.
Offline Virusakos

Senior Newbie





« Reply #4 - Posted 2010-06-21 23:17:59 »

Trying to create a test case to report the bug I came up with... well... a working version...   Cheesy

This was the test case I created, which works fine!
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.awt.event.WindowListener;

public class TestCaseFrame extends Frame implements FocusListener, WindowFocusListener, WindowListener {
   TestCaseCanvas canvas;
   
   public TestCaseFrame() {
      addWindowListener(this);
     
      canvas = new TestCaseCanvas();
     
      setTitle("TestCaseFrame");
      setBounds(0, 0, 640, 480);
      setResizable(false);
      setLocationRelativeTo(null);
     
      add(canvas);
     
      pack();
      setVisible(true);
   }

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

   @Override
   public void focusGained(FocusEvent e) {
      canvas.requestFocusInWindow();
   }

   @Override
   public void focusLost(FocusEvent e) {}

   @Override
   public void windowGainedFocus(WindowEvent e) {
      canvas.requestFocusInWindow();
   }

   @Override
   public void windowLostFocus(WindowEvent e) {}

   @Override
   public void windowActivated(WindowEvent e) {
      canvas.requestFocusInWindow();
   }

   @Override
   public void windowClosed(WindowEvent e) {}

   @Override
   public void windowClosing(WindowEvent e) {}

   @Override
   public void windowDeactivated(WindowEvent e) {}

   @Override
   public void windowDeiconified(WindowEvent e) {
      canvas.requestFocusInWindow();
   }

   @Override
   public void windowIconified(WindowEvent e) {}

   @Override
   public void windowOpened(WindowEvent e) {}

}


1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.LinkedList;

public class TestCaseCanvas extends Canvas implements FocusListener, KeyListener, Runnable {
   final int MAX_FRAMESKIP;
   final int PHEIGHT;
   final int PWIDTH;
   final int SKIP_TICKS;
   final int TICKS_PER_SECOND;
   
   boolean running;
   Graphics dbg;
   Image dbImg;
   int loops;
   LinkedList<KeyEvent> keyEvents = new LinkedList<KeyEvent>();
   long nextGameTick = nextGameTick();
   Thread animator;
   
   public TestCaseCanvas() {
      TICKS_PER_SECOND = 300;
      SKIP_TICKS = 1000 / TICKS_PER_SECOND;
      MAX_FRAMESKIP = 5;
      PWIDTH = 640;
      PHEIGHT = 480;
     
      setPreferredSize(new Dimension(PWIDTH, PHEIGHT));
      setBounds(0, 0, PWIDTH, PHEIGHT);
      setIgnoreRepaint(true);
      setFocusable(true);
     
      addFocusListener(this);
      addKeyListener(this);
   }
   
   public void addNotify() {
      super.addNotify();

      if (animator == null) {
         animator = new Thread(this);
      }
      startAnimator();
   }
   
   @Override
   public void focusGained(FocusEvent e) {
      System.out.println("I received focus");
   }

   @Override
   public void focusLost(FocusEvent e) {}

   @Override
   public void keyPressed(final KeyEvent e) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            keyEvents.add(e);
         }
      });
   }

   @Override
   public void keyReleased(KeyEvent e) {}

   @Override
   public void keyTyped(KeyEvent e) {}
   
   static long nextGameTick() {
      return System.nanoTime() / 1000000L;
   }
   
   void processKeyEvents() {
      KeyEvent e = keyEvents.poll();
      if (e != null) {
         System.out.println("Processing key event: " + e);
      }
   }
   
   void render() {
      try {
         if (dbImg == null) {
            dbImg = getGraphicsConfiguration().createCompatibleImage(PWIDTH, PHEIGHT);
         }
         
         if (dbg == null) {
            dbg = dbImg.getGraphics();
         }
         
         dbg.setColor(Color.BLACK);
         dbg.fillRect(0, 0, PWIDTH, PHEIGHT);
         dbg.setColor(Color.WHITE);
         dbg.drawString("This is a test case", 20, 20);
         
         Graphics g = getGraphics();
         g.drawImage(dbImg, 0, 0, PWIDTH, PHEIGHT, this);
         Toolkit.getDefaultToolkit().sync();
         g.dispose();
      }
      catch (Exception e) {
         System.out.println("Graphics error: " + e.getLocalizedMessage());
      }
   }
   
   public void run() {
      while (running) {
         loops = 0;
         while (nextGameTick() > nextGameTick && loops < MAX_FRAMESKIP) {
            if (keyEvents.size() > 0) {
               processKeyEvents();
            }
            nextGameTick += SKIP_TICKS;
            loops++;
         }
         
         render();
         
         Thread.yield();
      }
     
      animator = null;
   }
   
   void startAnimator() {
      running = true;
      animator.start();
   }
}


Going through the previous test case, I had a thought that the FocusListener was not working as it should, hence the KeyListener was never getting the KeyEvents.
Changing the PongPanel class with the following code, it fixes the 'erroneous' behaviour
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
public class PongPanel extends BasePanel implements FocusListener {
   public PongPanel(int width, int height, int updatesPerSecond, int maxFrameSkip) {
      super(width, height, updatesPerSecond, maxFrameSkip);
      addFocusListener(this);
   }

   @Override
   public void focusGained(FocusEvent e) {
      System.out.println("I have the focus");
      super.requestFocusInWindow();
   }

   @Override
   public void focusLost(FocusEvent e) {
      System.out.println("I lost the focus");
   }
}


Do I feel a little tiny bit wiser or do I?  Tongue

Onwards to make Java play sounds in Linux  persecutioncomplex

Regards,
Charalampos
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CopyableCougar4 (17 views)
2014-08-22 19:31:30

atombrot (28 views)
2014-08-19 09:29:53

Tekkerue (25 views)
2014-08-16 06:45:27

Tekkerue (23 views)
2014-08-16 06:22:17

Tekkerue (15 views)
2014-08-16 06:20:21

Tekkerue (22 views)
2014-08-16 06:12:11

Rayexar (61 views)
2014-08-11 02:49:23

BurntPizza (39 views)
2014-08-09 21:09:32

BurntPizza (31 views)
2014-08-08 02:01:56

Norakomi (38 views)
2014-08-06 19:49:38
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!