Skip to content

Commit 3b3b725

Browse files
committed
Tests - fixed flaw in key event processing for non-attached UI
components
1 parent ef27f4e commit 3b3b725

File tree

3 files changed

+45
-6
lines changed

3 files changed

+45
-6
lines changed

Ghidra/Features/Base/src/main/help/help/topics/ConsolePlugin/console.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,5 @@ <H2 align="left">Navigation</H2>
5353

5454
<P align="left" class="providedbyplugin">Provided by: <I>ConsolePlugin</I></P>
5555

56-
<P class="relatedtopic">Related Topics:</P>
5756
</BODY>
5857
</HTML>

Ghidra/Features/Python/src/main/help/help/topics/Python/interpreter.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,5 @@ <H2>Additional Help</H2>
165165

166166
<P align="left" class="providedbyplugin">Provided by: <I>PythonPlugin</I></P>
167167

168-
<P class="relatedtopic">Related Topics:</P>
169168
</BODY>
170169
</HTML>

Ghidra/Framework/Docking/src/main/java/docking/actions/KeyBindingUtils.java

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,14 @@ public static void exportKeyBindings(ToolOptions keyBindingOptions) {
176176
/**
177177
* Changes the given key event to the new source component and then dispatches that event.
178178
* This method is intended for clients that wish to effectively take a key event given to
179-
* one component and give it to another component. This is seldom-used code; if you don't
180-
* know when to use this code, then don't.
179+
* one component and give it to another component.
180+
*
181+
* <p>This method exists to deal with the complicated nature of key event processing and
182+
* how our (not Java's) framework processes key event bindings to trigger actions. If not
183+
* for our special processing of action key bindings, then this method would not be
184+
* necessary.
185+
*
186+
* <p><b>This is seldom-used code; if you don't know when to use this code, then don't.</b>
181187
*
182188
* @param newSource the new target of the event
183189
* @param e the existing event
@@ -190,9 +196,44 @@ public static void retargetEvent(Component newSource, KeyEvent e) {
190196

191197
KeyEvent newEvent = new KeyEvent(newSource, e.getID(), e.getWhen(), e.getModifiersEx(),
192198
e.getKeyCode(), e.getKeyChar(), e.getKeyLocation());
193-
e.consume();
199+
200+
/*
201+
Unusual Code Alert!
202+
203+
The KeyboardFocusManager is a complicated beast. Here we use knowledge of one such
204+
complication to correctly route key events. If the client of this method passes
205+
a component whose 'isShowing()' returns false, then the manager will not send the
206+
event to that component. Almost all clients will pass fully attached/realized
207+
components to the manager. We, however, will sometimes pass components that are not
208+
attached; for example, when we are using said components with a renderer to perform
209+
our own painting. In the case of non-attached components, we must call the
210+
redispatchEvent() method ourselves.
211+
212+
Why don't we just always call redispatchEvent()? Well, that
213+
method will not pass the new cloned event we just created back through the full
214+
key event pipeline. This means that tool-level (our Tool API, not Java)
215+
actions will not work, as tool-level actions are handled at the beginning of the
216+
key event pipeline, not by the components themselves.
217+
218+
Also, we have here guilty knowledge that the aforementioned tool-level key processing
219+
will check to see if the event was consumed. If consumed, then no further processing
220+
will happen; if not consumed, then the framework will continue to process the event
221+
passed into this method. Thus, after we send the new event, we will update the
222+
original event to match the consumed state of our new event. This means that the
223+
component passed to this method must, somewhere in its processing, consume the key
224+
event we dispatch here, if they do not wish for any further processing to take place.
225+
*/
194226
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
195-
kfm.dispatchEvent(newEvent);
227+
if (newSource.isShowing()) {
228+
kfm.dispatchEvent(newEvent);
229+
}
230+
else {
231+
kfm.redispatchEvent(newSource, newEvent);
232+
}
233+
234+
if (newEvent.isConsumed()) {
235+
e.consume();
236+
}
196237
}
197238

198239
/**

0 commit comments

Comments
 (0)