package org.simantics.debug.graphical; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; /** *
* This class wraps your KeyAdapter and suppresses spurious repeated events. *
** Written by Brian Ziman and available * for download and comments at http://www.brianziman.com/r/post/stuff-200910092100. *
** When running in an X11 environment, it appears as though either Java or * the windowing system stupidly generate lots of repeated key events when * you hold a key down. As it is impractical to get users to reconfigure their * systems, and Sun seems unable to fix this issue (having been reported nearly * ten years ago). This adapter is an attempt to filter out the useless events. *
** Many people have whined about this, but few have fixed it. Some have tried, * but their solutions are not as clean as my OCD nature requires. Here are * some examples of what this is meant to handle: *
** * The goal is to generate a KeyPressed event when a key is pressed, * and to generate a KeyReleased event when a key is released. And * ONLY when a key is pressed or released. *
** The class is tested with Java 1.6.0 on Ubuntu 8.10, but should theoretically * work on any platform, even if that platform issues events properly anyway. * That is, this SHOULD work in a cross platform manner. If it doesn't, * please let me know and I may fix it. *
** You don't actually call any of the methods on this class, directly. When Java * thinks it is receiving an event, it will call the methods in this class, * which will, in turn, decide whether an event has actually occurred, and * call YOUR methods when you probably intended them to be called. *
** Replace: *
** addKeyListener(new KeyAdapter() { * public void keyPressed(KeyEvent e) { ... } * public void keyReleased(KeyEvent e) { ... } * }); **
* with *
** addKeyListener(new UsefulKeyAdapter(new KeyAdapter() { * public void keyPressed(KeyEvent e) { ... } * public void keyReleased(KeyEvent e) { ... } * })); **
* Don't use this for keyTyped() events. If you are interested in these * sorts of events, the default behaviour is probably what you actually * want. *
** See How to Write a Key Listener on Sun's web site for more details. *
*This algorithm queues up keyboard events as the system reports them, * and then uses a separate thread to handle the desired events, and * disregard the spurious events.
*Testing has indicated that there is zero delay between the key released * event and the subsequent key pressed event when that pair are generated * spuriously, and that is the case in which they are ignored. The default * tolerance is 10 ms, as it is possible that the system will not always * generate spurious key events instantly, but that is still substantially * faster than a physical keyboard is able to perform multiple physical * actions.
*This code uses an ArrayBlockingQueue so the thread will not spin while * waiting for input. Most events are handled immediately, and no event * will be delayed more than the specified maximum age (default 10 ms). * *
* This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. *
** This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. *
** You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. *
** Copyright 2009-2010 Brian Ziman *
** Please contact me if you find flaws in this software, or have any other * comments or suggestions. *
*The run loop processes events as they are queued up.
*New algorithm:
*All events get queued up in sequence.
** A separate thread pulls events off in a tight loop.
*If the head event is a key released event:
*