Tests - fixed flaw in key event processing for non-attached UI

components
This commit is contained in:
dragonmacher 2019-11-25 17:55:07 -05:00
parent ef27f4ecb6
commit 3b3b7259bc
3 changed files with 45 additions and 6 deletions

View file

@ -53,6 +53,5 @@
<P align="left" class="providedbyplugin">Provided by: <I>ConsolePlugin</I></P>
<P class="relatedtopic">Related Topics:</P>
</BODY>
</HTML>

View file

@ -165,6 +165,5 @@
<P align="left" class="providedbyplugin">Provided by: <I>PythonPlugin</I></P>
<P class="relatedtopic">Related Topics:</P>
</BODY>
</HTML>

View file

@ -176,8 +176,14 @@ public class KeyBindingUtils {
/**
* Changes the given key event to the new source component and then dispatches that event.
* This method is intended for clients that wish to effectively take a key event given to
* one component and give it to another component. This is seldom-used code; if you don't
* know when to use this code, then don't.
* one component and give it to another component.
*
* <p>This method exists to deal with the complicated nature of key event processing and
* how our (not Java's) framework processes key event bindings to trigger actions. If not
* for our special processing of action key bindings, then this method would not be
* necessary.
*
* <p><b>This is seldom-used code; if you don't know when to use this code, then don't.</b>
*
* @param newSource the new target of the event
* @param e the existing event
@ -190,10 +196,45 @@ public class KeyBindingUtils {
KeyEvent newEvent = new KeyEvent(newSource, e.getID(), e.getWhen(), e.getModifiersEx(),
e.getKeyCode(), e.getKeyChar(), e.getKeyLocation());
e.consume();
/*
Unusual Code Alert!
The KeyboardFocusManager is a complicated beast. Here we use knowledge of one such
complication to correctly route key events. If the client of this method passes
a component whose 'isShowing()' returns false, then the manager will not send the
event to that component. Almost all clients will pass fully attached/realized
components to the manager. We, however, will sometimes pass components that are not
attached; for example, when we are using said components with a renderer to perform
our own painting. In the case of non-attached components, we must call the
redispatchEvent() method ourselves.
Why don't we just always call redispatchEvent()? Well, that
method will not pass the new cloned event we just created back through the full
key event pipeline. This means that tool-level (our Tool API, not Java)
actions will not work, as tool-level actions are handled at the beginning of the
key event pipeline, not by the components themselves.
Also, we have here guilty knowledge that the aforementioned tool-level key processing
will check to see if the event was consumed. If consumed, then no further processing
will happen; if not consumed, then the framework will continue to process the event
passed into this method. Thus, after we send the new event, we will update the
original event to match the consumed state of our new event. This means that the
component passed to this method must, somewhere in its processing, consume the key
event we dispatch here, if they do not wish for any further processing to take place.
*/
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
if (newSource.isShowing()) {
kfm.dispatchEvent(newEvent);
}
else {
kfm.redispatchEvent(newSource, newEvent);
}
if (newEvent.isConsumed()) {
e.consume();
}
}
/**
* A convenience method to register the given action with the given