-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* feat(gui): allow user to customize shortcuts * internal: fixed other constructor for jadx action * make code area actions customizable * show warning dialog when mouse button is commonly used * applied code formatting * code formatting and and moved string to resources * moved action related classes to their own package * added fix for actions with modifiers in macos * ignore left click in shortcut edit * applied code formatting * warn user when a duplicate shortcut is entered * save shortcut when key is pressed (instead of typed) * fix node under mouse being ignored Co-authored-by: skylot <118523+skylot@users.noreply.github.com> * add missing import * applied code formatting * added custom shortcuts support to script content panel * save shortcut when key is released (instead of pressed) * enable custom shortcut in script autocomplete * fix duplicate shortcut warning when the shortcut is set again at the same action * fixed mouse buttons shortcut not working for code area * fix exception with mouse button shortcuts * fix action getting fired twice * added variants for forward and back nav actions * fix exception when shortcut is not saved * fix mouse button shortcut for auto complete action * consume mouse event if bound to an action * workaround not being able to extend HashMap * fix exception in script code area when using mouse button shortcut * minor pref serialiazation improvement * fix action buttons not working (like run action) * fix exception with plugin actinos * fixed nullptr when adding an action with null actionmodel to jadxmenu * fix plugin action name not showing --------- Co-authored-by: skylot <118523+skylot@users.noreply.github.com>
- Loading branch information
1 parent
868e99e
commit 68b84ea
Showing
40 changed files
with
1,433 additions
and
399 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
jadx-gui/src/main/java/jadx/gui/settings/data/ShortcutsWrapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package jadx.gui.settings.data; | ||
|
||
import java.util.Map; | ||
|
||
import jadx.gui.ui.action.ActionModel; | ||
import jadx.gui.utils.shortcut.Shortcut; | ||
|
||
public class ShortcutsWrapper { | ||
private Map<ActionModel, Shortcut> shortcuts; | ||
|
||
public void updateShortcuts(Map<ActionModel, Shortcut> shortcuts) { | ||
this.shortcuts = shortcuts; | ||
} | ||
|
||
public Shortcut get(ActionModel actionModel) { | ||
return shortcuts.getOrDefault(actionModel, actionModel.getDefaultShortcut()); | ||
} | ||
|
||
public void put(ActionModel actionModel, Shortcut shortcut) { | ||
shortcuts.put(actionModel, shortcut); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
193 changes: 193 additions & 0 deletions
193
jadx-gui/src/main/java/jadx/gui/settings/ui/shortcut/ShortcutEdit.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
package jadx.gui.settings.ui.shortcut; | ||
|
||
import java.awt.AWTEvent; | ||
import java.awt.KeyboardFocusManager; | ||
import java.awt.Toolkit; | ||
import java.awt.event.FocusEvent; | ||
import java.awt.event.FocusListener; | ||
import java.awt.event.KeyEvent; | ||
import java.awt.event.MouseEvent; | ||
|
||
import javax.swing.BoxLayout; | ||
import javax.swing.Icon; | ||
import javax.swing.JButton; | ||
import javax.swing.JOptionPane; | ||
import javax.swing.JPanel; | ||
import javax.swing.JTextField; | ||
import javax.swing.UIManager; | ||
|
||
import jadx.gui.settings.JadxSettings; | ||
import jadx.gui.settings.ui.JadxSettingsWindow; | ||
import jadx.gui.ui.action.ActionModel; | ||
import jadx.gui.utils.NLS; | ||
import jadx.gui.utils.UiUtils; | ||
import jadx.gui.utils.shortcut.Shortcut; | ||
|
||
public class ShortcutEdit extends JPanel { | ||
private static final Icon CLEAR_ICON = UiUtils.openSvgIcon("ui/close"); | ||
|
||
private final ActionModel actionModel; | ||
private final JadxSettingsWindow settingsWindow; | ||
private final JadxSettings settings; | ||
private final TextField textField; | ||
|
||
public Shortcut shortcut; | ||
|
||
public ShortcutEdit(ActionModel actionModel, JadxSettingsWindow settingsWindow, JadxSettings settings) { | ||
this.actionModel = actionModel; | ||
this.settings = settings; | ||
this.settingsWindow = settingsWindow; | ||
|
||
textField = new TextField(); | ||
JButton clearButton = new JButton(CLEAR_ICON); | ||
|
||
setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); | ||
add(textField); | ||
add(clearButton); | ||
|
||
clearButton.addActionListener(e -> { | ||
setShortcut(Shortcut.none()); | ||
saveShortcut(); | ||
}); | ||
} | ||
|
||
public void setShortcut(Shortcut shortcut) { | ||
this.shortcut = shortcut; | ||
textField.reload(); | ||
} | ||
|
||
private void saveShortcut() { | ||
settings.getShortcuts().put(actionModel, shortcut); | ||
settingsWindow.needReload(); | ||
} | ||
|
||
private boolean verifyShortcut(Shortcut shortcut) { | ||
ActionModel otherAction = null; | ||
for (ActionModel a : ActionModel.values()) { | ||
if (actionModel != a && shortcut.equals(settings.getShortcuts().get(a))) { | ||
otherAction = a; | ||
break; | ||
} | ||
} | ||
|
||
if (otherAction != null) { | ||
int dialogResult = JOptionPane.showConfirmDialog( | ||
this, | ||
NLS.str("msg.duplicate_shortcut", | ||
shortcut, | ||
otherAction.getName(), | ||
otherAction.getCategory().getName()), | ||
NLS.str("msg.warning_title"), | ||
JOptionPane.YES_NO_OPTION); | ||
if (dialogResult != 0) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
private class TextField extends JTextField { | ||
private Shortcut tempShortcut; | ||
|
||
public TextField() { | ||
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(ev -> { | ||
if (!isListening()) { | ||
return false; | ||
} | ||
|
||
if (ev.getID() == KeyEvent.KEY_PRESSED) { | ||
Shortcut pressedShortcut = Shortcut.keyboard(ev.getKeyCode(), ev.getModifiersEx()); | ||
if (pressedShortcut.isValidKeyboard()) { | ||
tempShortcut = pressedShortcut; | ||
refresh(tempShortcut); | ||
} else { | ||
tempShortcut = null; | ||
} | ||
} else if (ev.getID() == KeyEvent.KEY_RELEASED) { | ||
removeFocus(); | ||
} | ||
ev.consume(); | ||
return true; | ||
}); | ||
|
||
addFocusListener(new FocusListener() { | ||
@Override | ||
public void focusGained(FocusEvent ev) { | ||
} | ||
|
||
@Override | ||
public void focusLost(FocusEvent ev) { | ||
if (tempShortcut != null) { | ||
if (verifyShortcut(tempShortcut)) { | ||
shortcut = tempShortcut; | ||
saveShortcut(); | ||
} else { | ||
reload(); | ||
} | ||
tempShortcut = null; | ||
} | ||
} | ||
}); | ||
|
||
Toolkit.getDefaultToolkit().addAWTEventListener(event -> { | ||
if (!isListening()) { | ||
return; | ||
} | ||
|
||
if (event instanceof MouseEvent) { | ||
MouseEvent mouseEvent = (MouseEvent) event; | ||
if (mouseEvent.getID() == MouseEvent.MOUSE_PRESSED) { | ||
int mouseButton = mouseEvent.getButton(); | ||
|
||
if (mouseButton <= MouseEvent.BUTTON1) { | ||
return; | ||
} | ||
|
||
if (mouseButton <= MouseEvent.BUTTON3) { | ||
int dialogResult = JOptionPane.showConfirmDialog( | ||
this, | ||
NLS.str("msg.common_mouse_shortcut"), | ||
NLS.str("msg.warning_title"), | ||
JOptionPane.YES_NO_OPTION); | ||
if (dialogResult != 0) { | ||
((MouseEvent) event).consume(); | ||
tempShortcut = null; | ||
removeFocus(); | ||
return; | ||
} | ||
} | ||
|
||
((MouseEvent) event).consume(); | ||
tempShortcut = Shortcut.mouse(mouseButton); | ||
refresh(tempShortcut); | ||
removeFocus(); | ||
} | ||
} | ||
}, AWTEvent.MOUSE_EVENT_MASK); | ||
} | ||
|
||
public void reload() { | ||
refresh(shortcut); | ||
} | ||
|
||
private void refresh(Shortcut displayedShortcut) { | ||
if (displayedShortcut == null || displayedShortcut.isNone()) { | ||
setText("None"); | ||
setForeground(UIManager.getColor("TextArea.inactiveForeground")); | ||
return; | ||
} | ||
setText(displayedShortcut.toString()); | ||
setForeground(UIManager.getColor("TextArea.foreground")); | ||
} | ||
|
||
private void removeFocus() { | ||
// triggers focusLost | ||
getRootPane().requestFocus(); | ||
} | ||
|
||
private boolean isListening() { | ||
return isFocusOwner(); | ||
} | ||
} | ||
} |
Oops, something went wrong.