GP-5007 - Update key bindings to allow users to use Enter and Escape

This commit is contained in:
dragonmacher 2024-10-10 15:58:39 -04:00
parent 9108198ba7
commit 44707fd7dc
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>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>
button.</LI>
</OL>
</BLOCKQUOTE><!-- Import/Export Key Bindings --><A name="Import"></A>
</BLOCKQUOTE>
<!-- Import/Export Key Bindings -->
<A name="Import"></A>
<H3>Import Key Bindings</H3>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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());

View File

@ -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() {

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

@ -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)) ||

View File

@ -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 <Enter> or <Backspace>.", 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);

View File

@ -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 <Enter> or <Backspace>");
"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);