feat(gui): 重构 FridaWindow 界面并添加新功能- 重新设计了 FridaWindow 的布局和样式,增加了菜单栏和更多控件

- 添加了进程列表和搜索功能,支持双击注入进程
- 实现了暗黑主题和自定义样式,提升了用户体验
- 优化了代码结构,增加了可读性和可维护性
This commit is contained in:
tzdwindows 7
2025-03-01 19:51:57 +08:00
parent f4baf0b1e4
commit b06c8fd4e7
5 changed files with 286 additions and 121 deletions

View File

@@ -31,7 +31,7 @@ repositories {
} }
} }
maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
// mavenCentral() mavenCentral()
} }
dependencies { dependencies {
@@ -69,11 +69,12 @@ dependencies {
implementation 'org.bitbucket.mstrobel:procyon-compilertools:0.5.36' implementation 'org.bitbucket.mstrobel:procyon-compilertools:0.5.36'
// 必须的核心依赖 // 必须的核心依赖
implementation 'com.fifesoft:rsyntaxtextarea:3.3.1' implementation 'com.fifesoft:rsyntaxtextarea:3.5.4'
implementation 'com.fifesoft:autocomplete:3.3.1'
// 可选UI增强 // 可选UI增强
implementation 'com.fifesoft:rstaui:3.3.1' implementation 'com.fifesoft:rstaui:3.3.1'
implementation 'com.fifesoft:languagesupport:3.3.0'
implementation 'com.fifesoft:autocomplete:3.3.2'
implementation 'org.apache.commons:commons-compress:1.23.0' implementation 'org.apache.commons:commons-compress:1.23.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'

View File

@@ -252,6 +252,12 @@ public class AxisInnovatorsBox {
*/ */
private void setTopic() { private void setTopic() {
try { try {
main.registrationTopic.addTopic(new com.formdev.flatlaf.FlatDarculaLaf(),
"Darcula主题",
"Darcula主题",
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:darcula_theme");
main.registrationTopic.addTopic(UIManager.getSystemLookAndFeelClassName(), main.registrationTopic.addTopic(UIManager.getSystemLookAndFeelClassName(),
LanguageManager.getLoadedLanguages().getText("default_theme.system.topicName"), LanguageManager.getLoadedLanguages().getText("default_theme.system.topicName"),
LanguageManager.getLoadedLanguages().getText("default_theme.default.tip"), LanguageManager.getLoadedLanguages().getText("default_theme.default.tip"),
@@ -277,13 +283,7 @@ public class AxisInnovatorsBox {
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64), LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:flatLightLaf_theme"); "system:flatLightLaf_theme");
main.registrationTopic.addTopic(new com.formdev.flatlaf.FlatDarculaLaf(), UIManager.setLookAndFeel(new com.formdev.flatlaf.FlatDarculaLaf());
"Darcula主题",
"Darcula主题",
LoadIcon.loadIcon(MainWindow.class, "logo.png", 64),
"system:darcula_theme");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) { } catch (Exception e) {
logger.warn("Failed to load the system facade class", e); logger.warn("Failed to load the system facade class", e);
} }

View File

@@ -229,7 +229,7 @@ public class FridaSyntax {
public static void addBasicCompletions(DefaultCompletionProvider provider) { public static void addBasicCompletions(DefaultCompletionProvider provider) {
String[] jsKeywords = {"function", "var", "let", "const", "if", "else", String[] jsKeywords = {"function", "var", "let", "const", "if", "else",
"for", "while(/* logic */)", "try", "catch", "true", "false","()", "for (int i = 0; i < ; i++) {\n" + "for", "while(/* logic */)", "try", "catch", "true", "false","()", "for (var i = 0; i < ; i++) {\n" +
" \n" + " \n" +
"}"}; "}"};

View File

@@ -3,7 +3,12 @@ package com.axis.innovators.box.gui;
import com.axis.innovators.box.gui.renderer.DarculaCompletionCellRenderer; import com.axis.innovators.box.gui.renderer.DarculaCompletionCellRenderer;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.fife.rsta.ac.LanguageSupport;
import org.fife.rsta.ac.LanguageSupportFactory;
import org.fife.rsta.ac.perl.PerlLanguageSupport;
import org.fife.ui.autocomplete.*; import org.fife.ui.autocomplete.*;
import org.fife.ui.rsyntaxtextarea.folding.CurlyFoldParser;
import org.fife.ui.rsyntaxtextarea.folding.FoldParserManager;
import org.tzd.frida.windows.Frida; import org.tzd.frida.windows.Frida;
import org.fife.ui.rsyntaxtextarea.*; import org.fife.ui.rsyntaxtextarea.*;
@@ -11,14 +16,12 @@ import org.fife.ui.rtextarea.RTextScrollPane;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EmptyBorder; import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent; import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel; import javax.swing.table.DefaultTableModel;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -32,12 +35,11 @@ public class FridaWindow extends WindowsJDialog {
private static final Logger logger = LogManager.getLogger(FridaWindow.class); private static final Logger logger = LogManager.getLogger(FridaWindow.class);
private RSyntaxTextArea scriptArea; private RSyntaxTextArea scriptArea;
private JTextArea logArea; private JTextArea logArea;
private JTextField pidField;
private boolean isRepetition = false; private boolean isRepetition = false;
private JComboBox<ProcessInfo> processCombo;
private JTextField pidField;
// IDEA风格配色 // IDEA风格配色
private static final Color BACKGROUND = new Color(0x2B2B2B); private static final Color BACKGROUND = new Color(0x2B2B2B);
private static final Color FOREGROUND = new Color(0xBBBBBB);
private static final Color SELECTION_COLOR = new Color(0x214283); private static final Color SELECTION_COLOR = new Color(0x214283);
public FridaWindow(Window owner) { public FridaWindow(Window owner) {
@@ -45,6 +47,14 @@ public class FridaWindow extends WindowsJDialog {
initUI(); initUI();
} }
static {
Font chineseFont = new Font("Microsoft YaHei", Font.PLAIN, 13);
UIManager.put("Menu.font", chineseFont);
UIManager.put("MenuItem.font", chineseFont);
UIManager.put("Button.font", chineseFont);
UIManager.put("ComboBox.font", chineseFont);
}
@Override @Override
public void initUI() { public void initUI() {
super.initUI(); super.initUI();
@@ -56,6 +66,10 @@ public class FridaWindow extends WindowsJDialog {
mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); mainPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
mainPanel.setBackground(BACKGROUND); mainPanel.setBackground(BACKGROUND);
pidField = new JTextField();
styleTextField(pidField, "输入PID或进程名");
mainPanel.add(pidField, BorderLayout.CENTER);
// 输入面板 // 输入面板
JPanel inputPanel = createInputPanel(); JPanel inputPanel = createInputPanel();
mainPanel.add(inputPanel, BorderLayout.NORTH); mainPanel.add(inputPanel, BorderLayout.NORTH);
@@ -74,7 +88,7 @@ public class FridaWindow extends WindowsJDialog {
centerSplit.setBottomComponent(logPanel); centerSplit.setBottomComponent(logPanel);
mainPanel.add(centerSplit, BorderLayout.CENTER); mainPanel.add(centerSplit, BorderLayout.CENTER);
createMenuBar();
setContentPane(mainPanel); setContentPane(mainPanel);
addWindowListener(new WindowAdapter() { addWindowListener(new WindowAdapter() {
@@ -85,41 +99,186 @@ public class FridaWindow extends WindowsJDialog {
}); });
} }
private void styleTextField(JTextField field, String placeholder) {
field.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
field.setBackground(new Color(0x3C3F41));
field.setForeground(Color.WHITE);
field.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(0x515658)),
BorderFactory.createEmptyBorder(5, 8, 5, 8)
));
field.putClientProperty("JTextField.placeholderText", placeholder);
}
private JPanel createInputPanel() { private JPanel createInputPanel() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5)); JPanel panel = new JPanel(new BorderLayout(10, 0));
panel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
panel.setOpaque(false); panel.setOpaque(false);
pidField = new JTextField(20); // 进程组合框
styleTextField(pidField, "输入进程ID或选择进程..."); processCombo = new JComboBox<>();
styleComboBox(processCombo);
JButton browseButton = new JButton("选择进程"); // 操作工具栏
styleButton(browseButton, new Color(65, 131, 215)); JPanel controlPanel = new JPanel(new GridLayout(1, 2, 8, 0));
browseButton.addActionListener(this::openProcessSelectionWindow); controlPanel.setOpaque(false);
JButton injectButton = new JButton("注入脚本"); JButton injectBtn = createModernButton(language.getText("fridaWindow.button.inject"), 0x6897BB);
styleButton(injectButton, new Color(215, 65, 65)); JButton stopBtn = createModernButton(language.getText("fridaWindow.button.inject.pid"), 0xD25252);
injectButton.addActionListener(this::handleInject);
panel.add(new JLabel("目标进程:")); injectBtn.addActionListener(this::handleInject);
panel.add(pidField); stopBtn.addActionListener(this::openProcessSelectionWindow);
panel.add(browseButton);
panel.add(injectButton); controlPanel.add(injectBtn);
controlPanel.add(stopBtn);
panel.add(processCombo, BorderLayout.CENTER);
panel.add(controlPanel, BorderLayout.EAST);
return panel; return panel;
} }
private JButton createModernButton(String text, int color) {
JButton btn = new JButton(text);
btn.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
btn.setFocusPainted(false);
btn.setBackground(new Color(color));
btn.setForeground(Color.WHITE);
btn.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(color).darker(), 1),
BorderFactory.createEmptyBorder(6, 15, 6, 15)
));
// 悬停效果
btn.addMouseListener(new MouseAdapter() {
public void mouseEntered(MouseEvent e) {
btn.setBackground(new Color(color).brighter());
}
public void mouseExited(MouseEvent e) {
btn.setBackground(new Color(color));
}
});
return btn;
}
private void styleComboBox(JComboBox<?> combo) {
combo.setRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
setBackground(isSelected ? new Color(0x214283) : new Color(0x3C3F41));
setForeground(Color.WHITE);
return this;
}
});
}
private void createMenuBar() {
JMenuBar menuBar = new JMenuBar();
// 菜单栏深色背景
menuBar.setBackground(new Color(0x3C3F41));
menuBar.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0));
// 统一设置菜单UI属性
UIManager.put("Menu.background", new Color(0x3C3F41));
UIManager.put("Menu.foreground", new Color(0xBBBBBB));
UIManager.put("MenuItem.background", new Color(0x3C3F41));
UIManager.put("MenuItem.foreground", new Color(0xBBBBBB));
UIManager.put("MenuItem.selectionBackground", new Color(0x214283));
// 文件菜单
JMenu fileMenu = new JMenu(language.getText("fridaWindow.menu"));
styleMenu(fileMenu);
// 退出菜单项
JMenuItem exitItem = new JMenuItem(language.getText("fridaWindow.menu.exit"));
styleMenuItem(exitItem);
exitItem.addActionListener(e -> dispose());
// 帮助菜单
JMenu helpMenu = new JMenu(language.getText("fridaWindow.menu.help"));
styleMenu(helpMenu);
// 关于菜单项
JMenuItem aboutItem = new JMenuItem(language.getText("fridaWindow.menu.help.about"));
styleMenuItem(aboutItem);
aboutItem.addActionListener(e -> showAboutDialog());
menuBar.add(fileMenu);
menuBar.add(helpMenu);
setJMenuBar(menuBar);
}
private void styleMenu(JMenu menu) {
menu.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
menu.setForeground(new Color(0xBBBBBB));
menu.setBorder(BorderFactory.createEmptyBorder(5, 8, 5, 8));
menu.setOpaque(true);
menu.setBackground(new Color(0x3C3F41));
}
private void styleMenuItem(JMenuItem item) {
item.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
item.setForeground(new Color(0xBBBBBB));
item.setBackground(new Color(0x3C3F41));
item.setBorder(BorderFactory.createEmptyBorder(5, 20, 5, 10)); // 增加左侧间距
item.setOpaque(true);
// 鼠标悬停效果
item.addMouseListener(new MouseAdapter() {
public void mouseEntered(MouseEvent e) {
item.setBackground(new Color(0x515658));
}
public void mouseExited(MouseEvent e) {
item.setBackground(new Color(0x3C3F41));
}
});
}
private void showAboutDialog() {
JDialog aboutDialog = new JDialog(this, "关于", true);
aboutDialog.setSize(300, 200);
aboutDialog.setLocationRelativeTo(this);
JPanel content = new JPanel(new BorderLayout());
content.setBorder(new EmptyBorder(20, 20, 20, 20));
JLabel title = new JLabel("Frida Injector v2.0");
title.setFont(new Font("Segoe UI", Font.BOLD, 16));
JTextArea info = new JTextArea("基于Frida的现代注入工具\n\nCopyright ? 2024");
info.setEditable(false);
content.add(title, BorderLayout.NORTH);
content.add(info, BorderLayout.CENTER);
aboutDialog.setContentPane(content);
aboutDialog.setVisible(true);
}
private JPanel createScriptPanel() { private JPanel createScriptPanel() {
JPanel panel = new JPanel(new BorderLayout()); JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createTitledBorder("Frida脚本编辑器")); panel.setBorder(BorderFactory.createTitledBorder("Frida脚本编辑器"));
scriptArea = new RSyntaxTextArea(); scriptArea = new RSyntaxTextArea();
scriptArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); LanguageSupportFactory lsf = LanguageSupportFactory.get();
LanguageSupport support = lsf.
getSupportFor(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
support.install(scriptArea);
scriptArea.setCodeFoldingEnabled(true); scriptArea.setCodeFoldingEnabled(true);
FoldParserManager.get().addFoldParserMapping("text/javascript", new CurlyFoldParser());
scriptArea.setFractionalFontMetricsEnabled(true);
scriptArea.setAutoIndentEnabled(true);
scriptArea.setCodeFoldingEnabled(true);
scriptArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT);
scriptArea.setAntiAliasingEnabled(true); scriptArea.setAntiAliasingEnabled(true);
scriptArea.setTabSize(4); scriptArea.setTabSize(4);
scriptArea.setCaretPosition(0); scriptArea.setCaretPosition(0);
scriptArea.setSelectionColor(SELECTION_COLOR); scriptArea.setSelectionColor(SELECTION_COLOR);
scriptArea.setCurrentLineHighlightColor(new Color(0x323232));
scriptArea.setMarkOccurrences(true); scriptArea.setMarkOccurrences(true);
scriptArea.setBracketMatchingEnabled(true); scriptArea.setBracketMatchingEnabled(true);
setupAutoCompletion(); setupAutoCompletion();
@@ -131,7 +290,6 @@ public class FridaWindow extends WindowsJDialog {
scriptArea.setFont(ideaFont); scriptArea.setFont(ideaFont);
scriptArea.setBackground(new Color(0x1E1F22)); scriptArea.setBackground(new Color(0x1E1F22));
//codeArea.setForeground(new Color(0xBBBBBB));
scriptArea.setSelectionColor(new Color(0x214283)); scriptArea.setSelectionColor(new Color(0x214283));
scriptArea.setCurrentLineHighlightColor(new Color(0x323232)); scriptArea.setCurrentLineHighlightColor(new Color(0x323232));
@@ -158,6 +316,11 @@ public class FridaWindow extends WindowsJDialog {
defaultStyle.foreground = foreground; defaultStyle.foreground = foreground;
defaultStyle.background = background; defaultStyle.background = background;
// ======== JavaScript 标准库配置 ========
// console 相关 API
setTokenStyle(scheme, Token.RESERVED_WORD_2, 0xCC7832); // 橙色
setTokenStyle(scheme, Token.FUNCTION, 0xFFC66D); // 黄色
// ======== Frida 关键字和 API 配置 ======== // ======== Frida 关键字和 API 配置 ========
// Frida 关键字(如 Java.perform, Interceptor.attach 等) // Frida 关键字(如 Java.perform, Interceptor.attach 等)
setTokenStyle(scheme, Token.RESERVED_WORD, 0xCC7832); // 橙色 setTokenStyle(scheme, Token.RESERVED_WORD, 0xCC7832); // 橙色
@@ -188,16 +351,6 @@ public class FridaWindow extends WindowsJDialog {
// 正则表达式 // 正则表达式
setTokenStyle(scheme, Token.REGEX, 0xD25252); // 红色 setTokenStyle(scheme, Token.REGEX, 0xD25252); // 红色
// ======== Frida 特有 API 配置 ========
// Java 相关 API
setTokenStyle(scheme, Token.RESERVED_WORD_2, 0xCC7832); // 橙色
// 内存操作 API
setTokenStyle(scheme, Token.DATA_TYPE, 0xE8BF6A); // 浅黄色
// 拦截器相关 API
setTokenStyle(scheme, Token.ANNOTATION, 0xBBB529); // 黄色
// ======== 跨语言通用配置 ======== // ======== 跨语言通用配置 ========
// XML/HTML 标签(如果有需要) // XML/HTML 标签(如果有需要)
setTokenStyle(scheme, Token.MARKUP_TAG_NAME, 0xE8BF6A); // 浅黄色 setTokenStyle(scheme, Token.MARKUP_TAG_NAME, 0xE8BF6A); // 浅黄色
@@ -211,6 +364,7 @@ public class FridaWindow extends WindowsJDialog {
return scheme; return scheme;
} }
private void setTokenStyle(SyntaxScheme scheme, int tokenType, int rgb) { private void setTokenStyle(SyntaxScheme scheme, int tokenType, int rgb) {
Style style = scheme.getStyle(tokenType); Style style = scheme.getStyle(tokenType);
style.foreground = new Color(rgb); style.foreground = new Color(rgb);
@@ -238,7 +392,6 @@ public class FridaWindow extends WindowsJDialog {
CompletionProvider provider = createCompletionProvider(); CompletionProvider provider = createCompletionProvider();
AutoCompletion ac = new AutoCompletion(provider); AutoCompletion ac = new AutoCompletion(provider);
// 关键配置
ac.setAutoActivationEnabled(true); ac.setAutoActivationEnabled(true);
ac.setParameterAssistanceEnabled(true); ac.setParameterAssistanceEnabled(true);
ac.setShowDescWindow(true); ac.setShowDescWindow(true);
@@ -246,7 +399,6 @@ public class FridaWindow extends WindowsJDialog {
ac.install(scriptArea); ac.install(scriptArea);
ac.setDescriptionWindowColor(new Color(0x323232)); ac.setDescriptionWindowColor(new Color(0x323232));
//ac.setChoicesWindowSize(386,200);
scriptArea.addKeyListener(new KeyAdapter() { scriptArea.addKeyListener(new KeyAdapter() {
@Override @Override
public void keyTyped(KeyEvent e) { public void keyTyped(KeyEvent e) {
@@ -268,33 +420,10 @@ public class FridaWindow extends WindowsJDialog {
return provider; return provider;
} }
private void styleTextField(JTextField field, String placeholder) {
field.setFont(new Font("JetBrains Mono", Font.PLAIN, 14));
field.setBackground(new Color(0x3C3F41));
field.setForeground(Color.WHITE);
field.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(0x515658)),
BorderFactory.createEmptyBorder(5, 8, 5, 8)
));
field.putClientProperty("JTextField.placeholderText", placeholder);
}
private void styleButton(JButton button, Color bgColor) {
button.setFont(new Font("Segoe UI", Font.PLAIN, 13));
button.setFocusPainted(false);
button.setBackground(bgColor);
button.setForeground(Color.WHITE);
button.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(bgColor.darker()),
BorderFactory.createEmptyBorder(5, 15, 5, 15)
));
}
private void handleInject(ActionEvent e) { private void handleInject(ActionEvent e) {
try { try {
long pid = Long.parseLong(pidField.getText()); long pid = Long.parseLong(pidField.getText());
String script = scriptArea.getText(); String script = scriptArea.getText();
Frida frida = new Frida(script, pid); Frida frida = new Frida(script, pid);
if (!isRepetition) { if (!isRepetition) {
try { try {
@@ -341,67 +470,93 @@ public class FridaWindow extends WindowsJDialog {
} }
private void initializeUI() { private void initializeUI() {
JPanel panel = new JPanel(); JPanel panel = new JPanel(new BorderLayout(5, 5));
panel.setLayout(new BorderLayout()); panel.setBorder(new EmptyBorder(10, 10, 10, 10));
panel.setBackground(new Color(0x2B2B2B));
// 获取所有进程信息 JTextField searchField = new JTextField(20);
processList = getProcesses(); styleSearchField(searchField);
// 创建搜索框 table = new JTable();
JPanel searchPanel = new JPanel(); table.setModel(createTableModel());
searchPanel.setLayout(new BorderLayout()); styleTable(table);
JTextField searchField = new JTextField();
searchField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
filterProcesses(searchField.getText());
}
@Override
public void removeUpdate(DocumentEvent e) {
filterProcesses(searchField.getText());
}
@Override
public void changedUpdate(DocumentEvent e) {
filterProcesses(searchField.getText());
}
});
searchPanel.add(new JLabel(language.getText("fridaWindow.processSelectionWindow.search")), BorderLayout.WEST);
searchPanel.add(searchField, BorderLayout.CENTER);
panel.add(searchPanel, BorderLayout.NORTH);
String[] columns = {language.getText("fridaWindow.processSelectionWindow.columns.1"),
language.getText("fridaWindow.processSelectionWindow.columns.2")};
Object[][] data = getTableData(processList);
table = new JTable(data, columns);
JScrollPane scrollPane = new JScrollPane(table); JScrollPane scrollPane = new JScrollPane(table);
panel.add(scrollPane, BorderLayout.CENTER); scrollPane.setBorder(BorderFactory.createLineBorder(new Color(0x3C3F41)));
JButton selectButton = new JButton(language.getText("fridaWindow.processSelectionWindow.selectButton")); JPopupMenu contextMenu = createContextMenu();
selectButton.addActionListener(e -> { table.addMouseListener(new MouseAdapter() {
int selectedRow = table.getSelectedRow(); public void mouseClicked(MouseEvent e) {
if (selectedRow >= 0) { if (SwingUtilities.isRightMouseButton(e)) {
long selectedPid = (Long) table.getValueAt(selectedRow, 1); contextMenu.show(table, e.getX(), e.getY());
((FridaWindow) getOwner()).pidField.setText(String.valueOf(selectedPid)); }
dispose(); else if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
injectSelectedProcess();
}
} }
}); });
panel.add(selectButton, BorderLayout.SOUTH);
panel.add(searchField, BorderLayout.NORTH);
panel.add(scrollPane, BorderLayout.CENTER);
setContentPane(panel); setContentPane(panel);
} }
private void filterProcesses(String query) { private DefaultTableModel createTableModel() {
List<ProcessInfo> filteredList = new ArrayList<>(); processList = getProcesses();
for (ProcessInfo process : processList) { String[] columns = { "进程名称", "进程ID" };
if (process.name().toLowerCase().contains(query.toLowerCase())) { Object[][] data = getTableData(processList);
filteredList.add(process); return new DefaultTableModel(data, columns) {
@Override
public boolean isCellEditable(int row, int column) {
return false;
} }
} };
}
Object[][] filteredData = getTableData(filteredList); private void injectSelectedProcess() {
table.setModel(new DefaultTableModel(filteredData, new String[]{"进程名称", "进程ID"})); int selectedRow = table.getSelectedRow();
if (selectedRow != -1) {
long pid = (Long) table.getModel().getValueAt(selectedRow, 1);
((FridaWindow) getOwner()).pidField.setText(String.valueOf(pid));
dispose();
}
}
private void styleSearchField(JTextField field) {
field.setFont(new Font("Microsoft YaHei", Font.PLAIN, 12));
field.putClientProperty("JTextField.placeholderText", "输入进程名搜索...");
field.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(new Color(0x515658)),
BorderFactory.createEmptyBorder(5, 8, 5, 8)
));
}
private void styleTable(JTable table) {
table.setRowHeight(28);
table.setIntercellSpacing(new Dimension(0, 0));
table.setShowGrid(false);
table.setSelectionBackground(new Color(0x214283));
// 自定义渲染器
table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(table, value,
isSelected, hasFocus, row, column);
c.setBackground(row % 2 == 0 ? new Color(0x323232) : new Color(0x2B2B2B));
c.setForeground(Color.WHITE);
return c;
}
});
}
private JPopupMenu createContextMenu() {
JPopupMenu menu = new JPopupMenu();
JMenuItem injectItem = new JMenuItem("注入选中进程");
injectItem.addActionListener(e -> injectSelectedProcess());
menu.add(injectItem);
return menu;
} }
private Object[][] getTableData(List<ProcessInfo> processes) { private Object[][] getTableData(List<ProcessInfo> processes) {
@@ -441,4 +596,8 @@ public class FridaWindow extends WindowsJDialog {
} }
private record ProcessInfo(long pid, String name) {} private record ProcessInfo(long pid, String name) {}
public static void main(String[] args) {
}
} }

View File

@@ -626,7 +626,7 @@ public class MainWindow extends JFrame {
private final ToolItem tool; private final ToolItem tool;
private Timer pressTimer; private Timer pressTimer;
private Timer releaseTimer; private Timer releaseTimer;
private static int delay = 0;
public CardMouseAdapter(JPanel card, ToolItem tool) { public CardMouseAdapter(JPanel card, ToolItem tool) {
this.card = card; this.card = card;
this.tool = tool; this.tool = tool;
@@ -639,9 +639,14 @@ public class MainWindow extends JFrame {
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
startReleaseAnimation(() -> tool.getAction().actionPerformed( if (delay == 0) {
new ActionEvent(card, ActionEvent.ACTION_PERFORMED, "") delay++;
)); startReleaseAnimation(() -> tool.getAction().actionPerformed(
new ActionEvent(card, ActionEvent.ACTION_PERFORMED, "")
));
} else {
delay--;
}
} }
@Override @Override