Merge remote-tracking branch

'origin/GP-5007-dragonmacher-backspace-for-key-binding--SQUASHED'
(Closes #6972)
This commit is contained in:
Ryan Kurtz 2024-10-11 08:21:38 -04:00
commit a3d606ad87
11 changed files with 151 additions and 61 deletions

View file

@ -150,12 +150,16 @@
<LI>Click in the text field for the key binding.</LI> <LI>Click in the text field for the key binding.</LI>
<LI>Press the &lt;Enter&gt; or &lt;Backspace&gt; to clear it.</LI> <LI>Press the <IMG SRC="Icons.DELETE_ICON"> button to clear it.</LI>
<LI>Click on the <B><FONT size="4">OK</FONT></B> or <FONT size="4"><B>Apply</B></FONT> <LI>Click on the <B><FONT size="4">OK</FONT></B> or <FONT size="4"><B>Apply</B></FONT>
button.</LI> button.</LI>
</OL> </OL>
</BLOCKQUOTE><!-- Import/Export Key Bindings --><A name="Import"></A> </BLOCKQUOTE>
<!-- Import/Export Key Bindings -->
<A name="Import"></A>
<H3>Import Key Bindings</H3> <H3>Import Key Bindings</H3>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 9 KiB

Before After
Before After

View file

@ -21,7 +21,6 @@ import java.awt.Component;
import javax.swing.*; import javax.swing.*;
import docking.*; import docking.*;
import docking.actions.KeyBindingUtils;
import docking.actions.ToolActions; import docking.actions.ToolActions;
import docking.widgets.label.GLabel; import docking.widgets.label.GLabel;
import ghidra.framework.plugintool.Plugin; import ghidra.framework.plugintool.Plugin;
@ -29,7 +28,7 @@ import ghidra.framework.plugintool.PluginTool;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
class KeyBindingInputDialog extends DialogComponentProvider implements KeyEntryListener { class KeyBindingInputDialog extends DialogComponentProvider implements KeyEntryListener {
private KeyEntryTextField kbField; private KeyEntryPanel kbPanel;
private KeyStroke ks; private KeyStroke ks;
private boolean isCancelled; private boolean isCancelled;
private Plugin plugin; private Plugin plugin;
@ -39,15 +38,15 @@ class KeyBindingInputDialog extends DialogComponentProvider implements KeyEntryL
super("Assign Script Key Binding", true, true, true, false); super("Assign Script Key Binding", true, true, true, false);
this.plugin = plugin; this.plugin = plugin;
kbField = new KeyEntryTextField(20, this); kbPanel = new KeyEntryPanel(20, this);
kbField.setName("KEY_BINDING"); if (currentKeyStroke != null) {
kbField.setText( kbPanel.setKeyStroke(currentKeyStroke);
currentKeyStroke == null ? "" : KeyBindingUtils.parseKeyStroke(currentKeyStroke)); }
JPanel panel = new JPanel(new BorderLayout(10, 10)); JPanel panel = new JPanel(new BorderLayout(10, 10));
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.add(new GLabel(scriptName), BorderLayout.NORTH); panel.add(new GLabel(scriptName), BorderLayout.NORTH);
panel.add(kbField, BorderLayout.CENTER); panel.add(kbPanel, BorderLayout.CENTER);
addWorkPanel(panel); addWorkPanel(panel);
addOKButton(); addOKButton();
@ -91,6 +90,6 @@ class KeyBindingInputDialog extends DialogComponentProvider implements KeyEntryL
void setKeyStroke(KeyStroke ks) { void setKeyStroke(KeyStroke ks) {
this.ks = ks; this.ks = ks;
kbField.setKeyStroke(ks); kbPanel.setKeyStroke(ks);
} }
} }

View file

@ -40,6 +40,7 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest {
private KeyEntryDialog keyEntryDialog; private KeyEntryDialog keyEntryDialog;
private JTextPane collisionPane; private JTextPane collisionPane;
private KeyEntryTextField keyEntryField; private KeyEntryTextField keyEntryField;
private JButton clearButton;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@ -71,7 +72,7 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest {
// clear the action // clear the action
showDialog(unboundAction); showDialog(unboundAction);
triggerBackspaceKey(keyEntryField); pressButton(clearButton);
pressDialogOK(); pressDialogOK();
acceleratorKey = unboundAction.getKeyBinding(); acceleratorKey = unboundAction.getKeyBinding();
@ -98,7 +99,7 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest {
showDialog(boundAction); showDialog(boundAction);
assertEquals("OPEN_BRACKET", keyEntryField.getText()); assertEquals("OPEN_BRACKET", keyEntryField.getText());
triggerBackspaceKey(keyEntryField); pressButton(clearButton);
pressDialogOK(); pressDialogOK();
KeyStroke ks = boundAction.getKeyBinding(); KeyStroke ks = boundAction.getKeyBinding();
@ -113,7 +114,7 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest {
KeyStroke oldKs = boundAction.getKeyBinding(); KeyStroke oldKs = boundAction.getKeyBinding();
assertEquals("OPEN_BRACKET", keyEntryField.getText()); assertEquals("OPEN_BRACKET", keyEntryField.getText());
triggerBackspaceKey(keyEntryField); pressButton(clearButton);
pressDialogOK(); pressDialogOK();
KeyStroke ks = boundAction.getKeyBinding(); KeyStroke ks = boundAction.getKeyBinding();
@ -175,7 +176,7 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest {
keyBindingKeyStroke.getKeyCode()); keyBindingKeyStroke.getKeyCode());
assertEquals(keyEntryDialog.getStatusText().trim(), ""); assertEquals(keyEntryDialog.getStatusText().trim(), "");
triggerBackspaceKey(keyEntryField); pressButton(clearButton);
triggerText(keyEntryField, "g"); triggerText(keyEntryField, "g");
pressDialogOK(); pressDialogOK();
@ -259,6 +260,8 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest {
assertNotNull(keyEntryDialog); assertNotNull(keyEntryDialog);
collisionPane = (JTextPane) getInstanceField("collisionPane", keyEntryDialog); collisionPane = (JTextPane) getInstanceField("collisionPane", keyEntryDialog);
keyEntryField = (KeyEntryTextField) getInstanceField("keyEntryField", keyEntryDialog); KeyEntryPanel keyPanel = (KeyEntryPanel) getInstanceField("keyEntryPanel", keyEntryDialog);
keyEntryField = (KeyEntryTextField) getInstanceField("keyEntryField", keyPanel);
clearButton = (JButton) getInstanceField("clearButton", keyPanel);
} }
} }

View file

@ -49,7 +49,7 @@ public class GhidraScriptMgrPlugin3Test extends AbstractGhidraScriptMgrPluginTes
KeyBindingInputDialog kbid = pressKeyBindingAction(); KeyBindingInputDialog kbid = pressKeyBindingAction();
KeyEntryTextField keyField = KeyEntryTextField keyField =
(KeyEntryTextField) findComponentByName(kbid.getComponent(), "KEY_BINDING"); (KeyEntryTextField) findComponentByName(kbid.getComponent(), "Key Entry Text Field");
triggerActionKey(keyField, InputEvent.SHIFT_DOWN_MASK | InputEvent.ALT_DOWN_MASK, triggerActionKey(keyField, InputEvent.SHIFT_DOWN_MASK | InputEvent.ALT_DOWN_MASK,
KeyEvent.VK_H); KeyEvent.VK_H);
pressButtonByText(kbid, "OK"); pressButtonByText(kbid, "OK");
@ -292,7 +292,8 @@ public class GhidraScriptMgrPlugin3Test extends AbstractGhidraScriptMgrPluginTes
SaveDialog saveDialog = waitForDialogComponent(SaveDialog.class); SaveDialog saveDialog = waitForDialogComponent(SaveDialog.class);
final ListPanel listPanel = (ListPanel) findComponentByName(saveDialog.getComponent(), "PATH_LIST"); final ListPanel listPanel =
(ListPanel) findComponentByName(saveDialog.getComponent(), "PATH_LIST");
assertNotNull(listPanel); assertNotNull(listPanel);
assertTrue(listPanel.isVisible()); assertTrue(listPanel.isVisible());
assertEquals(2, listPanel.getListModel().getSize()); assertEquals(2, listPanel.getListModel().getSize());

View file

@ -30,7 +30,7 @@ public class ActionBindingPanel extends JPanel {
private static final String DISABLED_HINT = "Select an action"; private static final String DISABLED_HINT = "Select an action";
private KeyEntryTextField keyEntryField; private KeyEntryPanel keyEntryPanel;
private JCheckBox useMouseBindingCheckBox; private JCheckBox useMouseBindingCheckBox;
private MouseEntryTextField mouseEntryField; private MouseEntryTextField mouseEntryField;
private JPanel textFieldPanel; private JPanel textFieldPanel;
@ -49,14 +49,14 @@ public class ActionBindingPanel extends JPanel {
textFieldPanel = new JPanel(new BorderLayout()); textFieldPanel = new JPanel(new BorderLayout());
keyEntryField = new KeyEntryTextField(20, ks -> listener.keyStrokeChanged(ks)); keyEntryPanel = new KeyEntryPanel(20, ks -> listener.keyStrokeChanged(ks));
keyEntryField.setDisabledHint(DISABLED_HINT); keyEntryPanel.setDisabledHint(DISABLED_HINT);
keyEntryField.setEnabled(false); // enabled on action selection keyEntryPanel.setEnabled(false); // enabled on action selection
mouseEntryField = new MouseEntryTextField(20, mb -> listener.mouseBindingChanged(mb)); mouseEntryField = new MouseEntryTextField(20, mb -> listener.mouseBindingChanged(mb));
mouseEntryField.setDisabledHint(DISABLED_HINT); mouseEntryField.setDisabledHint(DISABLED_HINT);
mouseEntryField.setEnabled(false); // enabled on action selection mouseEntryField.setEnabled(false); // enabled on action selection
textFieldPanel.add(keyEntryField, BorderLayout.NORTH); textFieldPanel.add(keyEntryPanel, BorderLayout.NORTH);
String checkBoxText = "Enter Mouse Binding"; String checkBoxText = "Enter Mouse Binding";
useMouseBindingCheckBox = new GCheckBox(checkBoxText); useMouseBindingCheckBox = new GCheckBox(checkBoxText);
@ -73,12 +73,12 @@ public class ActionBindingPanel extends JPanel {
private void updateTextField() { private void updateTextField() {
if (useMouseBindingCheckBox.isSelected()) { if (useMouseBindingCheckBox.isSelected()) {
textFieldPanel.remove(keyEntryField); textFieldPanel.remove(keyEntryPanel);
textFieldPanel.add(mouseEntryField, BorderLayout.NORTH); textFieldPanel.add(mouseEntryField, BorderLayout.NORTH);
} }
else { else {
textFieldPanel.remove(mouseEntryField); textFieldPanel.remove(mouseEntryField);
textFieldPanel.add(keyEntryField, BorderLayout.NORTH); textFieldPanel.add(keyEntryPanel, BorderLayout.NORTH);
} }
validate(); validate();
@ -87,25 +87,25 @@ public class ActionBindingPanel extends JPanel {
public void setKeyBindingData(KeyStroke ks, MouseBinding mb) { public void setKeyBindingData(KeyStroke ks, MouseBinding mb) {
keyEntryField.setKeyStroke(ks); keyEntryPanel.setKeyStroke(ks);
mouseEntryField.setMouseBinding(mb); mouseEntryField.setMouseBinding(mb);
} }
@Override @Override
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
keyEntryField.clearField(); keyEntryPanel.clearField();
mouseEntryField.clearField(); mouseEntryField.clearField();
keyEntryField.setEnabled(enabled); keyEntryPanel.setEnabled(enabled);
mouseEntryField.setEnabled(enabled); mouseEntryField.setEnabled(enabled);
} }
public void clearKeyStroke() { public void clearKeyStroke() {
keyEntryField.clearField(); keyEntryPanel.clearField();
} }
public KeyStroke getKeyStroke() { public KeyStroke getKeyStroke() {
return keyEntryField.getKeyStroke(); return keyEntryPanel.getKeyStroke();
} }
public MouseBinding getMouseBinding() { public MouseBinding getMouseBinding() {

View file

@ -0,0 +1,85 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package docking;
import javax.swing.*;
import docking.widgets.EmptyBorderButton;
import resources.Icons;
/**
* A panel that holds a {@link KeyEntryTextField} and a button for clearing the current key binding.
* <p>
* This class is a drop-in replacement for clients that are currently using
* {@link KeyEntryTextField}.
*/
public class KeyEntryPanel extends JPanel {
private KeyEntryTextField keyEntryField;
private JButton clearButton;
/**
* Constructs this class with a text field based on the number of given columns.
* @param columns the number of columns for the text field
* @param listener the listener to be called as the user enters key strokes
*/
public KeyEntryPanel(int columns, KeyEntryListener listener) {
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
keyEntryField = new KeyEntryTextField(columns, listener);
clearButton = new EmptyBorderButton(Icons.DELETE_ICON);
clearButton.setToolTipText("Clear the current key binding");
clearButton.addActionListener(e -> keyEntryField.clearField());
add(keyEntryField);
add(Box.createHorizontalStrut(2));
add(clearButton);
}
/**
* Sets the key stroke on this panel
* @param ks the key stroke
*/
public void setKeyStroke(KeyStroke ks) {
keyEntryField.setKeyStroke(ks);
}
/**
* Gets the key stroke being used by this panel
* @return the key stroke
*/
public KeyStroke getKeyStroke() {
return keyEntryField.getKeyStroke();
}
/**
* Sets the text field hint for this panel.
*
* @param disabledHint the hint
* @see KeyEntryTextField#setDisabledHint(String)
*/
public void setDisabledHint(String disabledHint) {
keyEntryField.setDisabledHint(disabledHint);
}
/**
* Clears the key stroke being used by this panel
*/
public void clearField() {
keyEntryField.clearField();
}
}

View file

@ -82,9 +82,12 @@ public class KeyEntryTextField extends HintTextField {
} }
public void clearField() { public void clearField() {
ksName = null; if (currentKeyStroke == null) {
return;
}
setText(""); setText("");
currentKeyStroke = null; processKeyStroke(null, true);
} }
private void processKeyStroke(KeyStroke ks, boolean notify) { private void processKeyStroke(KeyStroke ks, boolean notify) {
@ -128,17 +131,13 @@ public class KeyEntryTextField extends HintTextField {
public void keyPressed(KeyEvent e) { public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode(); int keyCode = e.getKeyCode();
KeyStroke keyStroke = null; KeyStroke keyStroke = null;
if (!isClearKey(keyCode) && !isModifiersOnly(e)) { if (!isModifiersOnly(e)) {
keyStroke = KeyStroke.getKeyStroke(keyCode, e.getModifiersEx()); keyStroke = KeyStroke.getKeyStroke(keyCode, e.getModifiersEx());
} }
processKeyStroke(keyStroke, true); processKeyStroke(keyStroke, true);
e.consume(); e.consume();
} }
private boolean isClearKey(int keyCode) {
return keyCode == KeyEvent.VK_BACK_SPACE || keyCode == KeyEvent.VK_ENTER;
}
private boolean isModifiersOnly(KeyEvent event) { private boolean isModifiersOnly(KeyEvent event) {
String keyText = KeyEvent.getKeyText(event.getKeyCode()); String keyText = KeyEvent.getKeyText(event.getKeyCode());
return keyText.equals(KeyEvent.getKeyText(KeyEvent.VK_CONTROL)) || return keyText.equals(KeyEvent.getKeyText(KeyEvent.VK_CONTROL)) ||

View file

@ -42,7 +42,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
private DockingActionIf action; private DockingActionIf action;
private JPanel defaultPanel; private JPanel defaultPanel;
private KeyEntryTextField keyEntryField; private KeyEntryPanel keyEntryPanel;
private JTextPane collisionPane; private JTextPane collisionPane;
private StyledDocument doc; private StyledDocument doc;
@ -83,8 +83,8 @@ public class KeyEntryDialog extends DialogComponentProvider {
StyledDocument document = pane.getStyledDocument(); StyledDocument document = pane.getStyledDocument();
try { try {
document.insertString(0, "To add or change a key binding, type any key combination.\n" + document.insertString(0, "To add or change a key binding, type any key combination",
"To remove a key binding, press <Enter> or <Backspace>.", null); null);
} }
catch (BadLocationException e1) { catch (BadLocationException e1) {
// shouldn't be possible // shouldn't be possible
@ -100,7 +100,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
labelPanel.add(pane); labelPanel.add(pane);
labelPanel.add(Box.createHorizontalStrut(5)); labelPanel.add(Box.createHorizontalStrut(5));
keyEntryField = new KeyEntryTextField(20, keyStroke -> { keyEntryPanel = new KeyEntryPanel(20, keyStroke -> {
okButton.setEnabled(true); okButton.setEnabled(true);
updateCollisionPane(keyStroke); updateCollisionPane(keyStroke);
}); });
@ -109,12 +109,12 @@ public class KeyEntryDialog extends DialogComponentProvider {
defaultPanel.setBorder(BorderFactory.createLoweredBevelBorder()); defaultPanel.setBorder(BorderFactory.createLoweredBevelBorder());
JPanel p = new JPanel(new FlowLayout(FlowLayout.CENTER)); JPanel p = new JPanel(new FlowLayout(FlowLayout.CENTER));
p.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); p.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
p.add(keyEntryField); p.add(keyEntryPanel);
KeyStroke keyBinding = action.getKeyBinding(); KeyStroke keyBinding = action.getKeyBinding();
if (keyBinding != null) { if (keyBinding != null) {
keyEntryField.setText(KeyBindingUtils.parseKeyStroke(keyBinding)); keyEntryPanel.setKeyStroke(keyBinding);
} }
setFocusComponent(keyEntryField); setFocusComponent(keyEntryPanel);
defaultPanel.add(p, BorderLayout.CENTER); defaultPanel.add(p, BorderLayout.CENTER);
JPanel mainPanel = new JPanel(new BorderLayout()); JPanel mainPanel = new JPanel(new BorderLayout());
@ -144,7 +144,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
* @param ks the keystroke to set * @param ks the keystroke to set
*/ */
public void setKeyStroke(KeyStroke ks) { public void setKeyStroke(KeyStroke ks) {
keyEntryField.setKeyStroke(ks); keyEntryPanel.setKeyStroke(ks);
updateCollisionPane(ks); updateCollisionPane(ks);
} }
@ -155,7 +155,7 @@ public class KeyEntryDialog extends DialogComponentProvider {
@Override @Override
protected void okCallback() { protected void okCallback() {
KeyStroke newKs = keyEntryField.getKeyStroke(); KeyStroke newKs = keyEntryPanel.getKeyStroke();
String errorMessage = toolActions.validateActionKeyBinding(action, newKs); String errorMessage = toolActions.validateActionKeyBinding(action, newKs);
if (errorMessage != null) { if (errorMessage != null) {
setStatusText(errorMessage); setStatusText(errorMessage);

View file

@ -219,8 +219,7 @@ public class KeyBindingsPanel extends JPanel {
// the content of the left-hand side label // the content of the left-hand side label
MultiLineLabel mlabel = MultiLineLabel mlabel =
new MultiLineLabel("To add or change a key binding, select an action\n" + new MultiLineLabel("To add or change a key binding, select an action\n" +
"and type any key combination\n \n" + "and type any key combination.");
"To remove a key binding, select an action and\n" + "press <Enter> or <Backspace>");
JPanel labelPanel = new JPanel(); JPanel labelPanel = new JPanel();
labelPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 0)); labelPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 0));
BoxLayout bl = new BoxLayout(labelPanel, BoxLayout.X_AXIS); BoxLayout bl = new BoxLayout(labelPanel, BoxLayout.X_AXIS);