Here's the scenario: I have two java applications. The first is a visual application which employs a swing GUI, all wrapped up in a JFrame which has very complex behavior (very old code base) of which I can NOT change. I simply have a hook to the JFrame object.
The second application is the one I am writing, which is basically a unit tester for the first application. Using the JFrame hook and the JDI, I have been able to do all the introspection I need to perform these tests, which are going quite well. In fact, my tests are going well enough that I would like to run them in the background. However, since many of my tests involve dispatching KeyEvents and MouseEvents to the JFrame, these will stall once the window loses focus. From what I have read, this seems to be due to a requirement of the default KeyboardFocusManager which will only dispatch these events to components which are both showing and focused (which also requires the window which contains them to be both showing and focused). This brings me to my question:
How can I "force" dispatch events to certain swing components without the KeyboardFocusManager from stopping their procession?
Important note: The component which I wish to dispatch these events to is also registered as the permanent focus owner, which helps remove the ambiguity of which component ought to receive the events when the window is unfocused (KeyboardFocusManager.getGlobalPermanentFocusOwner())
How I make an event: (pretty simple stuff)
public void keyPress(int keycode, char c) {
KeyEvent press = new KeyEvent(content, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, keycode, c);
pushEventToQueue(press);
}
public void mousePress(int buttons) {
MouseEvent press = new MouseEvent(content, MouseEvent.MOUSE_PRESSED,
System.currentTimeMillis(), buttons, curX, curY, 1, false);
pushEventToQueue(press);
}
What I have tried (and why they didn't work):
Dispatching the event via Component.dispatchEvent(event). This doesn't work because it requires the component to be visible, as it routes through the KeyboardFocusManager (oddly enough).
Dispatching the event via KeyboardFocusManager.dispatchEvent(event) for the reason above.
Calling Component.requestFocus() or .requestFocusInWindow() will allow the event to be delivered, but don't work for me beause they force the Window container to be focused as well, which brings the window to the foreground.
Iterating through the permanent focus owner's listeners, and calling the event functions with my custom event. I am not exactly sure why this didn't work, but I suspect it has something to do with the lack of propagation through the different focus owners in normal application function.
Here is my current pushEventToQueue function, with failed commented out portions included for your amusement:
private void pushEventToQueue(AWTEvent evt) {
// Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(evt);
// Component perm = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
// if (perm == null) {
// content.dispatchEvent(evt);
// } else {
// if (evt instanceof KeyEvent) {
// for (KeyListener l:perm.getKeyListeners()) {
// if (evt.getID() == KeyEvent.KEY_PRESSED)
// l.keyPressed((KeyEvent) evt);
// else if (evt.getID() == KeyEvent.KEY_RELEASED)
// l.keyReleased((KeyEvent) evt);
// else if (evt.getID() == KeyEvent.KEY_TYPED)
// l.keyTyped((KeyEvent) evt);
// }
// } else if (evt instanceof MouseEvent) {
// for (MouseListener l:perm.getMouseListeners()) {
// if (evt.getID() == MouseEvent.MOUSE_PRESSED)
// l.mousePressed((MouseEvent) evt);
// else if (evt.getID() == MouseEvent.MOUSE_RELEASED)
// l.mouseReleased((MouseEvent) evt);
// else if (evt.getID() == MouseEvent.MOUSE_CLICKED)
// l.mouseClicked((MouseEvent) evt);
// }
// } else
// perm.dispatchEvent(evt);
// }
content.dispatchEvent(evt);
try {
Thread.sleep(50); //Minimal but necessary
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The only thing I can think of doing now, which I am not sure how to go about, is to extend the KeyboardFocusManager class and to add some functionality which will default the focus to an unfocused component of my choosing when no windows in the current JVM have focus (aka all java windows are in the background). Ideally, this wouldn't interfere with the existing program functionality since the only case in which it would exhibit non-default behavior is when all windows are unfocused.
I cannot change the code base of the swing application. That means I cannot implement KeyBindings instead of KeyListeners, nor can I override the isFocused/isShowing methods for swing components. What I can do is anything that reflection or the JDI offers, which seems a bit useless in this case.
Does anyone have experience with this? Can anyone offer guidance?