diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Tool/ToolOptions_Dialog.htm b/Ghidra/Features/Base/src/main/help/help/topics/Tool/ToolOptions_Dialog.htm index a486aea2a6..574d2d8fc1 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/Tool/ToolOptions_Dialog.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/Tool/ToolOptions_Dialog.htm @@ -150,12 +150,16 @@
  • Click in the text field for the key binding.
  • -
  • Press the <Enter> or <Backspace> to clear it.
  • +
  • Press the button to clear it.
  • Click on the OK or Apply button.
  • - + + + + +

    Import Key Bindings

    diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Tool/images/KeyBindings.png b/Ghidra/Features/Base/src/main/help/help/topics/Tool/images/KeyBindings.png index 224a6eb38d..c7f2c85ec2 100644 Binary files a/Ghidra/Features/Base/src/main/help/help/topics/Tool/images/KeyBindings.png and b/Ghidra/Features/Base/src/main/help/help/topics/Tool/images/KeyBindings.png differ diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Tool/images/SetKeyBindings.png b/Ghidra/Features/Base/src/main/help/help/topics/Tool/images/SetKeyBindings.png index aea7d9ecb3..0322020868 100644 Binary files a/Ghidra/Features/Base/src/main/help/help/topics/Tool/images/SetKeyBindings.png and b/Ghidra/Features/Base/src/main/help/help/topics/Tool/images/SetKeyBindings.png differ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/KeyBindingInputDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/KeyBindingInputDialog.java index 422a3947bf..d7e3c90ac8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/KeyBindingInputDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/KeyBindingInputDialog.java @@ -4,9 +4,9 @@ * 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. @@ -21,7 +21,6 @@ import java.awt.Component; import javax.swing.*; import docking.*; -import docking.actions.KeyBindingUtils; import docking.actions.ToolActions; import docking.widgets.label.GLabel; import ghidra.framework.plugintool.Plugin; @@ -29,7 +28,7 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.util.HelpLocation; class KeyBindingInputDialog extends DialogComponentProvider implements KeyEntryListener { - private KeyEntryTextField kbField; + private KeyEntryPanel kbPanel; private KeyStroke ks; private boolean isCancelled; private Plugin plugin; @@ -39,15 +38,15 @@ class KeyBindingInputDialog extends DialogComponentProvider implements KeyEntryL super("Assign Script Key Binding", true, true, true, false); this.plugin = plugin; - kbField = new KeyEntryTextField(20, this); - kbField.setName("KEY_BINDING"); - kbField.setText( - currentKeyStroke == null ? "" : KeyBindingUtils.parseKeyStroke(currentKeyStroke)); + kbPanel = new KeyEntryPanel(20, this); + if (currentKeyStroke != null) { + kbPanel.setKeyStroke(currentKeyStroke); + } JPanel panel = new JPanel(new BorderLayout(10, 10)); panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); panel.add(new GLabel(scriptName), BorderLayout.NORTH); - panel.add(kbField, BorderLayout.CENTER); + panel.add(kbPanel, BorderLayout.CENTER); addWorkPanel(panel); addOKButton(); @@ -91,6 +90,6 @@ class KeyBindingInputDialog extends DialogComponentProvider implements KeyEntryL void setKeyStroke(KeyStroke ks) { this.ks = ks; - kbField.setKeyStroke(ks); + kbPanel.setKeyStroke(ks); } } diff --git a/Ghidra/Features/Base/src/test.slow/java/docking/action/KeyEntryDialogTest.java b/Ghidra/Features/Base/src/test.slow/java/docking/action/KeyEntryDialogTest.java index 40a644a351..f6d5bcbb78 100644 --- a/Ghidra/Features/Base/src/test.slow/java/docking/action/KeyEntryDialogTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/docking/action/KeyEntryDialogTest.java @@ -4,9 +4,9 @@ * 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. @@ -40,6 +40,7 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest { private KeyEntryDialog keyEntryDialog; private JTextPane collisionPane; private KeyEntryTextField keyEntryField; + private JButton clearButton; @Before public void setUp() throws Exception { @@ -71,7 +72,7 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest { // clear the action showDialog(unboundAction); - triggerBackspaceKey(keyEntryField); + pressButton(clearButton); pressDialogOK(); acceleratorKey = unboundAction.getKeyBinding(); @@ -98,7 +99,7 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest { showDialog(boundAction); assertEquals("OPEN_BRACKET", keyEntryField.getText()); - triggerBackspaceKey(keyEntryField); + pressButton(clearButton); pressDialogOK(); KeyStroke ks = boundAction.getKeyBinding(); @@ -113,7 +114,7 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest { KeyStroke oldKs = boundAction.getKeyBinding(); assertEquals("OPEN_BRACKET", keyEntryField.getText()); - triggerBackspaceKey(keyEntryField); + pressButton(clearButton); pressDialogOK(); KeyStroke ks = boundAction.getKeyBinding(); @@ -175,7 +176,7 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest { keyBindingKeyStroke.getKeyCode()); assertEquals(keyEntryDialog.getStatusText().trim(), ""); - triggerBackspaceKey(keyEntryField); + pressButton(clearButton); triggerText(keyEntryField, "g"); pressDialogOK(); @@ -259,6 +260,8 @@ public class KeyEntryDialogTest extends AbstractGhidraHeadedIntegrationTest { assertNotNull(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); } } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/GhidraScriptMgrPlugin3Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/GhidraScriptMgrPlugin3Test.java index 677ac3a1c7..7dfd5322ba 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/GhidraScriptMgrPlugin3Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/script/GhidraScriptMgrPlugin3Test.java @@ -4,9 +4,9 @@ * 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. @@ -49,7 +49,7 @@ public class GhidraScriptMgrPlugin3Test extends AbstractGhidraScriptMgrPluginTes KeyBindingInputDialog kbid = pressKeyBindingAction(); 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, KeyEvent.VK_H); pressButtonByText(kbid, "OK"); @@ -292,7 +292,8 @@ public class GhidraScriptMgrPlugin3Test extends AbstractGhidraScriptMgrPluginTes 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); assertTrue(listPanel.isVisible()); assertEquals(2, listPanel.getListModel().getSize()); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/ActionBindingPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/ActionBindingPanel.java index 5a4e398620..4cc64eca82 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/ActionBindingPanel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/ActionBindingPanel.java @@ -4,9 +4,9 @@ * 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. @@ -30,7 +30,7 @@ public class ActionBindingPanel extends JPanel { private static final String DISABLED_HINT = "Select an action"; - private KeyEntryTextField keyEntryField; + private KeyEntryPanel keyEntryPanel; private JCheckBox useMouseBindingCheckBox; private MouseEntryTextField mouseEntryField; private JPanel textFieldPanel; @@ -49,14 +49,14 @@ public class ActionBindingPanel extends JPanel { textFieldPanel = new JPanel(new BorderLayout()); - keyEntryField = new KeyEntryTextField(20, ks -> listener.keyStrokeChanged(ks)); - keyEntryField.setDisabledHint(DISABLED_HINT); - keyEntryField.setEnabled(false); // enabled on action selection + keyEntryPanel = new KeyEntryPanel(20, ks -> listener.keyStrokeChanged(ks)); + keyEntryPanel.setDisabledHint(DISABLED_HINT); + keyEntryPanel.setEnabled(false); // enabled on action selection mouseEntryField = new MouseEntryTextField(20, mb -> listener.mouseBindingChanged(mb)); mouseEntryField.setDisabledHint(DISABLED_HINT); mouseEntryField.setEnabled(false); // enabled on action selection - textFieldPanel.add(keyEntryField, BorderLayout.NORTH); + textFieldPanel.add(keyEntryPanel, BorderLayout.NORTH); String checkBoxText = "Enter Mouse Binding"; useMouseBindingCheckBox = new GCheckBox(checkBoxText); @@ -73,12 +73,12 @@ public class ActionBindingPanel extends JPanel { private void updateTextField() { if (useMouseBindingCheckBox.isSelected()) { - textFieldPanel.remove(keyEntryField); + textFieldPanel.remove(keyEntryPanel); textFieldPanel.add(mouseEntryField, BorderLayout.NORTH); } else { textFieldPanel.remove(mouseEntryField); - textFieldPanel.add(keyEntryField, BorderLayout.NORTH); + textFieldPanel.add(keyEntryPanel, BorderLayout.NORTH); } validate(); @@ -87,25 +87,25 @@ public class ActionBindingPanel extends JPanel { public void setKeyBindingData(KeyStroke ks, MouseBinding mb) { - keyEntryField.setKeyStroke(ks); + keyEntryPanel.setKeyStroke(ks); mouseEntryField.setMouseBinding(mb); } @Override public void setEnabled(boolean enabled) { - keyEntryField.clearField(); + keyEntryPanel.clearField(); mouseEntryField.clearField(); - keyEntryField.setEnabled(enabled); + keyEntryPanel.setEnabled(enabled); mouseEntryField.setEnabled(enabled); } public void clearKeyStroke() { - keyEntryField.clearField(); + keyEntryPanel.clearField(); } public KeyStroke getKeyStroke() { - return keyEntryField.getKeyStroke(); + return keyEntryPanel.getKeyStroke(); } public MouseBinding getMouseBinding() { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/KeyEntryPanel.java b/Ghidra/Framework/Docking/src/main/java/docking/KeyEntryPanel.java new file mode 100644 index 0000000000..e33fc5fdab --- /dev/null +++ b/Ghidra/Framework/Docking/src/main/java/docking/KeyEntryPanel.java @@ -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. + *

    + * 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(); + } +} diff --git a/Ghidra/Framework/Docking/src/main/java/docking/KeyEntryTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/KeyEntryTextField.java index 6388a26a22..3ff2f824e0 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/KeyEntryTextField.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/KeyEntryTextField.java @@ -4,9 +4,9 @@ * 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. @@ -82,9 +82,12 @@ public class KeyEntryTextField extends HintTextField { } public void clearField() { - ksName = null; + if (currentKeyStroke == null) { + return; + } + setText(""); - currentKeyStroke = null; + processKeyStroke(null, true); } private void processKeyStroke(KeyStroke ks, boolean notify) { @@ -128,17 +131,13 @@ public class KeyEntryTextField extends HintTextField { public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); KeyStroke keyStroke = null; - if (!isClearKey(keyCode) && !isModifiersOnly(e)) { + if (!isModifiersOnly(e)) { keyStroke = KeyStroke.getKeyStroke(keyCode, e.getModifiersEx()); } processKeyStroke(keyStroke, true); e.consume(); } - private boolean isClearKey(int keyCode) { - return keyCode == KeyEvent.VK_BACK_SPACE || keyCode == KeyEvent.VK_ENTER; - } - private boolean isModifiersOnly(KeyEvent event) { String keyText = KeyEvent.getKeyText(event.getKeyCode()); return keyText.equals(KeyEvent.getKeyText(KeyEvent.VK_CONTROL)) || diff --git a/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyEntryDialog.java b/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyEntryDialog.java index 822996c993..61c6acd5ca 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyEntryDialog.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/actions/KeyEntryDialog.java @@ -4,9 +4,9 @@ * 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. @@ -42,7 +42,7 @@ public class KeyEntryDialog extends DialogComponentProvider { private DockingActionIf action; private JPanel defaultPanel; - private KeyEntryTextField keyEntryField; + private KeyEntryPanel keyEntryPanel; private JTextPane collisionPane; private StyledDocument doc; @@ -83,8 +83,8 @@ public class KeyEntryDialog extends DialogComponentProvider { StyledDocument document = pane.getStyledDocument(); try { - document.insertString(0, "To add or change a key binding, type any key combination.\n" + - "To remove a key binding, press or .", null); + document.insertString(0, "To add or change a key binding, type any key combination", + null); } catch (BadLocationException e1) { // shouldn't be possible @@ -100,7 +100,7 @@ public class KeyEntryDialog extends DialogComponentProvider { labelPanel.add(pane); labelPanel.add(Box.createHorizontalStrut(5)); - keyEntryField = new KeyEntryTextField(20, keyStroke -> { + keyEntryPanel = new KeyEntryPanel(20, keyStroke -> { okButton.setEnabled(true); updateCollisionPane(keyStroke); }); @@ -109,12 +109,12 @@ public class KeyEntryDialog extends DialogComponentProvider { defaultPanel.setBorder(BorderFactory.createLoweredBevelBorder()); JPanel p = new JPanel(new FlowLayout(FlowLayout.CENTER)); p.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0)); - p.add(keyEntryField); + p.add(keyEntryPanel); KeyStroke keyBinding = action.getKeyBinding(); if (keyBinding != null) { - keyEntryField.setText(KeyBindingUtils.parseKeyStroke(keyBinding)); + keyEntryPanel.setKeyStroke(keyBinding); } - setFocusComponent(keyEntryField); + setFocusComponent(keyEntryPanel); defaultPanel.add(p, BorderLayout.CENTER); JPanel mainPanel = new JPanel(new BorderLayout()); @@ -144,7 +144,7 @@ public class KeyEntryDialog extends DialogComponentProvider { * @param ks the keystroke to set */ public void setKeyStroke(KeyStroke ks) { - keyEntryField.setKeyStroke(ks); + keyEntryPanel.setKeyStroke(ks); updateCollisionPane(ks); } @@ -155,7 +155,7 @@ public class KeyEntryDialog extends DialogComponentProvider { @Override protected void okCallback() { - KeyStroke newKs = keyEntryField.getKeyStroke(); + KeyStroke newKs = keyEntryPanel.getKeyStroke(); String errorMessage = toolActions.validateActionKeyBinding(action, newKs); if (errorMessage != null) { setStatusText(errorMessage); diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java index 01ed0957f2..39632c098c 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/plugintool/dialog/KeyBindingsPanel.java @@ -4,9 +4,9 @@ * 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. @@ -219,8 +219,7 @@ public class KeyBindingsPanel extends JPanel { // the content of the left-hand side label MultiLineLabel mlabel = new MultiLineLabel("To add or change a key binding, select an action\n" + - "and type any key combination\n \n" + - "To remove a key binding, select an action and\n" + "press or "); + "and type any key combination."); JPanel labelPanel = new JPanel(); labelPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 0)); BoxLayout bl = new BoxLayout(labelPanel, BoxLayout.X_AXIS);