Last active
December 15, 2015 00:49
-
-
Save lharding/5176082 to your computer and use it in GitHub Desktop.
Example Processing code for getting around AWT's terrible key repeat handling on Linux. Takes advantage of the fact that autorepeat keypresses come inhumanly soon after the virtual key release to filter out keyup->keydown pairs that happen too fast. This example is from a project of mine that uses ultimately sends out key events as strings, but …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private static class NonsimultaneousTimeSeries<T> extends TreeMap<Long, T> { | |
@Override | |
public T put(Long when, T what) { | |
//If something already happened on this millisecond, try the next one: | |
while(containsKey(when)) when++; | |
return super.put(when, what); | |
} | |
} | |
private final StringBuilder keysDown = new StringBuilder(); | |
private final NonsimultaneousTimeSeries<String> inputEventQ = new NonsimultaneousTimeSeries<String>(); | |
private final NonsimultaneousTimeSeries<KEv> keyQ = new NonsimultaneousTimeSeries<KEv>(); | |
private final Map<Integer, KEv> lastUps = new HashMap<Integer, KEv>(); | |
private final Map<Integer, KEv> heldKeys = new HashMap<Integer, KEv>(); | |
private void sendInput() { | |
//send list as final input event for this frame | |
sendInputEvent(System.currentTimeMillis(), "KS", keysDown.toString()); | |
synchronized (inputEventQ) { | |
for(String s : inputEventQ.values()) { | |
try { | |
//System.out.println("Sending: " + s); | |
sendMessage(s); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
inputEventQ.clear(); | |
} | |
try { | |
sendMessage("P\n"); | |
outWriter.flush(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
//System.out.println("All input sent."); | |
} | |
private void debounceKeys() { | |
final int DEBOUNCE = 3; | |
long now = System.currentTimeMillis(); | |
for(KEv e : keyEvents) { | |
if(e.press) { | |
if((!lastUps.containsKey(e.keyCode)) || (lastUps.get(e.keyCode).when < (e.when - DEBOUNCE))) { | |
// If the last time this key went up is long enough ago, send a new down event | |
sendInputEvent(e.when, "KD", e.key, e.keyCode); | |
keyQ.put(e.when, e); | |
} | |
else { | |
// otherwise, send no down event, and get rid of the up event: | |
lastUps.remove(e.keyCode); | |
} | |
} | |
else { | |
lastUps.put(e.keyCode, e); | |
} | |
} | |
keyEvents.clear(); | |
// Check each recently upped key to see if it's stay up long enough to report: | |
List<KEv> toRemove = new ArrayList<KEv>(lastUps.size()); | |
for(KEv u : lastUps.values()) { | |
if(u.when < now-DEBOUNCE) { | |
toRemove.add(u); | |
sendInputEvent(u.when, "KU", u.key, u.keyCode); | |
keyQ.put(u.when, u); | |
} | |
} | |
for(KEv e : toRemove) { | |
lastUps.remove(e.keyCode); | |
} | |
//1. scan keyQ and build key state array | |
for(KEv k : keyQ.values()) { | |
if(k.press) | |
heldKeys.put(k.keyCode, k); | |
else | |
heldKeys.remove(k.keyCode); | |
} | |
//2. convert key state array to list of held keys | |
keysDown.delete(0, keysDown.length()); | |
for(KEv k : heldKeys.values()) { | |
keysDown.append(k.key); | |
keysDown.append(k.keyCode); | |
keysDown.append(" "); | |
} | |
//4. clear keyQ | |
keyQ.clear(); | |
} | |
static class KEv { | |
public boolean press; | |
public long when; | |
public char key; | |
public int keyCode; | |
KEv(boolean press, long when, char key, int keyCode) { | |
this.press = press; | |
this.when = when; | |
this.key = key; | |
this.keyCode = keyCode; | |
} | |
} | |
Queue<KEv> keyEvents = new ConcurrentLinkedQueue<KEv>(); | |
@Override | |
public void keyPressed(processing.event.KeyEvent event) { | |
keyEvents.add(new KEv(true, event.getMillis(), event.getKey(), event.getKeyCode())); | |
} | |
@Override | |
public void keyReleased(processing.event.KeyEvent event) { | |
keyEvents.add(new KEv(false, event.getMillis(), event.getKey(), event.getKeyCode())); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment