From d3a0a56b8bc3091c730fc1e21ba1c62c0c651890 Mon Sep 17 00:00:00 2001 From: Skylot Date: Fri, 18 Feb 2022 18:00:14 +0000 Subject: [PATCH] feat(gui): ctrl+c copy highlighted word in code view (#1292) --- .../src/main/java/jadx/gui/ui/MainWindow.java | 7 +++- .../gui/ui/codearea/AbstractCodeArea.java | 38 ++++++++++++++++--- .../jadx/gui/ui/codearea/FridaAction.java | 8 +--- .../jadx/gui/ui/codearea/XposedAction.java | 8 +--- .../src/main/java/jadx/gui/utils/UiUtils.java | 18 +++++++++ 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java index 0b699fa1..21a6b38d 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java @@ -110,6 +110,7 @@ import jadx.gui.treemodel.JNode; import jadx.gui.treemodel.JPackage; import jadx.gui.treemodel.JResource; import jadx.gui.treemodel.JRoot; +import jadx.gui.ui.codearea.AbstractCodeArea; import jadx.gui.ui.codearea.AbstractCodeContentPanel; import jadx.gui.ui.codearea.EditorViewState; import jadx.gui.ui.dialog.ADBDialog; @@ -936,7 +937,11 @@ public class MainWindow extends JFrame { public void actionPerformed(ActionEvent e) { ContentPanel panel = tabbedPane.getSelectedCodePanel(); if (panel instanceof AbstractCodeContentPanel) { - String preferText = ((AbstractCodeContentPanel) panel).getCodeArea().getSelectedText(); + AbstractCodeArea codeArea = ((AbstractCodeContentPanel) panel).getCodeArea(); + String preferText = codeArea.getSelectedText(); + if (StringUtils.isEmpty(preferText)) { + preferText = codeArea.getWordUnderCaret(); + } if (!StringUtils.isEmpty(preferText)) { SearchDialog.searchText(MainWindow.this, preferText); return; diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java index 8a542eaf..e6bd7998 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/AbstractCodeArea.java @@ -6,6 +6,8 @@ import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -37,6 +39,7 @@ import jadx.gui.ui.panel.ContentPanel; import jadx.gui.utils.DefaultPopupMenuListener; import jadx.gui.utils.JumpPosition; import jadx.gui.utils.NLS; +import jadx.gui.utils.UiUtils; public abstract class AbstractCodeArea extends RSyntaxTextArea { private static final long serialVersionUID = -3980354865216031972L; @@ -57,9 +60,16 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea { setCloseCurlyBraces(true); setAntiAliasingEnabled(true); loadSettings(); + JadxSettings settings = contentPanel.getTabbedPane().getMainWindow().getSettings(); setLineWrap(settings.isCodeAreaLineWrap()); + addWrapLineMenuAction(settings); + + addCaretActions(); + addFastCopyAction(); + } + private void addWrapLineMenuAction(JadxSettings settings) { JPopupMenu popupMenu = getPopupMenu(); popupMenu.addSeparator(); JCheckBoxMenuItem wrapItem = new JCheckBoxMenuItem(NLS.str("popup.line_wrap"), getLineWrap()); @@ -88,7 +98,16 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea { wrapItem.setState(getLineWrap()); } }); + } + + private void setCodeAreaLineWrap(AbstractCodeArea codeArea, boolean wrap) { + codeArea.setLineWrap(wrap); + if (codeArea.isVisible()) { + codeArea.repaint(); + } + } + private void addCaretActions() { Caret caret = getCaret(); if (caret instanceof DefaultCaret) { ((DefaultCaret) caret).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); @@ -123,11 +142,20 @@ public abstract class AbstractCodeArea extends RSyntaxTextArea { }); } - private void setCodeAreaLineWrap(AbstractCodeArea codeArea, boolean wrap) { - codeArea.setLineWrap(wrap); - if (codeArea.isVisible()) { - codeArea.repaint(); - } + /** + * Ctrl+C will copy highlighted word + */ + private void addFastCopyAction() { + addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_C && UiUtils.isCtrlDown(e)) { + if (StringUtils.isEmpty(getSelectedText())) { + UiUtils.copyToClipboard(getWordUnderCaret()); + } + } + } + }); } private String highlightCaretWord(String lastText, int pos) { diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/FridaAction.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/FridaAction.java index e318adca..fac5c2dc 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/FridaAction.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/FridaAction.java @@ -1,8 +1,5 @@ package jadx.gui.ui.codearea; -import java.awt.Toolkit; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.*; @@ -29,6 +26,7 @@ import jadx.gui.treemodel.JField; import jadx.gui.treemodel.JMethod; import jadx.gui.treemodel.JNode; import jadx.gui.utils.NLS; +import jadx.gui.utils.UiUtils; import static javax.swing.KeyStroke.getKeyStroke; @@ -62,9 +60,7 @@ public final class FridaAction extends JNodeMenuAction { try { String fridaSnippet = generateFridaSnippet(); LOG.info("Frida snippet:\n{}", fridaSnippet); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - StringSelection selection = new StringSelection(fridaSnippet); - clipboard.setContents(selection, selection); + UiUtils.copyToClipboard(fridaSnippet); } catch (Exception e) { LOG.error("Failed to generate Frida code snippet", e); JOptionPane.showMessageDialog(codeArea.getMainWindow(), e.getLocalizedMessage(), NLS.str("error_dialog.title"), diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/XposedAction.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/XposedAction.java index d102a1bc..f98d4948 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/XposedAction.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/XposedAction.java @@ -1,8 +1,5 @@ package jadx.gui.ui.codearea; -import java.awt.Toolkit; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.List; @@ -25,6 +22,7 @@ import jadx.gui.treemodel.JClass; import jadx.gui.treemodel.JMethod; import jadx.gui.treemodel.JNode; import jadx.gui.utils.NLS; +import jadx.gui.utils.UiUtils; import static javax.swing.KeyStroke.getKeyStroke; @@ -55,9 +53,7 @@ public class XposedAction extends JNodeMenuAction { try { String xposedSnippet = generateXposedSnippet(); LOG.info("Xposed snippet:\n{}", xposedSnippet); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - StringSelection selection = new StringSelection(xposedSnippet); - clipboard.setContents(selection, selection); + UiUtils.copyToClipboard(xposedSnippet); } catch (Exception e) { LOG.error("Failed to generate Xposed code snippet", e); JOptionPane.showMessageDialog(codeArea.getMainWindow(), e.getLocalizedMessage(), NLS.str("error_dialog.title"), diff --git a/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java b/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java index 1e93c9f2..083ea984 100644 --- a/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java +++ b/jadx-gui/src/main/java/jadx/gui/utils/UiUtils.java @@ -32,6 +32,7 @@ import com.formdev.flatlaf.extras.FlatSVGIcon; import jadx.core.dex.info.AccessInfo; import jadx.core.dex.instructions.args.ArgType; +import jadx.core.utils.StringUtils; import jadx.core.utils.Utils; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.gui.ui.codearea.AbstractCodeArea; @@ -253,6 +254,10 @@ public class UiUtils { return CTRL_BNT_KEY; } + public static boolean isCtrlDown(KeyEvent keyEvent) { + return keyEvent.getModifiersEx() == CTRL_BNT_KEY; + } + public static void addEscapeShortCutToDispose(T window) { KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); window.getRootPane().registerKeyboardAction(e -> window.dispose(), stroke, JComponent.WHEN_IN_FOCUSED_WINDOW); @@ -296,4 +301,17 @@ public class UiUtils { JOptionPane.showMessageDialog(parent, message, NLS.str("message.errorTitle"), JOptionPane.ERROR_MESSAGE); } + + public static void copyToClipboard(String text) { + if (StringUtils.isEmpty(text)) { + return; + } + try { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + StringSelection selection = new StringSelection(text); + clipboard.setContents(selection, selection); + } catch (Exception e) { + LOG.error("Failed copy text to clipboard", e); + } + } } -- GitLab