Jump to content
  • Advertisement
Sign in to follow this  
tom_mai78101

How do you organize KeyEvent Input Handler in Java?

This topic is 2607 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Here's a class that I have found that seemed to work, but wastes a lot of memory:

[source lang="java]
package com.mojang.escape;

import java.awt.event.*;

public class InputHandler implements KeyListener, FocusListener, MouseListener, MouseMotionListener {
public boolean[] keys = new boolean[65536];

public void mouseDragged(MouseEvent arg0) {
}

public void mouseMoved(MouseEvent arg0) {
}

public void mouseClicked(MouseEvent arg0) {
}

public void mouseEntered(MouseEvent arg0) {
}

public void mouseExited(MouseEvent arg0) {
}

public void mousePressed(MouseEvent arg0) {
}

public void mouseReleased(MouseEvent arg0) {
}

public void focusGained(FocusEvent arg0) {
}

public void focusLost(FocusEvent arg0) {
for (int i=0; i<keys.length; i++) {
keys = false;
}
}

public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code>0 && code<keys.length) {
keys = true;
}
}

public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
if (code>0 && code<keys.length) {
keys = false;
}
}

public void keyTyped(KeyEvent arg0) {
}
}
[/source]


Should I really use this design for my input detection class? What should I do with the wasted boolean array? Note that all of the Listeners were implemented for future use. Any suggestions were fine, just that whenever I think of it, it's cringes my mind a lot of OCDness. :blink:


Share this post


Link to post
Share on other sites
Advertisement
When JVM process starts up, it reserves 64 - 500MB of memory.

Your boolean array is 64kB. Ironically, the above is likely to be fastest solution, all things considered, with exception of clearing the entire array.

But Java comes with a Set class, so why not use that?


public class InputHandler implements KeyListener, FocusListener, MouseListener, MouseMotionListener {
private Set<Integer> keys;

public void focusLost(FocusEvent arg0) {
keys.clear();
} public void keyPressed(KeyEvent e) {
keys.add(e.getKeyCode());
} public void keyReleased(KeyEvent e) {
keys.remove(e.getKeyCode());
} }


However, using a set will consume much more memory over lifetime of application. First the integer from getKeyCode must be boxed into an Integer, creating new instance. Each element added creates another instance. So each add/remove performs two allocations at minimum.

Each of these means there's extra work for GC. It's not a big deal, but for real-time use, allocations tend to be avoided. Obviously, one could code an inline set using an array, considering that typically number of pressed keys will be < 5. Or even if 100 are pressed, one could still save memory.

Share this post


Link to post
Share on other sites
My program is run at real-time, so this is why I didn't think of using Sets in the first place. Since you said my class is the fastest solution known, I guess it will have to do, and may my OCD rest in peace a little bit.

By inline set initialization, do you mean manually adding the keys in use to the Set, so that when the keys were used, it will just take the keys detected in the Set? Would that be another fast and simple solution, even though I have to cast it to Big Integer?

Share this post


Link to post
Share on other sites

Since you said my class is the fastest solution known


Not "fastest known". Potentially more efficient given the presented alternatives.

By inline set initialization, do you mean manually adding the keys in use to the Set, so that when the keys were used, it will just take the keys detected in the Set? Would that be another fast and simple solution, even though I have to cast it to Big Integer?[/quote]

I meant this:class KeySet {
private int[] values = new int[16];
private int count;

public void add(int value) {
if (values.length <= count) return;

for (int i = 0; i < count; i++) {
if (values == value) return;
}
values[count] = value;
count++;
}

public void remove(int value) {
if (count == 0) return;
if (values.length <= count) return;

for (int i = 0; i < count; i++) {
if (values == value) {
values = values[count-1];
count--;
return;
}
}
}
};


Given that it's unlikely that 16 keys will be pressed at the same time, the above combines both approaches. Since the array only takes 64 bytes, linear search is sufficient.

Share this post


Link to post
Share on other sites
Here's a pseudo-code:
[source]
tick()
checksInput()
if (key press detected == true)
key = KeyEvent e.getKeyCode()
KeySet s.add(key)
manipulateInput()
int[] values = KeySet.values
for each (v of values)
if (values.contains(v) == true)
doInputAction(v)
gameTick()
//Do whatever the game wants to do.
[/source]

Other than setting the KeySet.values to be public, do you think I have optimized the manipulateInput() method as best as it can go? Just checking... :unsure:


Share this post


Link to post
Share on other sites

do you think I have optimized the manipulateInput() method as best as it can go? Just checking...


Ask the profiler. If it was previously the bottleneck and now no longer is, then yes.

Share this post


Link to post
Share on other sites

[quote name='tom_mai78101' timestamp='1319387546' post='4875628']
do you think I have optimized the manipulateInput() method as best as it can go? Just checking...


Ask the profiler. If it was previously the bottleneck and now no longer is, then yes.
[/quote]

Ok thanks for the help. :D

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!