Qt Windows版本的《智能鼠标点击器》

最近使用QT结合AI整了一款Windows端的鼠标点击器,可以帮我我们解放双手,按照既定的xy坐标去处理点击动作!

软件截图:

操作流程

1.录入动作

(已更新2.0)

2.执行序列动作

(已更新2.0)

3.重复执行序列动作

(已更新2.0)

4.鼠标连续点击测试

(已更新2.0)


源码分享

.pro文件

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

TARGET = WinMouseClicker
TEMPLATE = app

SOURCES += \
    main.cpp \
    mainwindow.cpp \
    coordinatemarker.cpp

HEADERS += \
    mainwindow.h

# Windows 平台需要链接 user32 库
win32 {
    LIBS += -luser32
}

# ========== 编码设置 ==========
# 对于 MSVC 编译器,添加 UTF-8 支持
win32-msvc* {
    QMAKE_CXXFLAGS += /utf-8
}

# 对于 MinGW 编译器
win32-g++ {
    QMAKE_CXXFLAGS += -finput-charset=UTF-8 -fexec-charset=UTF-8
}

# 设置源代码编码为 UTF-8
CODECFORSRC = UTF-8

# 添加资源文件(如果需要图标等资源)
# RESOURCES += resources.qrc

# 发布版本设置
CONFIG(release, debug|release) {
    DEFINES += QT_NO_DEBUG_OUTPUT
}

# 调试版本设置
CONFIG(debug, debug|release) {
    DEFINES += QT_DEBUG
}

# 设置图标(可选)
# win32:RC_ICONS += app.ico

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <windows.h>
#include <vector>

QT_BEGIN_NAMESPACE
class QPushButton;
class QDoubleSpinBox;
class QSpinBox;
class QLabel;
class QCheckBox;
class QTimer;
class QTableWidget;
class QTableWidgetItem;
class QProgressBar;
class QMenu;
class QComboBox;
class QRadioButton;
class QButtonGroup;
class QGroupBox;
QT_END_NAMESPACE

// 动作数据结构
struct ClickAction {
    int id;
    int x;
    int y;
    double delay;      // 延迟时间(秒)
    bool leftButton;
    bool doubleClick;
    QString description;

    ClickAction(int id = 0, int x = 0, int y = 0, double delay = 0.0,
                bool leftButton = true, bool doubleClick = false,
                const QString& desc = "")
        : id(id), x(x), y(y), delay(delay),
          leftButton(leftButton), doubleClick(doubleClick),
          description(desc) {}
};

// 标记窗口类 - 用于显示坐标位置
class CoordinateMarker : public QWidget
{
    Q_OBJECT
public:
    explicit CoordinateMarker(QWidget *parent = nullptr);
    void setPosition(int x, int y);

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    int posX;
    int posY;
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected:
    bool eventFilter(QObject *obj, QEvent *event) override;
    bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
    void resizeEvent(QResizeEvent *event) override;

private slots:
    void onClickButtonClicked();      // 点击按钮槽函数
    void onPickCoordClicked();        // 拾取坐标槽函数
    void onRepeatTimeout();           // 重复点击定时器

    // 动作序列相关槽函数
    void onAddActionClicked();        // 添加动作
    void onRemoveActionClicked();     // 移除动作
    void onClearActionsClicked();     // 清空动作
    void onExecuteSequenceClicked();  // 执行序列
    void onRepeatSequenceClicked();   // 重复执行序列
    void onStopSequenceClicked();     // 停止序列
    void onSequenceTimeout();         // 序列定时器

    // 倒计时相关
    void onCountdownTimeout();        // 倒计时定时器

    // 表格相关
    void onActionTableItemChanged(QTableWidgetItem *item);
    void onActionTableSelectionChanged();
    void onActionTableCellClicked(int row, int column);
    void onActionTableCurrentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn);

    // 表格右键菜单
    void onTableContextMenu(const QPoint &pos);
    void onInsertAction();            // 插入动作
    void onMoveActionUp();            // 上移动作
    void onMoveActionDown();          // 下移动作
    void onDuplicateAction();         // 复制动作

    // 复选框状态改变
    void onRepeatStateChanged(int state);
    void onRepeatCountChanged(int value);
    void onInfiniteSequenceRepeatChanged(int state);
    void onRepeatModeChanged();       // 重复模式改变

    // 导入导出功能
    void onExportActionsClicked();    // 导出动作序列
    void onImportActionsClicked();    // 导入动作序列

    // 时间相关
    QString formatTime(int seconds);  // 格式化时间显示
    void updateTimeDisplay();         // 更新时间显示

private:
    // Windows API 鼠标点击函数
    void clickAt(int x, int y, bool leftButton = true, bool doubleClick = false);
    void clickAction(const ClickAction& action);

    // 移动鼠标到指定位置
    void moveMouseTo(int x, int y);

    // 创建鼠标点击事件
    void sendMouseClick(int x, int y, bool leftButton, bool down);

    // 动作序列管理
    void addActionToList(const ClickAction& action);
    void updateActionTable();
    void createTableContextMenu();    // 创建表格右键菜单
    void highlightTableRow(int row);  // 高亮表格行
    void showCoordinateMarker(int x, int y); // 显示坐标标记
    void hideCoordinateMarker();      // 隐藏坐标标记

    // 表格验证
    bool validateTableInput(int row, int column, const QString& text);
    void setupTableDelegates();       // 设置表格委托

    // 快捷键设置
    void setupShortcuts();

    // 开始倒计时
    void startCountdown(int seconds);

    // 转换延迟值为毫秒
    int delayToMilliseconds(double seconds);

    // 转换时间到秒
    int timeToSeconds(int hours, int minutes, int seconds);

    // 执行序列相关
    void startSequenceExecution(bool repeatMode = false);

    // 更新进度显示
    void updateProgressInfo();

    // 显示状态消息
    void showStatusMessage(const QString& message, bool isError = false, bool isSuccess = false);

    // 激活窗口并显示在最前面
    void activateAndShowWindow();

    // 注册全局热键
    void registerGlobalHotkey();

    // 注销全局热键
    void unregisterGlobalHotkey();

    // 重置序列执行状态
    void resetSequenceExecution();

    // 文件操作
    bool saveActionsToJson(const QString& filePath);    // 保存为JSON
    bool loadActionsFromJson(const QString& filePath);  // 从JSON加载

    // 应用设置
    void saveSettings();               // 保存设置
    void loadSettings();               // 加载设置

    // UI 组件
    QSpinBox *xSpinBox;
    QSpinBox *ySpinBox;
    QDoubleSpinBox *delaySpinBox;
    QSpinBox *repeatCountSpinBox;
    QSpinBox *sequenceRepeatSpinBox;
    QSpinBox *countdownSpinBox;
    QPushButton *clickButton;
    QPushButton *pickCoordButton;
    QCheckBox *repeatCheckBox;
    QCheckBox *leftButtonCheck;
    QCheckBox *doubleClickCheck;
    QCheckBox *infiniteRepeatCheck;
    QCheckBox *infiniteSequenceRepeatCheck;
    QLabel *statusLabel;
    QLabel *cursorLabel;
    QProgressBar *progressBar;
    QLabel *progressLabel;

    // 重复模式相关
    QComboBox *repeatModeCombo;
    QLabel *timeLabel;
    QSpinBox *hoursSpinBox;
    QSpinBox *minutesSpinBox;
    QSpinBox *secondsSpinBox;
    QGroupBox *timeGroup;

    // 动作序列相关UI组件
    QPushButton *addActionButton;
    QPushButton *removeActionButton;
    QPushButton *clearActionsButton;
    QPushButton *executeSequenceButton;
    QPushButton *repeatSequenceButton;
    QPushButton *stopSequenceButton;
    QPushButton *exportActionsButton;  // 导出按钮
    QPushButton *importActionsButton;  // 导入按钮
    QTableWidget *actionTable;

    // 右键菜单
    QMenu *tableContextMenu;

    // 坐标标记窗口
    CoordinateMarker *coordinateMarker;
    QTimer *markerTimer;

    QTimer *repeatTimer;
    QTimer *sequenceTimer;
    QTimer *countdownTimer;
    bool isRepeating;
    bool isSequenceRunning;
    bool isRepeatingSequence;
    bool isInfiniteSequenceRepeat;

    // 动作数据
    std::vector<ClickAction> actionList;
    int currentActionIndex;
    int nextActionId;
    int countdownSeconds;
    bool hotkeyRegistered;

    // 计数相关
    int currentRepeatCount;
    int totalRepeatCount;
    int currentSequenceRepeat;
    int totalSequenceRepeat;

    // 时间相关
    int totalRepeatTime;  // 总重复时间(秒)
    int elapsedTime;      // 已执行时间(秒)
    QTimer *timeUpdateTimer;

    // 中断标志
    bool stopRequested;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QPushButton>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QLabel>
#include <QCheckBox>
#include <QTimer>
#include <QMouseEvent>
#include <QDebug>
#include <QMessageBox>
#include <QTableWidget>
#include <QHeaderView>
#include <QFile>
#include <QTextStream>
#include <QKeyEvent>
#include <QShortcut>
#include <QFileDialog>
#include <QProgressBar>
#include <QFont>
#include <QResizeEvent>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
#include <QDateTime>
#include <QMenu>
#include <QAction>
#include <QInputDialog>
#include <QComboBox>
#include <QIntValidator>
#include <QDoubleValidator>
#include <QItemDelegate>
#include <QStyleOptionComboBox>
#include <QSettings>
#include <QPainter>
#include <QRadioButton>
#include <QButtonGroup>
#include <QTimeEdit>

// 全局热键消息ID
#define HOTKEY_ID 1

// 自定义表格委托类 - 用于输入验证和下拉框
class ActionTableDelegate : public QItemDelegate
{
public:
    explicit ActionTableDelegate(QObject *parent = nullptr) : QItemDelegate(parent) {}

    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                          const QModelIndex &index) const override
    {
        switch (index.column()) {
        case 1: // X坐标 - 整数输入
        case 2: { // Y坐标 - 整数输入
            QSpinBox *editor = new QSpinBox(parent);
            editor->setRange(0, GetSystemMetrics(index.column() == 1 ? SM_CXSCREEN : SM_CYSCREEN) - 1);
            editor->setSuffix(" px");
            return editor;
        }
        case 3: { // 延迟时间 - 浮点数输入
            QDoubleSpinBox *editor = new QDoubleSpinBox(parent);
            editor->setRange(0.0, 10800.0);  // 修改:最小值改为0
            editor->setDecimals(3);
            editor->setSingleStep(0.1);
            editor->setSuffix(" 秒");
            return editor;
        }
        case 4: { // 按键选择 - 下拉框
            QComboBox *editor = new QComboBox(parent);
            editor->addItem("左键");
            editor->addItem("右键");
            editor->addItem("中键");

            // 添加样式表,确保下拉项正常显示
            editor->setStyleSheet(
                "QComboBox {"
                "  padding: 4px;"
                "  font-size: 12px;"
                "  border: 1px solid #ccc;"
                "  border-radius: 4px;"
                "  background-color: white;"
                "  color: #333;"
                "}"
                "QComboBox:hover {"
                "  border: 1px solid #4CAF50;"
                "}"
                "QComboBox::drop-down {"
                "  border: none;"
                "}"
                "QComboBox::down-arrow {"
                "  image: none;"
                "  border-left: 1px solid #ddd;"
                "  width: 18px;"
                "}"
                "QComboBox QAbstractItemView {"
                "  border: 1px solid #ccc;"
                "  selection-background-color: #e0e0e0;"
                "  selection-color: #333;"
                "  background-color: white;"
                "  color: #333;"
                "  padding: 4px;"
                "  font-size: 12px;"
                "}"
                "QComboBox QAbstractItemView::item {"
                "  padding: 6px;"
                "  border-bottom: 1px solid #f0f0f0;"
                "}"
                "QComboBox QAbstractItemView::item:hover {"
                "  background-color: #f0f0f0;"
                "  color: #000;"
                "}"
                "QComboBox QAbstractItemView::item:selected {"
                "  background-color: #e0e0e0;"
                "  color: #333;"
                "}"
            );

            return editor;
        }
        case 5: { // 点击类型 - 下拉框
            QComboBox *editor = new QComboBox(parent);
            editor->addItem("单击");
            editor->addItem("双击");
            editor->addItem("按下");
            editor->addItem("释放");

            // 添加相同的样式表
            editor->setStyleSheet(
                "QComboBox {"
                "  padding: 4px;"
                "  font-size: 12px;"
                "  border: 1px solid #ccc;"
                "  border-radius: 4px;"
                "  background-color: white;"
                "  color: #333;"
                "}"
                "QComboBox:hover {"
                "  border: 1px solid #4CAF50;"
                "}"
                "QComboBox::drop-down {"
                "  border: none;"
                "}"
                "QComboBox::down-arrow {"
                "  image: none;"
                "  border-left: 1px solid #ddd;"
                "  width: 18px;"
                "}"
                "QComboBox QAbstractItemView {"
                "  border: 1px solid #ccc;"
                "  selection-background-color: #e0e0e0;"
                "  selection-color: #333;"
                "  background-color: white;"
                "  color: #333;"
                "  padding: 4px;"
                "  font-size: 12px;"
                "}"
                "QComboBox QAbstractItemView::item {"
                "  padding: 6px;"
                "  border-bottom: 1px solid #f0f0f0;"
                "}"
                "QComboBox QAbstractItemView::item:hover {"
                "  background-color: #f0f0f0;"
                "  color: #000;"
                "}"
                "QComboBox QAbstractItemView::item:selected {"
                "  background-color: #e0e0e0;"
                "  color: #333;"
                "}"
            );

            return editor;
        }
        default:
            return QItemDelegate::createEditor(parent, option, index);
        }
    }

    void setEditorData(QWidget *editor, const QModelIndex &index) const override
    {
        QString value = index.model()->data(index, Qt::EditRole).toString();

        switch (index.column()) {
        case 1: // X坐标
        case 2: { // Y坐标
            QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
            spinBox->setValue(value.toInt());
            break;
        }
        case 3: { // 延迟时间
            QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
            spinBox->setValue(value.toDouble());
            break;
        }
        case 4: { // 按键选择
            QComboBox *comboBox = static_cast<QComboBox*>(editor);
            QString buttonText = value;
            if (buttonText == "左键") comboBox->setCurrentIndex(0);
            else if (buttonText == "右键") comboBox->setCurrentIndex(1);
            else if (buttonText == "中键") comboBox->setCurrentIndex(2);
            else comboBox->setCurrentText(value);
            break;
        }
        case 5: { // 点击类型
            QComboBox *comboBox = static_cast<QComboBox*>(editor);
            QString clickType = value;
            if (clickType == "单击" || clickType == "否") comboBox->setCurrentIndex(0);
            else if (clickType == "双击" || clickType == "是") comboBox->setCurrentIndex(1);
            else if (clickType == "按下") comboBox->setCurrentIndex(2);
            else if (clickType == "释放") comboBox->setCurrentIndex(3);
            else comboBox->setCurrentText(value);
            break;
        }
        default:
            QItemDelegate::setEditorData(editor, index);
        }
    }

    void setModelData(QWidget *editor, QAbstractItemModel *model,
                      const QModelIndex &index) const override
    {
        switch (index.column()) {
        case 1: // X坐标
        case 2: { // Y坐标
            QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
            model->setData(index, spinBox->value(), Qt::EditRole);
            break;
        }
        case 3: { // 延迟时间
            QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>(editor);
            model->setData(index, spinBox->value(), Qt::EditRole);
            break;
        }
        case 4: // 按键选择
        case 5: { // 点击类型
            QComboBox *comboBox = static_cast<QComboBox*>(editor);
            model->setData(index, comboBox->currentText(), Qt::EditRole);
            break;
        }
        default:
            QItemDelegate::setModelData(editor, model, index);
        }
    }
};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , isRepeating(false)
    , isSequenceRunning(false)
    , isRepeatingSequence(false)
    , isInfiniteSequenceRepeat(false)
    , currentActionIndex(0)
    , nextActionId(1)
    , stopRequested(false)
    , countdownSeconds(0)
    , currentRepeatCount(0)
    , totalRepeatCount(0)
    , currentSequenceRepeat(0)
    , totalSequenceRepeat(0)
    , hotkeyRegistered(false)
    , tableContextMenu(nullptr)
    , totalRepeatTime(0)
    , elapsedTime(0)
{
    // 设置窗口
    setWindowTitle("智能鼠标点击器 v3.0 - 支持动作序列、时间控制和坐标预览");
    resize(700, 550);  // 修改:减小窗口高度

    // 设置窗口图标和样式
    setStyleSheet("QMainWindow { background-color: #f0f0f0; }");

    // 安装事件过滤器
    qApp->installEventFilter(this);

    // 创建中央部件
    QWidget *centralWidget = new QWidget(this);
    centralWidget->setStyleSheet("QWidget { background-color: white; border-radius: 8px; }");
    setCentralWidget(centralWidget);

    // 创建主布局
    QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
    mainLayout->setSpacing(8);  // 减小间距
    mainLayout->setContentsMargins(8, 8, 8, 8);  // 减小边距

    // ========== 基础点击控制区域 ==========
    QGroupBox *basicGroup = new QGroupBox("🎯 基础点击控制", centralWidget);
    basicGroup->setStyleSheet(
        "QGroupBox {"
        "  font-weight: bold;"
        "  font-size: 13px;"
        "  border: 2px solid #4CAF50;"
        "  border-radius: 8px;"
        "  margin-top: 8px;"
        "  padding-top: 12px;"  // 减小内边距
        "}"
        "QGroupBox::title {"
        "  subcontrol-origin: margin;"
        "  left: 12px;"  // 减小左边距
        "  padding: 0 8px 0 8px;"  // 减小内边距
        "  color: #4CAF50;"
        "  font-size: 13px;"
        "}"
    );

    QGridLayout *basicLayout = new QGridLayout(basicGroup);
    basicLayout->setVerticalSpacing(8);  // 减小垂直间距
    basicLayout->setHorizontalSpacing(10);  // 减小水平间距
    basicLayout->setContentsMargins(10, 10, 10, 10);  // 减小内边距

    // X坐标
    QLabel *xLabel = new QLabel("📌 X坐标:", basicGroup);
    xLabel->setToolTip("点击位置的X坐标 (0-" + QString::number(GetSystemMetrics(SM_CXSCREEN) - 1) + ")");
    xLabel->setStyleSheet("QLabel { font-size: 12px; font-weight: 500; }");
    basicLayout->addWidget(xLabel, 0, 0);

    xSpinBox = new QSpinBox(basicGroup);
    xSpinBox->setRange(0, GetSystemMetrics(SM_CXSCREEN) - 1);
    xSpinBox->setValue(100);
    xSpinBox->setSuffix(" px");
    xSpinBox->setToolTip("设置点击位置的X坐标\n按空格键可快速拾取当前光标位置");
    xSpinBox->setStyleSheet(
        "QSpinBox {"
        "  padding: 5px;"
        "  font-size: 12px;"
        "  border: 1px solid #ccc;"
        "  border-radius: 4px;"
        "}"
        "QSpinBox:hover {"
        "  border: 1px solid #4CAF50;"
        "}"
    );
    basicLayout->addWidget(xSpinBox, 0, 1);

    // Y坐标
    QLabel *yLabel = new QLabel("📌 Y坐标:", basicGroup);
    yLabel->setToolTip("点击位置的Y坐标 (0-" + QString::number(GetSystemMetrics(SM_CYSCREEN) - 1) + ")");
    yLabel->setStyleSheet("QLabel { font-size: 12px; font-weight: 500; }");
    basicLayout->addWidget(yLabel, 1, 0);

    ySpinBox = new QSpinBox(basicGroup);
    ySpinBox->setRange(0, GetSystemMetrics(SM_CYSCREEN) - 1);
    ySpinBox->setValue(100);
    ySpinBox->setSuffix(" px");
    ySpinBox->setToolTip("设置点击位置的Y坐标\n按空格键可快速拾取当前光标位置");
    ySpinBox->setStyleSheet(
        "QSpinBox {"
        "  padding: 5px;"
        "  font-size: 12px;"
        "  border: 1px solid #ccc;"
        "  border-radius: 4px;"
        "}"
        "QSpinBox:hover {"
        "  border: 1px solid #4CAF50;"
        "}"
    );
    basicLayout->addWidget(ySpinBox, 1, 1);

    // 延迟时间
    QLabel *delayLabel = new QLabel("⏱️ 延迟时间:", basicGroup);
    delayLabel->setToolTip("每次点击之间的间隔时间");
    delayLabel->setStyleSheet("QLabel { font-size: 12px; font-weight: 500; }");
    basicLayout->addWidget(delayLabel, 2, 0);

    delaySpinBox = new QDoubleSpinBox(basicGroup);
    delaySpinBox->setRange(0.0, 10800.0);  // 修改:最小值改为0
    delaySpinBox->setValue(1.0);
    delaySpinBox->setDecimals(3);
    delaySpinBox->setSingleStep(0.1);
    delaySpinBox->setSuffix(" 秒");
    delaySpinBox->setToolTip("重复点击时的间隔时间\n范围: 0秒 到 3小时");
    delaySpinBox->setStyleSheet(
        "QDoubleSpinBox {"
        "  padding: 5px;"
        "  font-size: 12px;"
        "  border: 1px solid #ccc;"
        "  border-radius: 4px;"
        "}"
        "QDoubleSpinBox:hover {"
        "  border: 1px solid #4CAF50;"
        "}"
    );
    basicLayout->addWidget(delaySpinBox, 2, 1);

    // 倒计时设置
    QLabel *countdownLabel = new QLabel("⏱️ 开始倒计时:", basicGroup);
    countdownLabel->setToolTip("任务开始前的倒计时时间");
    countdownLabel->setStyleSheet("QLabel { font-size: 12px; font-weight: 500; }");
    basicLayout->addWidget(countdownLabel, 3, 0);

    countdownSpinBox = new QSpinBox(basicGroup);
    countdownSpinBox->setRange(0, 10800);
    countdownSpinBox->setValue(3);
    countdownSpinBox->setSuffix(" 秒");
    countdownSpinBox->setToolTip("任务开始前的倒计时时间,设为0则不显示倒计时");
    countdownSpinBox->setStyleSheet(
        "QSpinBox {"
        "  padding: 5px;"
        "  font-size: 12px;"
        "  border: 1px solid #ccc;"
        "  border-radius: 4px;"
        "}"
        "QSpinBox:hover {"
        "  border: 1px solid #4CAF50;"
        "}"
    );
    basicLayout->addWidget(countdownSpinBox, 3, 1);

    // 拾取坐标按钮
    pickCoordButton = new QPushButton("🎯 拾取坐标", basicGroup);
    pickCoordButton->setToolTip("点击后移动鼠标到目标位置,按空格键拾取坐标");
    pickCoordButton->setStyleSheet(
        "QPushButton {"
        "  background-color: #FF9800;"
        "  color: white;"
        "  font-weight: bold;"
        "  font-size: 12px;"
        "  padding: 6px 14px;"  // 减小内边距
        "  border-radius: 5px;"
        "  border: none;"
        "}"
        "QPushButton:hover {"
        "  background-color: #F57C00;"
        "}"
        "QPushButton:pressed {"
        "  background-color: #E65100;"
        "}"
    );
    basicLayout->addWidget(pickCoordButton, 0, 2, 2, 1);

    // 立即点击按钮
    clickButton = new QPushButton("🎯 立即点击", basicGroup);
    clickButton->setStyleSheet(
        "QPushButton {"
        "  background-color: #2196F3;"
        "  color: white;"
        "  font-size: 13px;"
        "  font-weight: bold;"
        "  padding: 8px;"
        "  border-radius: 5px;"
        "  border: none;"
        "  min-width: 120px;"  // 减小最小宽度
        "}"
        "QPushButton:hover {"
        "  background-color: #1976D2;"
        "}"
        "QPushButton:pressed {"
        "  background-color: #0D47A1;"
        "}"
        "QPushButton:disabled {"
        "  background-color: #BDBDBD;"
        "}"
    );
    clickButton->setToolTip("重复点击启用时:开始/停止重复点击\n重复点击未启用时:执行单次点击\n快捷键: Ctrl+S");
    basicLayout->addWidget(clickButton, 2, 2, 2, 1);

    // 光标位置显示
    cursorLabel = new QLabel("🖱️ 光标位置: (0, 0)", basicGroup);
    cursorLabel->setStyleSheet(
        "QLabel {"
        "  color: #0066CC;"
        "  font-style: italic;"
        "  font-size: 12px;"
        "  font-weight: bold;"
        "  background-color: #f0f8ff;"
        "  padding: 6px 10px;"  // 减小内边距
        "  border-radius: 6px;"
        "  border: 1px solid #b3e0ff;"
        "}"
    );
    basicLayout->addWidget(cursorLabel, 4, 0, 1, 3);

    // 点击选项
    QHBoxLayout *optionsLayout = new QHBoxLayout();
    optionsLayout->setSpacing(15);  // 减小间距

    leftButtonCheck = new QCheckBox("🖱️ 左键点击", basicGroup);
    leftButtonCheck->setChecked(true);
    leftButtonCheck->setToolTip("使用鼠标左键点击\n取消勾选将使用右键点击");
    leftButtonCheck->setStyleSheet("QCheckBox { font-size: 12px; font-weight: 500; }");
    optionsLayout->addWidget(leftButtonCheck);

    doubleClickCheck = new QCheckBox("⚡ 双击", basicGroup);
    doubleClickCheck->setToolTip("执行双击操作而不是单击");
    doubleClickCheck->setStyleSheet("QCheckBox { font-size: 12px; font-weight: 500; }");
    optionsLayout->addWidget(doubleClickCheck);

    optionsLayout->addStretch();
    basicLayout->addLayout(optionsLayout, 5, 0, 1, 3);

    // 重复点击设置 - 第一行
    QHBoxLayout *repeatSettingsLayout1 = new QHBoxLayout();
    repeatSettingsLayout1->setSpacing(8);

    repeatCheckBox = new QCheckBox("🔁 启用重复点击", basicGroup);
    repeatCheckBox->setToolTip("勾选后可以设置重复点击次数和间隔");
    repeatCheckBox->setChecked(false);
    repeatCheckBox->setStyleSheet("QCheckBox { font-size: 12px; font-weight: 500; }");
    repeatSettingsLayout1->addWidget(repeatCheckBox);
    connect(repeatCheckBox, &QCheckBox::stateChanged, this, &MainWindow::onRepeatStateChanged);

    QLabel *repeatModeLabel = new QLabel("重复模式:", basicGroup);
    repeatModeLabel->setStyleSheet("QLabel { font-size: 12px; font-weight: 500; }");
    repeatSettingsLayout1->addWidget(repeatModeLabel);

    repeatModeCombo = new QComboBox(basicGroup);
    repeatModeCombo->addItem("按次数重复");
    repeatModeCombo->addItem("按时间重复");
    repeatModeCombo->setToolTip("选择重复模式:按次数或按时间");
    repeatModeCombo->setStyleSheet(
        "QComboBox {"
        "  padding: 4px;"
        "  font-size: 12px;"
        "  border: 1px solid #ccc;"
        "  border-radius: 4px;"
        "  min-width: 110px;"
        "  background-color: white;"
        "  color: #333;"
        "}"
        "QComboBox:hover {"
        "  border: 1px solid #4CAF50;"
        "  background-color: #f9f9f9;"
        "  color: #000;"
        "}"
        "QComboBox::drop-down {"
        "  border: none;"
        "}"
        "QComboBox::down-arrow {"
        "  image: none;"
        "  border-left: 1px solid #ddd;"
        "  width: 18px;"
        "}"
        "QComboBox QAbstractItemView {"
        "  border: 1px solid #ccc;"
        "  selection-background-color: #e0e0e0;"
        "  selection-color: #333;"
        "}"
    );
    connect(repeatModeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
            this, &MainWindow::onRepeatModeChanged);
    repeatSettingsLayout1->addWidget(repeatModeCombo);

    repeatSettingsLayout1->addStretch();
    basicLayout->addLayout(repeatSettingsLayout1, 6, 0, 1, 3);

    // 重复点击设置 - 第二行(次数设置)
    QHBoxLayout *repeatSettingsLayout2 = new QHBoxLayout();
    repeatSettingsLayout2->setSpacing(8);

    QLabel *repeatCountLabel = new QLabel("重复次数:", basicGroup);
    repeatCountLabel->setStyleSheet("QLabel { font-size: 12px; font-weight: 500; }");
    repeatSettingsLayout2->addWidget(repeatCountLabel);

    repeatCountSpinBox = new QSpinBox(basicGroup);
    repeatCountSpinBox->setRange(1, 9999);
    repeatCountSpinBox->setValue(10);
    repeatCountSpinBox->setSuffix(" 次");
    repeatCountSpinBox->setToolTip("重复点击的次数\n设置为1时相当于单次点击");
    repeatCountSpinBox->setEnabled(false);
    repeatCountSpinBox->setStyleSheet(
        "QSpinBox {"
        "  font-size: 12px;"
        "  padding: 4px;"
        "  border: 1px solid #ccc;"
        "  border-radius: 4px;"
        "  min-width: 70px;"
        "}"
    );
    repeatSettingsLayout2->addWidget(repeatCountSpinBox);
    connect(repeatCountSpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
            this, &MainWindow::onRepeatCountChanged);

    infiniteRepeatCheck = new QCheckBox("无限循环", basicGroup);
    infiniteRepeatCheck->setToolTip("勾选后将无限重复点击,直到手动停止");
    infiniteRepeatCheck->setEnabled(false);
    infiniteRepeatCheck->setStyleSheet("QCheckBox { font-size: 12px; font-weight: 500; }");
    repeatSettingsLayout2->addWidget(infiniteRepeatCheck);
    connect(infiniteRepeatCheck, &QCheckBox::stateChanged, this, [this](int state) {
        repeatCountSpinBox->setEnabled(state == Qt::Unchecked && repeatModeCombo->currentIndex() == 0);
        if (repeatModeCombo->currentIndex() == 1) {
            hoursSpinBox->setEnabled(state == Qt::Unchecked);
            minutesSpinBox->setEnabled(state == Qt::Unchecked);
            secondsSpinBox->setEnabled(state == Qt::Unchecked);
        }
    });

    repeatSettingsLayout2->addStretch();
    basicLayout->addLayout(repeatSettingsLayout2, 7, 0, 1, 3);

    // 时间设置组
    timeGroup = new QGroupBox("⏰ 时间设置", basicGroup);
    timeGroup->setStyleSheet(
        "QGroupBox {"
        "  font-weight: normal;"
        "  font-size: 12px;"
        "  border: 1px solid #ddd;"
        "  border-radius: 5px;"
        "  margin-top: 4px;"
        "  padding-top: 8px;"
        "}"
        "QGroupBox::title {"
        "  subcontrol-origin: margin;"
        "  left: 8px;"
        "  padding: 0 4px 0 4px;"
        "  color: #666;"
        "}"
    );
    timeGroup->setVisible(false); // 默认隐藏

    QHBoxLayout *timeLayout = new QHBoxLayout(timeGroup);
    timeLayout->setSpacing(4);

    timeLabel = new QLabel("持续时间:", timeGroup);
    timeLabel->setStyleSheet("QLabel { font-size: 12px; }");
    timeLayout->addWidget(timeLabel);

    hoursSpinBox = new QSpinBox(timeGroup);
    hoursSpinBox->setRange(0, 99);
    hoursSpinBox->setValue(0);
    hoursSpinBox->setSuffix(" 时");
    hoursSpinBox->setToolTip("小时");
    hoursSpinBox->setStyleSheet(
        "QSpinBox {"
        "  font-size: 12px;"
        "  padding: 4px;"
        "  border: 1px solid #ccc;"
        "  border-radius: 4px;"
        "  min-width: 55px;"
        "}"
    );
    timeLayout->addWidget(hoursSpinBox);

    minutesSpinBox = new QSpinBox(timeGroup);
    minutesSpinBox->setRange(0, 59);
    minutesSpinBox->setValue(1);
    minutesSpinBox->setSuffix(" 分");
    minutesSpinBox->setToolTip("分钟");
    minutesSpinBox->setStyleSheet(
        "QSpinBox {"
        "  font-size: 12px;"
        "  padding: 4px;"
        "  border: 1px solid #ccc;"
        "  border-radius: 4px;"
        "  min-width: 55px;"
        "}"
    );
    timeLayout->addWidget(minutesSpinBox);

    secondsSpinBox = new QSpinBox(timeGroup);
    secondsSpinBox->setRange(0, 59);
    secondsSpinBox->setValue(0);
    secondsSpinBox->setSuffix(" 秒");
    secondsSpinBox->setToolTip("秒");
    secondsSpinBox->setStyleSheet(
        "QSpinBox {"
        "  font-size: 12px;"
        "  padding: 4px;"
        "  border: 1px solid #ccc;"
        "  border-radius: 4px;"
        "  min-width: 55px;"
        "}"
    );
    timeLayout->addWidget(secondsSpinBox);

    timeLayout->addStretch();
    basicLayout->addWidget(timeGroup, 8, 0, 1, 3);

    // 连接按钮信号
    connect(pickCoordButton, &QPushButton::clicked, this, &MainWindow::onPickCoordClicked);
    connect(clickButton, &QPushButton::clicked, this, &MainWindow::onClickButtonClicked);

    mainLayout->addWidget(basicGroup);

    // ========== 动作序列区域 ==========
    QGroupBox *sequenceGroup = new QGroupBox("📋 动作序列管理", centralWidget);
    sequenceGroup->setStyleSheet(
        "QGroupBox {"
        "  font-weight: bold;"
        "  font-size: 13px;"
        "  border: 2px solid #2196F3;"
        "  border-radius: 8px;"
        "  margin-top: 8px;"
        "  padding-top: 12px;"
        "}"
        "QGroupBox::title {"
        "  subcontrol-origin: margin;"
        "  left: 12px;"
        "  padding: 0 8px 0 8px;"
        "  color: #2196F3;"
        "  font-size: 13px;"
        "}"
    );

    QVBoxLayout *sequenceLayout = new QVBoxLayout(sequenceGroup);
    sequenceLayout->setSpacing(6);  // 减小间距
    sequenceLayout->setContentsMargins(10, 10, 10, 10);  // 减小内边距

    // 动作表格
    actionTable = new QTableWidget(sequenceGroup);
    actionTable->setColumnCount(6);
    QStringList headers;
    headers << "ID" << "X坐标" << "Y坐标" << "延迟(秒)" << "按键" << "点击类型";
    actionTable->setHorizontalHeaderLabels(headers);
    actionTable->setSelectionBehavior(QTableWidget::SelectRows);
    actionTable->setSelectionMode(QTableWidget::SingleSelection);
    actionTable->setEditTriggers(QTableWidget::DoubleClicked | QTableWidget::EditKeyPressed);
    actionTable->setMinimumHeight(150);  // 减小最小高度
    actionTable->setMaximumHeight(220);  // 减小最大高度
    actionTable->setContextMenuPolicy(Qt::CustomContextMenu);  // 启用右键菜单

    // 表格样式
    actionTable->setStyleSheet(
        "QTableWidget {"
        "  background-color: #ffffff;"
        "  alternate-background-color: #f8fafc;"
        "  border: 2px solid #e1e8ed;"
        "  border-radius: 6px;"
        "  padding: 0px;"
        "  gridline-color: #eef2f7;"
        "  font-size: 11px;"
        "  outline: 0;"
        "  selection-background-color: rgba(33, 150, 243, 0.2);"
        "  selection-color: #1976D2;"
        "}"
        "QTableWidget::item {"
        "  padding: 6px 5px;"  // 减小内边距
        "  border-bottom: 1px solid #f0f0f0;"
        "  color: #2d3748;"
        "}"
        "QTableWidget::item:selected {"
        "  background-color: rgba(25, 118, 210, 0.2);"
        "  color: #1976D2;"
        "  font-weight: bold;"
        "  border: none;"
        "}"
        "QTableWidget::item:hover:!selected {"
        "  background-color: #f8fafc;"
        "}"
        "QHeaderView::section {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #2196F3, stop:1 #1976D2);"
        "  color: white;"
        "  padding: 10px 6px;"  // 减小内边距
        "  font-weight: bold;"
        "  font-size: 12px;"
        "  border: none;"
        "  border-right: 1px solid #0D47A1;"
        "}"
        "QHeaderView::section:first {"
        "  border-top-left-radius: 5px;"
        "}"
        "QHeaderView::section:last {"
        "  border-top-right-radius: 5px;"
        "}"
        "QScrollBar:vertical {"
        "  border: none;"
        "  background: #f5f5f5;"
        "  width: 10px;"
        "  border-radius: 5px;"
        "}"
        "QScrollBar::handle:vertical {"
        "  background: #bdbdbd;"
        "  border-radius: 5px;"
        "  min-height: 18px;"
        "}"
        "QScrollBar::handle:vertical:hover {"
        "  background: #9e9e9e;"
        "}"
        "QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {"
        "  border: none;"
        "  background: none;"
        "}"
    );

    actionTable->setAlternatingRowColors(true);
    QHeaderView* header = actionTable->horizontalHeader();
    header->setStretchLastSection(true);
    header->setDefaultAlignment(Qt::AlignCenter | Qt::AlignVCenter);
    header->setSectionResizeMode(QHeaderView::Interactive);
    header->setMinimumSectionSize(65);
    header->setDefaultSectionSize(100);

    // 设置列宽
    actionTable->setColumnWidth(0, 55);    // ID
    actionTable->setColumnWidth(1, 100);   // X坐标
    actionTable->setColumnWidth(2, 100);   // Y坐标
    actionTable->setColumnWidth(3, 110);   // 延迟(秒)
    actionTable->setColumnWidth(4, 85);    // 按键
    actionTable->setColumnWidth(5, 95);    // 点击类型

    actionTable->verticalHeader()->setDefaultSectionSize(35);  // 减小行高
    actionTable->verticalHeader()->setVisible(false);
    actionTable->setShowGrid(false);
    actionTable->setCornerButtonEnabled(false);

    // 设置自定义委托
    actionTable->setItemDelegate(new ActionTableDelegate(this));

    sequenceLayout->addWidget(actionTable, 1);

    // 连接表格信号
    connect(actionTable, &QTableWidget::itemChanged, this, &MainWindow::onActionTableItemChanged);
    connect(actionTable, &QTableWidget::itemSelectionChanged, this, &MainWindow::onActionTableSelectionChanged);
    connect(actionTable, &QTableWidget::cellClicked, this, &MainWindow::onActionTableCellClicked);
    connect(actionTable, &QTableWidget::currentCellChanged, this, &MainWindow::onActionTableCurrentCellChanged);
    connect(actionTable, &QTableWidget::customContextMenuRequested, this, &MainWindow::onTableContextMenu);

    // 序列重复设置
    QHBoxLayout *repeatSequenceLayout = new QHBoxLayout();
    repeatSequenceLayout->setSpacing(8);

    QLabel *seqRepeatLabel = new QLabel("序列重复次数:", sequenceGroup);
    seqRepeatLabel->setStyleSheet("QLabel { font-size: 12px; font-weight: 500; }");
    repeatSequenceLayout->addWidget(seqRepeatLabel);

    sequenceRepeatSpinBox = new QSpinBox(sequenceGroup);
    sequenceRepeatSpinBox->setRange(1, 9999);
    sequenceRepeatSpinBox->setValue(1);
    sequenceRepeatSpinBox->setSuffix(" 次");
    sequenceRepeatSpinBox->setToolTip("序列重复执行的次数");
    sequenceRepeatSpinBox->setStyleSheet(
        "QSpinBox {"
        "  font-size: 12px;"
        "  padding: 4px;"
        "  border: 1px solid #ccc;"
        "  border-radius: 4px;"
        "}"
    );
    repeatSequenceLayout->addWidget(sequenceRepeatSpinBox);

    infiniteSequenceRepeatCheck = new QCheckBox("无限循环", sequenceGroup);
    infiniteSequenceRepeatCheck->setToolTip("勾选后将无限重复执行序列,直到手动停止");
    infiniteSequenceRepeatCheck->setStyleSheet("QCheckBox { font-size: 12px; font-weight: 500; }");
    repeatSequenceLayout->addWidget(infiniteSequenceRepeatCheck);
    connect(infiniteSequenceRepeatCheck, &QCheckBox::stateChanged, this, &MainWindow::onInfiniteSequenceRepeatChanged);

    repeatSequenceLayout->addStretch();
    sequenceLayout->addLayout(repeatSequenceLayout);

    // ========== 新的按钮布局 ==========
    // 第一行:添加、移除、清空、导入、导出
    QHBoxLayout *buttonRow1Layout = new QHBoxLayout();
    buttonRow1Layout->setSpacing(6);

    // 按钮组1 - 操作按钮
    QGroupBox *buttonGroup1 = new QGroupBox("操作", sequenceGroup);
    buttonGroup1->setStyleSheet(
        "QGroupBox {"
        "  font-weight: normal;"
        "  font-size: 11px;"
        "  border: 1px solid #e0e0e0;"
        "  border-radius: 5px;"
        "  margin-top: 6px;"
        "}"
        "QGroupBox::title {"
        "  subcontrol-origin: margin;"
        "  left: 8px;"
        "  padding: 0 4px;"
        "  color: #666;"
        "}"
    );

    QHBoxLayout *group1Layout = new QHBoxLayout(buttonGroup1);
    group1Layout->setSpacing(6);
    group1Layout->setContentsMargins(6, 6, 6, 6);

    addActionButton = new QPushButton("➕ 添加", buttonGroup1);
    addActionButton->setToolTip("将当前设置的点击参数添加到序列中\n快捷键: Ctrl+A");
    addActionButton->setStyleSheet(
        "QPushButton {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #4CAF50, stop:1 #388E3C);"
        "  color: white;"
        "  font-size: 11px;"
        "  font-weight: 600;"
        "  padding: 6px 14px;"  // 减小内边距
        "  border-radius: 5px;"
        "  border: none;"
        "  min-width: 70px;"  // 减小最小宽度
        "}"
        "QPushButton:hover {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #66BB6A, stop:1 #43A047);"
        "}"
        "QPushButton:pressed {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #2E7D32, stop:1 #1B5E20);"
        "}"
        "QPushButton:disabled {"
        "  background: #E0E0E0;"
        "  color: #9E9E9E;"
        "}"
    );
    group1Layout->addWidget(addActionButton);
    connect(addActionButton, &QPushButton::clicked, this, &MainWindow::onAddActionClicked);

    removeActionButton = new QPushButton("➖ 移除", buttonGroup1);
    removeActionButton->setToolTip("移除选中的动作\n快捷键: Ctrl+D");
    removeActionButton->setStyleSheet(
        "QPushButton {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #FF9800, stop:1 #F57C00);"
        "  color: white;"
        "  font-size: 11px;"
        "  font-weight: 600;"
        "  padding: 6px 14px;"
        "  border-radius: 5px;"
        "  border: none;"
        "  min-width: 70px;"
        "}"
        "QPushButton:hover {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #FFB74D, stop:1 #FF9800);"
        "}"
        "QPushButton:pressed {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #EF6C00, stop:1 #E65100);"
        "}"
        "QPushButton:disabled {"
        "  background: #FFCC80;"
        "  color: #666;"
        "}"
    );
    removeActionButton->setEnabled(false);
    group1Layout->addWidget(removeActionButton);
    connect(removeActionButton, &QPushButton::clicked, this, &MainWindow::onRemoveActionClicked);

    clearActionsButton = new QPushButton("🗑️ 清空", buttonGroup1);
    clearActionsButton->setToolTip("清空所有动作");
    clearActionsButton->setStyleSheet(
        "QPushButton {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #F44336, stop:1 #D32F2F);"
        "  color: white;"
        "  font-size: 11px;"
        "  font-weight: 600;"
        "  padding: 6px 14px;"
        "  border-radius: 5px;"
        "  border: none;"
        "  min-width: 70px;"
        "}"
        "QPushButton:hover {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #EF5350, stop:1 #E53935);"
        "}"
        "QPushButton:pressed {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #C62828, stop:1 #B71C1C);"
        "}"
    );
    group1Layout->addWidget(clearActionsButton);
    connect(clearActionsButton, &QPushButton::clicked, this, &MainWindow::onClearActionsClicked);

    buttonRow1Layout->addWidget(buttonGroup1, 1);

    // 按钮组2 - 文件操作
    QGroupBox *buttonGroup2 = new QGroupBox("文件", sequenceGroup);
    buttonGroup2->setStyleSheet(
        "QGroupBox {"
        "  font-weight: normal;"
        "  font-size: 11px;"
        "  border: 1px solid #e0e0e0;"
        "  border-radius: 5px;"
        "  margin-top: 6px;"
        "}"
        "QGroupBox::title {"
        "  subcontrol-origin: margin;"
        "  left: 8px;"
        "  padding: 0 4px;"
        "  color: #666;"
        "}"
    );

    QHBoxLayout *group2Layout = new QHBoxLayout(buttonGroup2);
    group2Layout->setSpacing(6);
    group2Layout->setContentsMargins(6, 6, 6, 6);

    importActionsButton = new QPushButton("📥 导入", buttonGroup2);
    importActionsButton->setToolTip("从JSON文件导入动作序列");
    importActionsButton->setStyleSheet(
        "QPushButton {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #673AB7, stop:1 #5E35B1);"
        "  color: white;"
        "  font-size: 11px;"
        "  font-weight: 600;"
        "  padding: 6px 14px;"
        "  border-radius: 5px;"
        "  border: none;"
        "  min-width: 70px;"
        "}"
        "QPushButton:hover {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #7E57C2, stop:1 #673AB7);"
        "}"
        "QPushButton:pressed {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #512DA8, stop:1 #4527A0);"
        "}"
    );
    group2Layout->addWidget(importActionsButton);
    connect(importActionsButton, &QPushButton::clicked, this, &MainWindow::onImportActionsClicked);

    exportActionsButton = new QPushButton("📤 导出", buttonGroup2);
    exportActionsButton->setToolTip("将动作序列导出为JSON文件");
    exportActionsButton->setStyleSheet(
        "QPushButton {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #009688, stop:1 #00897B);"
        "  color: white;"
        "  font-size: 11px;"
        "  font-weight: 600;"
        "  padding: 6px 14px;"
        "  border-radius: 5px;"
        "  border: none;"
        "  min-width: 70px;"
        "}"
        "QPushButton:hover {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #26A69A, stop:1 #009688);"
        "}"
        "QPushButton:pressed {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #00695C, stop:1 #004D40);"
        "}"
    );
    group2Layout->addWidget(exportActionsButton);
    connect(exportActionsButton, &QPushButton::clicked, this, &MainWindow::onExportActionsClicked);

    buttonRow1Layout->addWidget(buttonGroup2, 1);

    sequenceLayout->addLayout(buttonRow1Layout);

    // 第二行:执行、重复执行、停止
    QHBoxLayout *buttonRow2Layout = new QHBoxLayout();
    buttonRow2Layout->setSpacing(6);

    // 按钮组3 - 执行控制
    QGroupBox *buttonGroup3 = new QGroupBox("执行控制", sequenceGroup);
    buttonGroup3->setStyleSheet(
        "QGroupBox {"
        "  font-weight: normal;"
        "  font-size: 11px;"
        "  border: 1px solid #e0e0e0;"
        "  border-radius: 5px;"
        "  margin-top: 6px;"
        "}"
        "QGroupBox::title {"
        "  subcontrol-origin: margin;"
        "  left: 8px;"
        "  padding: 0 4px;"
        "  color: #666;"
        "}"
    );

    QHBoxLayout *group3Layout = new QHBoxLayout(buttonGroup3);
    group3Layout->setSpacing(6);
    group3Layout->setContentsMargins(6, 6, 6, 6);

    executeSequenceButton = new QPushButton("▶️ 执行", buttonGroup3);
    executeSequenceButton->setToolTip("执行动作序列一次\n快捷键: Ctrl+S");
    executeSequenceButton->setStyleSheet(
        "QPushButton {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #2196F3, stop:1 #1976D2);"
        "  color: white;"
        "  font-size: 11px;"
        "  font-weight: 600;"
        "  padding: 8px 16px;"  // 减小内边距
        "  border-radius: 5px;"
        "  border: none;"
        "  min-width: 80px;"  // 减小最小宽度
        "}"
        "QPushButton:hover {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #42A5F5, stop:1 #2196F3);"
        "}"
        "QPushButton:pressed {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #1565C0, stop:1 #0D47A1);"
        "}"
        "QPushButton:disabled {"
        "  background: #BDBDBD;"
        "  color: #757575;"
        "}"
    );
    group3Layout->addWidget(executeSequenceButton);
    connect(executeSequenceButton, &QPushButton::clicked, this, &MainWindow::onExecuteSequenceClicked);

    repeatSequenceButton = new QPushButton("🔁 重复执行", buttonGroup3);
    repeatSequenceButton->setToolTip("重复执行动作序列\n快捷键: Ctrl+R");
    repeatSequenceButton->setStyleSheet(
        "QPushButton {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #9C27B0, stop:1 #7B1FA2);"
        "  color: white;"
        "  font-size: 11px;"
        "  font-weight: 600;"
        "  padding: 8px 16px;"
        "  border-radius: 5px;"
        "  border: none;"
        "  min-width: 90px;"  // 减小最小宽度
        "}"
        "QPushButton:hover {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #AB47BC, stop:1 #8E24AA);"
        "}"
        "QPushButton:pressed {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #6A1B9A, stop:1 #4A148C);"
        "}"
        "QPushButton:disabled {"
        "  background: #CE93D8;"
        "  color: #757575;"
        "}"
    );
    group3Layout->addWidget(repeatSequenceButton);
    connect(repeatSequenceButton, &QPushButton::clicked, this, &MainWindow::onRepeatSequenceClicked);

    stopSequenceButton = new QPushButton("⏹️ 停止", buttonGroup3);
    stopSequenceButton->setToolTip("停止正在执行的序列\n快捷键: Ctrl+C 或 Esc");
    stopSequenceButton->setStyleSheet(
        "QPushButton {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #757575, stop:1 #616161);"
        "  color: white;"
        "  font-size: 11px;"
        "  font-weight: 600;"
        "  padding: 8px 16px;"
        "  border-radius: 5px;"
        "  border: none;"
        "  min-width: 80px;"
        "}"
        "QPushButton:hover {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #9E9E9E, stop:1 #757575);"
        "}"
        "QPushButton:pressed {"
        "  background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "                stop:0 #424242, stop:1 #212121);"
        "}"
        "QPushButton:disabled {"
        "  background: #E0E0E0;"
        "  color: #9E9E9E;"
        "}"
    );
    stopSequenceButton->setEnabled(false);
    group3Layout->addWidget(stopSequenceButton);
    connect(stopSequenceButton, &QPushButton::clicked, this, &MainWindow::onStopSequenceClicked);

    buttonRow2Layout->addWidget(buttonGroup3);
    sequenceLayout->addLayout(buttonRow2Layout);

    mainLayout->addWidget(sequenceGroup, 1);

    // ========== 进度显示区域 ==========
    QHBoxLayout *progressLayout = new QHBoxLayout();

    progressLabel = new QLabel("就绪", centralWidget);
    progressLabel->setAlignment(Qt::AlignLeft);
    progressLabel->setStyleSheet(
        "QLabel {"
        "  color: #333;"
        "  padding: 6px;"  // 减小内边距
        "  min-height: 22px;"  // 减小最小高度
        "  font-size: 12px;"
        "  font-weight: 500;"
        "}"
    );

    progressBar = new QProgressBar(centralWidget);
    progressBar->setRange(0, 100);
    progressBar->setValue(0);
    progressBar->setTextVisible(true);
    progressBar->setFormat("%p%");
    progressBar->setStyleSheet(
        "QProgressBar {"
        "  border: 1px solid #ddd;"
        "  border-radius: 6px;"
        "  text-align: center;"
        "  height: 22px;"  // 减小高度
        "  font-size: 11px;"
        "  font-weight: 500;"
        "}"
        "QProgressBar::chunk {"
        "  background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
        "                stop:0 #4CAF50, stop:1 #2E7D32);"
        "  border-radius: 5px;"
        "  border: none;"
        "}"
    );

    progressLayout->addWidget(progressLabel, 1);
    progressLayout->addWidget(progressBar, 2);
    mainLayout->addLayout(progressLayout);

    // ========== 状态显示 ==========
    statusLabel = new QLabel("✅ 就绪 - 欢迎使用智能鼠标点击器 v3.0!", centralWidget);
    statusLabel->setAlignment(Qt::AlignCenter);
    statusLabel->setStyleSheet(
        "QLabel {"
        "  background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
        "                stop:0 #e8f5e9, stop:1 #c8e6c9);"
        "  color: #2e7d32;"
        "  border: 2px solid #a5d6a7;"
        "  padding: 6px;"  // 减小内边距
        "  border-radius: 6px;"
        "  font-weight: 600;"
        "  font-size: 11px;"
        "}"
    );
    mainLayout->addWidget(statusLabel);

    mainLayout->addStretch();

    // ========== 初始化定时器 ==========
    repeatTimer = new QTimer(this);
    connect(repeatTimer, &QTimer::timeout, this, &MainWindow::onRepeatTimeout);

    sequenceTimer = new QTimer(this);
    sequenceTimer->setSingleShot(true);
    connect(sequenceTimer, &QTimer::timeout, this, &MainWindow::onSequenceTimeout);

    countdownTimer = new QTimer(this);
    countdownTimer->setInterval(1000);
    connect(countdownTimer, &QTimer::timeout, this, &MainWindow::onCountdownTimeout);

    timeUpdateTimer = new QTimer(this);
    timeUpdateTimer->setInterval(1000);
    connect(timeUpdateTimer, &QTimer::timeout, this, &MainWindow::updateTimeDisplay);

    // 坐标标记窗口
    coordinateMarker = new CoordinateMarker();
    markerTimer = new QTimer(this);
    markerTimer->setSingleShot(true);
    connect(markerTimer, &QTimer::timeout, this, &MainWindow::hideCoordinateMarker);

    // 定时更新光标位置
    QTimer *cursorTimer = new QTimer(this);
    connect(cursorTimer, &QTimer::timeout, [this]() {
        POINT cursorPos;
        GetCursorPos(&cursorPos);
        cursorLabel->setText(QString("🖱️ 光标位置: (%1, %2)").arg(cursorPos.x).arg(cursorPos.y));
    });
    cursorTimer->start(100);

    // 创建表格右键菜单
    createTableContextMenu();

    // 设置快捷键
    setupShortcuts();

    // 加载保存的设置
    loadSettings();
}

MainWindow::~MainWindow()
{
    // 保存设置
    saveSettings();

    if (hotkeyRegistered) {
        UnregisterHotKey((HWND)winId(), HOTKEY_ID);
    }

    if (tableContextMenu) {
        delete tableContextMenu;
    }

    if (coordinateMarker) {
        delete coordinateMarker;
    }
}

// 保存设置
void MainWindow::saveSettings()
{
    QSettings settings("SmartClicker", "MouseClicker");

    // 保存窗口位置和大小
    settings.setValue("window/geometry", saveGeometry());

    // 保存基础设置
    settings.setValue("basic/x", xSpinBox->value());
    settings.setValue("basic/y", ySpinBox->value());
    settings.setValue("basic/delay", delaySpinBox->value());
    settings.setValue("basic/countdown", countdownSpinBox->value());
    settings.setValue("basic/leftButton", leftButtonCheck->isChecked());
    settings.setValue("basic/doubleClick", doubleClickCheck->isChecked());
    settings.setValue("basic/repeatEnabled", repeatCheckBox->isChecked());
    settings.setValue("basic/repeatCount", repeatCountSpinBox->value());
    settings.setValue("basic/infiniteRepeat", infiniteRepeatCheck->isChecked());
    settings.setValue("basic/repeatMode", repeatModeCombo->currentIndex());
    settings.setValue("basic/hours", hoursSpinBox->value());
    settings.setValue("basic/minutes", minutesSpinBox->value());
    settings.setValue("basic/seconds", secondsSpinBox->value());

    // 保存序列设置
    settings.setValue("sequence/repeatCount", sequenceRepeatSpinBox->value());
    settings.setValue("sequence/infiniteRepeat", infiniteSequenceRepeatCheck->isChecked());
}

// 加载设置
void MainWindow::loadSettings()
{
    QSettings settings("SmartClicker", "MouseClicker");

    // 恢复窗口位置和大小
    restoreGeometry(settings.value("window/geometry").toByteArray());

    // 恢复基础设置
    xSpinBox->setValue(settings.value("basic/x", 100).toInt());
    ySpinBox->setValue(settings.value("basic/y", 100).toInt());
    delaySpinBox->setValue(settings.value("basic/delay", 1.0).toDouble());
    countdownSpinBox->setValue(settings.value("basic/countdown", 3).toInt());
    leftButtonCheck->setChecked(settings.value("basic/leftButton", true).toBool());
    doubleClickCheck->setChecked(settings.value("basic/doubleClick", false).toBool());
    repeatCheckBox->setChecked(settings.value("basic/repeatEnabled", false).toBool());
    repeatCountSpinBox->setValue(settings.value("basic/repeatCount", 10).toInt());
    infiniteRepeatCheck->setChecked(settings.value("basic/infiniteRepeat", false).toBool());
    repeatModeCombo->setCurrentIndex(settings.value("basic/repeatMode", 0).toInt());
    hoursSpinBox->setValue(settings.value("basic/hours", 0).toInt());
    minutesSpinBox->setValue(settings.value("basic/minutes", 1).toInt());
    secondsSpinBox->setValue(settings.value("basic/seconds", 0).toInt());

    // 恢复序列设置
    sequenceRepeatSpinBox->setValue(settings.value("sequence/repeatCount", 1).toInt());
    infiniteSequenceRepeatCheck->setChecked(settings.value("sequence/infiniteRepeat", false).toBool());

    // 更新按钮状态
    onRepeatStateChanged(repeatCheckBox->isChecked() ? Qt::Checked : Qt::Unchecked);
    onRepeatModeChanged();  // 更新显示
}

// 创建表格右键菜单
void MainWindow::createTableContextMenu()
{
    tableContextMenu = new QMenu(this);

    QAction *insertAction = new QAction("📝 插入动作", this);
    insertAction->setToolTip("在当前选中行之前插入新动作");
    connect(insertAction, &QAction::triggered, this, &MainWindow::onInsertAction);

    QAction *duplicateAction = new QAction("📋 复制动作", this);
    duplicateAction->setToolTip("复制选中的动作");
    connect(duplicateAction, &QAction::triggered, this, &MainWindow::onDuplicateAction);

    QAction *moveUpAction = new QAction("⬆️ 上移", this);
    moveUpAction->setToolTip("将选中的动作上移一位");
    connect(moveUpAction, &QAction::triggered, this, &MainWindow::onMoveActionUp);

    QAction *moveDownAction = new QAction("⬇️ 下移", this);
    moveDownAction->setToolTip("将选中的动作下移一位");
    connect(moveDownAction, &QAction::triggered, this, &MainWindow::onMoveActionDown);

    tableContextMenu->addAction(insertAction);
    tableContextMenu->addAction(duplicateAction);
    tableContextMenu->addSeparator();
    tableContextMenu->addAction(moveUpAction);
    tableContextMenu->addAction(moveDownAction);
}

// 表格右键菜单事件
void MainWindow::onTableContextMenu(const QPoint &pos)
{
    QTableWidgetItem *item = actionTable->itemAt(pos);
    if (item) {
        tableContextMenu->exec(actionTable->viewport()->mapToGlobal(pos));
    }
}

// 插入动作
void MainWindow::onInsertAction()
{
    int currentRow = actionTable->currentRow();
    if (currentRow < 0) return;

    int x = xSpinBox->value();
    int y = ySpinBox->value();
    double delaySeconds = delaySpinBox->value();
    bool leftButton = leftButtonCheck->isChecked();
    bool doubleClick = doubleClickCheck->isChecked();

    ClickAction newAction(nextActionId++, x, y, delaySeconds, leftButton, doubleClick);
    actionList.insert(actionList.begin() + currentRow, newAction);
    updateActionTable();

    showStatusMessage(QString("✅ 已在位置 %1 插入动作 %2").arg(currentRow + 1).arg(newAction.id), false, true);
}

// 复制动作
void MainWindow::onDuplicateAction()
{
    int currentRow = actionTable->currentRow();
    if (currentRow < 0) return;

    if (currentRow >= 0 && currentRow < (int)actionList.size()) {
        ClickAction original = actionList[currentRow];
        ClickAction duplicate(nextActionId++, original.x, original.y, original.delay,
                             original.leftButton, original.doubleClick);

        actionList.insert(actionList.begin() + currentRow + 1, duplicate);
        updateActionTable();

        showStatusMessage(QString("✅ 已复制动作 %1 为动作 %2").arg(original.id).arg(duplicate.id), false, true);
    }
}

// 上移动作
void MainWindow::onMoveActionUp()
{
    int currentRow = actionTable->currentRow();
    if (currentRow > 0 && currentRow < (int)actionList.size()) {
        std::swap(actionList[currentRow], actionList[currentRow - 1]);
        updateActionTable();
        actionTable->selectRow(currentRow - 1);
        showStatusMessage(QString("✅ 已将动作上移一位"), false, true);
    }
}

// 下移动作
void MainWindow::onMoveActionDown()
{
    int currentRow = actionTable->currentRow();
    if (currentRow >= 0 && currentRow < (int)actionList.size() - 1) {
        std::swap(actionList[currentRow], actionList[currentRow + 1]);
        updateActionTable();
        actionTable->selectRow(currentRow + 1);
        showStatusMessage(QString("✅ 已将动作下移一位"), false, true);
    }
}

// 显示坐标标记
void MainWindow::showCoordinateMarker(int x, int y)
{
    coordinateMarker->setPosition(x, y);
    coordinateMarker->show();
    coordinateMarker->raise();

    // 3秒后自动隐藏
    markerTimer->start(3000);
}

// 隐藏坐标标记
void MainWindow::hideCoordinateMarker()
{
    coordinateMarker->hide();
}

// 高亮表格行
void MainWindow::highlightTableRow(int row)
{
    if (row < 0 || row >= actionTable->rowCount()) return;

    // 清除之前的高亮
    for (int i = 0; i < actionTable->rowCount(); ++i) {
        for (int j = 0; j < actionTable->columnCount(); ++j) {
            QTableWidgetItem *item = actionTable->item(i, j);
            if (item) {
                item->setBackground(QBrush());
                item->setForeground(QBrush());
                item->setFont(QFont());
            }
        }
    }

    // 高亮当前行
    for (int j = 0; j < actionTable->columnCount(); ++j) {
        QTableWidgetItem *item = actionTable->item(row, j);
        if (item) {
            item->setBackground(QColor(255, 235, 180));
            item->setForeground(QColor(102, 60, 0));
            item->setFont(QFont("", -1, QFont::Bold));
        }
    }

    actionTable->scrollToItem(actionTable->item(row, 0), QAbstractItemView::EnsureVisible);
}

// 表格单元格点击事件
void MainWindow::onActionTableCellClicked(int row, int column)
{
    Q_UNUSED(column);
    if (row >= 0 && row < (int)actionList.size()) {
        const ClickAction& action = actionList[row];

        // 在状态栏显示详细信息
        QString buttonText = action.leftButton ? "左键" : "右键";
        QString clickType = action.doubleClick ? "双击" : "单击";
        showStatusMessage(QString("📊 选中动作 %1: (%2, %3) | %4 %5 | 延迟: %6秒")
                         .arg(action.id)
                         .arg(action.x)
                         .arg(action.y)
                         .arg(buttonText)
                         .arg(clickType)
                         .arg(QString::number(action.delay, 'f', 3)), false, true);

        // 高亮当前行
        highlightTableRow(row);
    }
}

// 表格当前单元格改变事件
void MainWindow::onActionTableCurrentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)
{
    Q_UNUSED(currentColumn);
    Q_UNUSED(previousRow);
    Q_UNUSED(previousColumn);

    if (currentRow >= 0 && currentRow < (int)actionList.size()) {
        const ClickAction& action = actionList[currentRow];

        if (currentColumn <= 2) {
            // 显示坐标标记
            showCoordinateMarker(action.x, action.y);
        }


        // 更新基础设置区域的值为当前选中的动作
        xSpinBox->setValue(action.x);
        ySpinBox->setValue(action.y);
        delaySpinBox->setValue(action.delay);
        leftButtonCheck->setChecked(action.leftButton);
        doubleClickCheck->setChecked(action.doubleClick);
    }
}

void MainWindow::registerGlobalHotkey()
{
    if (!hotkeyRegistered) {
        if (RegisterHotKey((HWND)winId(), HOTKEY_ID, MOD_CONTROL, 'C')) {
            hotkeyRegistered = true;
            qDebug() << "全局热键 Ctrl+C 已注册";
        } else {
            qDebug() << "全局热键注册失败";
        }
    }
}

void MainWindow::unregisterGlobalHotkey()
{
    if (hotkeyRegistered) {
        UnregisterHotKey((HWND)winId(), HOTKEY_ID);
        hotkeyRegistered = false;
        qDebug() << "全局热键 Ctrl+C 已注销";
    }
}

void MainWindow::resetSequenceExecution()
{
    currentActionIndex = 0;
    currentSequenceRepeat = 0;
    isSequenceRunning = false;
    isRepeatingSequence = false;
    isInfiniteSequenceRepeat = false;
    stopRequested = false;
}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    QMainWindow::resizeEvent(event);
    int tableHeight = actionTable->height();
    int rowCount = actionTable->rowCount();
    if (rowCount > 0) {
        int suggestedRowHeight = qMin(40, qMax(30, tableHeight / qMax(1, rowCount) - 2));
        actionTable->verticalHeader()->setDefaultSectionSize(suggestedRowHeight);
    }
}

bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
    MSG* msg = static_cast<MSG*>(message);
    if (msg->message == WM_HOTKEY) {
        if (msg->wParam == HOTKEY_ID) {
            stopRequested = true;
            if (isSequenceRunning) {
                sequenceTimer->stop();
                countdownTimer->stop();
                timeUpdateTimer->stop();
                isSequenceRunning = false;
                isRepeatingSequence = false;
                isInfiniteSequenceRepeat = false;
                clickButton->setEnabled(true);
                executeSequenceButton->setEnabled(true);
                repeatSequenceButton->setEnabled(true);
                stopSequenceButton->setEnabled(false);
                addActionButton->setEnabled(true);
                removeActionButton->setEnabled(actionTable->currentRow() >= 0);
                clearActionsButton->setEnabled(true);
                importActionsButton->setEnabled(true);
                exportActionsButton->setEnabled(true);
                showStatusMessage("⏹️ 动作序列已通过全局快捷键 Ctrl+C 停止", false, true);
                unregisterGlobalHotkey();
                resetSequenceExecution();
                activateAndShowWindow();
            }
            if (isRepeating) {
                isRepeating = false;
                repeatTimer->stop();
                timeUpdateTimer->stop();
                if (repeatCheckBox->isChecked()) {
                    clickButton->setText("🎯 开始重复点击");
                } else {
                    clickButton->setText("🎯 立即点击");
                }
                executeSequenceButton->setEnabled(true);
                repeatSequenceButton->setEnabled(true);
                importActionsButton->setEnabled(true);
                exportActionsButton->setEnabled(true);
                showStatusMessage("⏹️ 重复点击已通过全局快捷键 Ctrl+C 停止", false, true);
                unregisterGlobalHotkey();
                activateAndShowWindow();
            }
            return true;
        }
    }
    return QMainWindow::nativeEvent(eventType, message, result);
}

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
        if (keyEvent->key() == Qt::Key_Space && !keyEvent->isAutoRepeat()) {
            POINT cursorPos;
            GetCursorPos(&cursorPos);
            xSpinBox->setValue(cursorPos.x);
            ySpinBox->setValue(cursorPos.y);
            showStatusMessage(QString("🎯 坐标已拾取: (%1, %2)").arg(cursorPos.x).arg(cursorPos.y), false, true);
            return true;
        }
        if (keyEvent->key() == Qt::Key_Escape && !keyEvent->isAutoRepeat()) {
            if (isSequenceRunning || isRepeating) {
                onStopSequenceClicked();
                return true;
            }
        }
    }
    return QMainWindow::eventFilter(obj, event);
}

void MainWindow::setupShortcuts()
{
    QShortcut *shortcutStartStop = new QShortcut(QKeySequence("Ctrl+S"), this);
    connect(shortcutStartStop, &QShortcut::activated, [this]() {
        if (isSequenceRunning) {
            onStopSequenceClicked();
        } else {
            if (actionList.empty()) {
                onClickButtonClicked();
            } else {
                onExecuteSequenceClicked();
            }
        }
    });

    QShortcut *shortcutRepeat = new QShortcut(QKeySequence("Ctrl+R"), this);
    connect(shortcutRepeat, &QShortcut::activated, this, &MainWindow::onRepeatSequenceClicked);

    QShortcut *shortcutAdd = new QShortcut(QKeySequence("Ctrl+A"), this);
    connect(shortcutAdd, &QShortcut::activated, this, &MainWindow::onAddActionClicked);

    QShortcut *shortcutDelete = new QShortcut(QKeySequence("Ctrl+D"), this);
    connect(shortcutDelete, &QShortcut::activated, this, &MainWindow::onRemoveActionClicked);

    QShortcut *shortcutEsc = new QShortcut(QKeySequence("Esc"), this);
    connect(shortcutEsc, &QShortcut::activated, [this]() {
        if (isSequenceRunning || isRepeating) {
            onStopSequenceClicked();
        }
    });

    // 新增快捷键:Ctrl+I 插入动作,Ctrl+U 上移,Ctrl+J 下移
    QShortcut *shortcutInsert = new QShortcut(QKeySequence("Ctrl+I"), this);
    connect(shortcutInsert, &QShortcut::activated, this, &MainWindow::onInsertAction);

    QShortcut *shortcutMoveUp = new QShortcut(QKeySequence("Ctrl+Up"), this);
    connect(shortcutMoveUp, &QShortcut::activated, this, &MainWindow::onMoveActionUp);

    QShortcut *shortcutMoveDown = new QShortcut(QKeySequence("Ctrl+Down"), this);
    connect(shortcutMoveDown, &QShortcut::activated, this, &MainWindow::onMoveActionDown);
}

void MainWindow::activateAndShowWindow()
{
    if (isMinimized()) {
        showNormal();
    }
    activateWindow();
    raise();
    setWindowState((windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
}

void MainWindow::showStatusMessage(const QString& message, bool isError, bool isSuccess)
{
    if (isError) {
        statusLabel->setStyleSheet(
            "QLabel {"
            "  background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
            "                stop:0 #ffebee, stop:1 #ffcdd2);"
            "  color: #c62828;"
            "  border: 2px solid #ffcdd2;"
            "  padding: 8px;"  // 减小内边距
            "  border-radius: 6px;"
            "  font-weight: 600;"
            "  font-size: 12px;"
            "}"
        );
    } else if (isSuccess) {
        statusLabel->setStyleSheet(
            "QLabel {"
            "  background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
            "                stop:0 #e8f5e9, stop:1 #c8e6c9);"
            "  color: #2e7d32;"
            "  border: 2px solid #a5d6a7;"
            "  padding: 8px;"
            "  border-radius: 6px;"
            "  font-weight: 600;"
            "  font-size: 12px;"
            "}"
        );
    } else {
        statusLabel->setStyleSheet(
            "QLabel {"
            "  background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
            "                stop:0 #e3f2fd, stop:1 #bbdefb);"
            "  color: #1565c0;"
            "  border: 2px solid #bbdefb;"
            "  padding: 8px;"
            "  border-radius: 6px;"
            "  font-weight: 600;"
            "  font-size: 12px;"
            "}"
        );
    }
    statusLabel->setText(message);
}

void MainWindow::updateProgressInfo()
{
    if (isSequenceRunning) {
        if (actionList.empty()) {
            progressLabel->setText("就绪");
            progressBar->setValue(0);
            return;
        }
        int totalActions = actionList.size();
        int currentProgress = 0;
        QString progressText;
        if (isRepeatingSequence) {
            if (isInfiniteSequenceRepeat) {
                progressText = QString("🔁 无限重复执行: 第 %1 次 | 动作: %2/%3")
                              .arg(currentSequenceRepeat)
                              .arg(currentActionIndex + 1)
                              .arg(totalActions);
                currentProgress = 0;
            } else {
                int totalSteps = totalActions * totalSequenceRepeat;
                int completedSteps = (currentSequenceRepeat - 1) * totalActions + currentActionIndex;
                currentProgress = (totalSteps > 0) ? (completedSteps * 100 / totalSteps) : 0;
                progressText = QString("🔁 重复执行: 第 %1/%2 次 | 动作: %3/%4")
                              .arg(currentSequenceRepeat)
                              .arg(totalSequenceRepeat)
                              .arg(currentActionIndex + 1)
                              .arg(totalActions);
            }
        } else {
            currentProgress = (totalActions > 0) ? ((currentActionIndex * 100) / totalActions) : 0;
            progressText = QString("▶️ 执行序列: 动作 %1/%2")
                          .arg(currentActionIndex + 1)
                          .arg(totalActions);
        }
        progressLabel->setText(progressText);
        progressBar->setValue(currentProgress);
    } else if (isRepeating) {
        QString progressText;
        int currentProgress = 0;

        if (repeatModeCombo->currentIndex() == 1) {
            // 按时间重复
            if (infiniteRepeatCheck->isChecked()) {
                progressText = QString("🔁 重复点击: 已运行 %1 | 无限循环")
                              .arg(formatTime(elapsedTime));
                currentProgress = 0;
            } else {
                currentProgress = (totalRepeatTime > 0) ? (elapsedTime * 100 / totalRepeatTime) : 0;
                if (currentProgress > 100) currentProgress = 100;
                progressText = QString("🔁 重复点击: %1/%2")
                              .arg(formatTime(elapsedTime))
                              .arg(formatTime(totalRepeatTime));
            }
        } else {
            // 按次数重复
            if (infiniteRepeatCheck->isChecked()) {
                int completed = totalRepeatCount - currentRepeatCount;
                progressText = QString("🔁 重复点击: 第 %1 次 (无限循环)").arg(completed + 1);
                currentProgress = 0;
            } else {
                int completed = totalRepeatCount - currentRepeatCount;
                currentProgress = (totalRepeatCount > 0) ? (completed * 100 / totalRepeatCount) : 0;
                progressText = QString("🔁 重复点击: %1/%2 次").arg(completed + 1).arg(totalRepeatCount);
            }
        }
        progressLabel->setText(progressText);
        progressBar->setValue(currentProgress);
    } else {
        progressLabel->setText("就绪");
        progressBar->setValue(0);
    }
}

// 格式化时间显示
QString MainWindow::formatTime(int seconds)
{
    int hours = seconds / 3600;
    int minutes = (seconds % 3600) / 60;
    int secs = seconds % 60;

    if (hours > 0) {
        return QString("%1:%2:%3").arg(hours, 2, 10, QChar('0'))
                                 .arg(minutes, 2, 10, QChar('0'))
                                 .arg(secs, 2, 10, QChar('0'));
    } else if (minutes > 0) {
        return QString("%1:%2").arg(minutes, 2, 10, QChar('0'))
                              .arg(secs, 2, 10, QChar('0'));
    } else {
        return QString("%1秒").arg(secs);
    }
}

// 更新时间显示
void MainWindow::updateTimeDisplay()
{
    if (isRepeating && repeatModeCombo->currentIndex() == 1) {
        elapsedTime++;
        updateProgressInfo();

        // 检查是否达到时间限制
        if (!infiniteRepeatCheck->isChecked() && elapsedTime >= totalRepeatTime) {
            isRepeating = false;
            repeatTimer->stop();
            timeUpdateTimer->stop();
            clickButton->setText("🎯 开始重复点击");
            showStatusMessage(QString("✅ 重复点击完成,共运行 %1").arg(formatTime(totalRepeatTime)), false, true);
            executeSequenceButton->setEnabled(true);
            repeatSequenceButton->setEnabled(true);
            importActionsButton->setEnabled(true);
            exportActionsButton->setEnabled(true);
            progressBar->setValue(100);
            progressLabel->setText("完成");
            unregisterGlobalHotkey();
            activateAndShowWindow();
        }
    }
}

void MainWindow::startCountdown(int seconds)
{
    countdownSeconds = seconds;
    QString modeText;
    if (isRepeatingSequence) {
        if (isInfiniteSequenceRepeat) {
            modeText = "无限重复执行序列";
        } else {
            modeText = QString("重复执行序列 (%1次)").arg(totalSequenceRepeat);
        }
    } else {
        modeText = "执行序列";
    }
    if (countdownSeconds > 0) {
        showStatusMessage(QString("⏱️ 倒计时: %1 秒后开始%2...").arg(countdownSeconds).arg(modeText));
        countdownTimer->start();
    } else {
        onCountdownTimeout();
    }
}

int MainWindow::delayToMilliseconds(double seconds)
{
    return static_cast<int>(seconds * 1000);
}

int MainWindow::timeToSeconds(int hours, int minutes, int seconds)
{
    return hours * 3600 + minutes * 60 + seconds;
}

void MainWindow::startSequenceExecution(bool repeatMode)
{
    if (actionList.empty()) {
        showStatusMessage("⚠️ 动作列表为空,请先添加动作", true);
        QMessageBox::warning(this, "警告", "动作列表为空,请先添加动作!");
        return;
    }
    if (isRepeating) {
        isRepeating = false;
        repeatTimer->stop();
        timeUpdateTimer->stop();
        clickButton->setText("🎯 开始重复点击");
        showStatusMessage("⏹️ 重复点击已停止", false, true);
        unregisterGlobalHotkey();
    }
    resetSequenceExecution();
    isRepeatingSequence = repeatMode;
    isInfiniteSequenceRepeat = infiniteSequenceRepeatCheck->isChecked();
    if (isRepeatingSequence) {
        if (isInfiniteSequenceRepeat) {
            totalSequenceRepeat = 0;
        } else {
            totalSequenceRepeat = sequenceRepeatSpinBox->value();
        }
        currentSequenceRepeat = 1;
    } else {
        totalSequenceRepeat = 1;
        currentSequenceRepeat = 1;
        isInfiniteSequenceRepeat = false;
    }
    clickButton->setEnabled(false);
    executeSequenceButton->setEnabled(false);
    repeatSequenceButton->setEnabled(false);
    stopSequenceButton->setEnabled(true);
    addActionButton->setEnabled(false);
    removeActionButton->setEnabled(false);
    clearActionsButton->setEnabled(false);
    sequenceRepeatSpinBox->setEnabled(false);
    infiniteSequenceRepeatCheck->setEnabled(false);
    importActionsButton->setEnabled(false);
    exportActionsButton->setEnabled(false);
    registerGlobalHotkey();
    int countdownTime = countdownSpinBox->value();
    startCountdown(countdownTime);
    isSequenceRunning = true;
    stopRequested = false;
    updateProgressInfo();
}

void MainWindow::clickAt(int x, int y, bool leftButton, bool doubleClick)
{
    POINT originalPos;
    GetCursorPos(&originalPos);
    moveMouseTo(x, y);
    if (doubleClick) {
        sendMouseClick(x, y, leftButton, true);
        sendMouseClick(x, y, leftButton, false);
        Sleep(50);
        sendMouseClick(x, y, leftButton, true);
        sendMouseClick(x, y, leftButton, false);
    } else {
        sendMouseClick(x, y, leftButton, true);
        sendMouseClick(x, y, leftButton, false);
    }
    // 移动回原始位置
    moveMouseTo(originalPos.x, originalPos.y);
}

void MainWindow::clickAction(const ClickAction& action)
{
    QString modeText = isRepeatingSequence ? "重复执行中" : "执行中";
    QString buttonText = action.leftButton ? "左键" : "右键";
    QString clickType = action.doubleClick ? "双击" : "单击";
    showStatusMessage(QString("%1 - 动作 %2: (%3, %4) | %5 %6 | 延迟: %7秒")
                     .arg(modeText)
                     .arg(action.id)
                     .arg(action.x)
                     .arg(action.y)
                     .arg(buttonText)
                     .arg(clickType)
                     .arg(QString::number(action.delay, 'f', 3)));
    clickAt(action.x, action.y, action.leftButton, action.doubleClick);
    updateProgressInfo();
}

void MainWindow::moveMouseTo(int x, int y)
{
    INPUT input = {0};
    input.type = INPUT_MOUSE;
    input.mi.dx = x * (65535.0f / GetSystemMetrics(SM_CXSCREEN));
    input.mi.dy = y * (65535.0f / GetSystemMetrics(SM_CYSCREEN));
    input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
    SendInput(1, &input, sizeof(INPUT));
}

void MainWindow::sendMouseClick(int x, int y, bool leftButton, bool down)
{
    Q_UNUSED(x);
    Q_UNUSED(y);

    INPUT input = {0};
    input.type = INPUT_MOUSE;
    if (leftButton) {
        if (down) {
            input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
        } else {
            input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
        }
    } else {
        if (down) {
            input.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
        } else {
            input.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
        }
    }
    SendInput(1, &input, sizeof(INPUT));
}

void MainWindow::addActionToList(const ClickAction& action)
{
    actionList.push_back(action);
    updateActionTable();
}

void MainWindow::updateActionTable()
{
    actionTable->blockSignals(true);
    actionTable->setRowCount(actionList.size());
    for (size_t i = 0; i < actionList.size(); ++i) {
        const ClickAction& action = actionList[i];
        QTableWidgetItem *idItem = new QTableWidgetItem(QString::number(action.id));
        idItem->setFlags(idItem->flags() & ~Qt::ItemIsEditable);
        idItem->setTextAlignment(Qt::AlignCenter);
        idItem->setData(Qt::UserRole, QVariant(action.id));
        idItem->setToolTip(QString("动作 ID: %1\n双击编辑").arg(action.id));
        actionTable->setItem(i, 0, idItem);

        QTableWidgetItem *xItem = new QTableWidgetItem(QString::number(action.x));
        xItem->setTextAlignment(Qt::AlignCenter);
        xItem->setToolTip(QString("X坐标: %1").arg(action.x));
        actionTable->setItem(i, 1, xItem);

        QTableWidgetItem *yItem = new QTableWidgetItem(QString::number(action.y));
        yItem->setTextAlignment(Qt::AlignCenter);
        yItem->setToolTip(QString("Y坐标: %1").arg(action.y));
        actionTable->setItem(i, 2, yItem);

        QTableWidgetItem *delayItem = new QTableWidgetItem(QString::number(action.delay, 'f', 3));
        delayItem->setTextAlignment(Qt::AlignCenter);
        delayItem->setToolTip(QString("延迟: %1 秒").arg(QString::number(action.delay, 'f', 3)));
        actionTable->setItem(i, 3, delayItem);

        QTableWidgetItem *buttonItem = new QTableWidgetItem(action.leftButton ? "左键" : "右键");
        buttonItem->setTextAlignment(Qt::AlignCenter);
        buttonItem->setToolTip(action.leftButton ? "左键点击" : "右键点击");
        actionTable->setItem(i, 4, buttonItem);

        QTableWidgetItem *doubleItem = new QTableWidgetItem(action.doubleClick ? "双击" : "单击");
        doubleItem->setTextAlignment(Qt::AlignCenter);
        doubleItem->setToolTip(action.doubleClick ? "双击操作" : "单击操作");
        actionTable->setItem(i, 5, doubleItem);
    }
    actionTable->blockSignals(false);
    resizeEvent(nullptr);
}

// 保存为JSON格式
bool MainWindow::saveActionsToJson(const QString& filePath)
{
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        return false;
    }

    QJsonArray actionsArray;
    for (const auto& action : actionList) {
        QJsonObject actionObj;
        actionObj["id"] = action.id;
        actionObj["x"] = action.x;
        actionObj["y"] = action.y;
        actionObj["delay"] = QString::number(action.delay, 'f', 3);
        actionObj["button"] = action.leftButton ? "left" : "right";
        actionObj["double_click"] = action.doubleClick;
        actionObj["description"] = action.description;

        actionsArray.append(actionObj);
    }

    QJsonObject rootObj;
    rootObj["app_name"] = "智能鼠标点击器";
    rootObj["version"] = "3.0";
    rootObj["description"] = "鼠标动作序列配置文件";
    rootObj["total_actions"] = static_cast<int>(actionList.size());
    rootObj["export_time"] = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    rootObj["actions"] = actionsArray;

    QJsonDocument doc(rootObj);

    // 使用缩进格式化,便于阅读和编辑
    QByteArray jsonData = doc.toJson(QJsonDocument::Indented);
    file.write(jsonData);
    file.close();

    return true;
}

// 从JSON格式加载
bool MainWindow::loadActionsFromJson(const QString& filePath)
{
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return false;
    }

    QByteArray data = file.readAll();
    file.close();

    QJsonDocument doc = QJsonDocument::fromJson(data);
    if (doc.isNull() || !doc.isObject()) {
        return false;
    }

    QJsonObject rootObj = doc.object();

    // 检查必需字段
    if (!rootObj.contains("actions") || !rootObj["actions"].isArray()) {
        return false;
    }

    QJsonArray actionsArray = rootObj["actions"].toArray();
    std::vector<ClickAction> newActionList;
    int maxId = 0;

    for (int i = 0; i < actionsArray.size(); ++i) {
        QJsonObject actionObj = actionsArray[i].toObject();

        // 检查必需字段
        if (!actionObj.contains("id") || !actionObj.contains("x") ||
            !actionObj.contains("y") || !actionObj.contains("delay") ||
            !actionObj.contains("button") || !actionObj.contains("double_click")) {
            continue;  // 跳过无效的动作
        }

        ClickAction action;
        action.id = actionObj["id"].toInt();

        // 更新最大ID
        if (action.id > maxId) {
            maxId = action.id;
        }

        action.x = actionObj["x"].toInt();
        action.y = actionObj["y"].toInt();

        // 处理延迟时间(支持字符串和数字)
        QJsonValue delayValue = actionObj["delay"];
        if (delayValue.isString()) {
            action.delay = delayValue.toString().toDouble();
        } else {
            action.delay = delayValue.toDouble();
        }

        // 处理按钮类型
        QString buttonType = actionObj["button"].toString().toLower();
        action.leftButton = (buttonType == "left" || buttonType == "左键" || buttonType == "leftbutton");

        // 处理双击
        action.doubleClick = actionObj["double_click"].toBool();

        // 处理描述
        if (actionObj.contains("description")) {
            action.description = actionObj["description"].toString();
        } else {
            action.description = QString("动作 %1: (%2, %3) 延迟: %4秒 %5 %6")
                               .arg(action.id)
                               .arg(action.x)
                               .arg(action.y)
                               .arg(QString::number(action.delay, 'f', 3))
                               .arg(action.leftButton ? "左键" : "右键")
                               .arg(action.doubleClick ? "双击" : "单击");
        }

        newActionList.push_back(action);
    }

    if (!newActionList.empty()) {
        actionList = newActionList;
        nextActionId = maxId + 1;  // 设置下一个ID
        updateActionTable();
        return true;
    }

    return false;
}

// 重复模式改变
void MainWindow::onRepeatModeChanged()
{
    if (repeatModeCombo->currentIndex() == 0) {
        // 按次数重复
        repeatCountSpinBox->setEnabled(!infiniteRepeatCheck->isChecked());
        timeGroup->setVisible(false);
    } else {
        // 按时间重复
        repeatCountSpinBox->setEnabled(false);
        timeGroup->setVisible(true);
        hoursSpinBox->setEnabled(!infiniteRepeatCheck->isChecked());
        minutesSpinBox->setEnabled(!infiniteRepeatCheck->isChecked());
        secondsSpinBox->setEnabled(!infiniteRepeatCheck->isChecked());
    }
}

void MainWindow::onRepeatStateChanged(int state)
{
    bool enabled = (state == Qt::Checked);
    repeatModeCombo->setEnabled(enabled);
    infiniteRepeatCheck->setEnabled(enabled);

    if (enabled) {
        clickButton->setText("🎯 开始重复点击");
        showStatusMessage("🔁 已启用重复点击模式");

        // 根据当前模式设置控件状态
        onRepeatModeChanged();
    } else {
        clickButton->setText("🎯 立即点击");
        showStatusMessage("✅ 已禁用重复点击模式");
        repeatCountSpinBox->setEnabled(false);
        timeGroup->setVisible(false);

        if (isRepeating) {
            isRepeating = false;
            repeatTimer->stop();
            timeUpdateTimer->stop();
            clickButton->setText("🎯 立即点击");
            executeSequenceButton->setEnabled(true);
            repeatSequenceButton->setEnabled(true);
            importActionsButton->setEnabled(true);
            exportActionsButton->setEnabled(true);
            unregisterGlobalHotkey();
            activateAndShowWindow();
        }
    }
}

void MainWindow::onRepeatCountChanged(int value)
{
    infiniteRepeatCheck->setChecked(false);
}

void MainWindow::onInfiniteSequenceRepeatChanged(int state)
{
    bool enabled = (state == Qt::Checked);
    sequenceRepeatSpinBox->setEnabled(!enabled);
}

void MainWindow::onPickCoordClicked()
{
    POINT cursorPos;
    GetCursorPos(&cursorPos);
    xSpinBox->setValue(cursorPos.x);
    ySpinBox->setValue(cursorPos.y);
    showStatusMessage(QString("🎯 坐标已拾取: (%1, %2)").arg(cursorPos.x).arg(cursorPos.y), false, true);
}

void MainWindow::onClickButtonClicked()
{
    int x = xSpinBox->value();
    int y = ySpinBox->value();
    bool leftButton = leftButtonCheck->isChecked();
    bool doubleClick = doubleClickCheck->isChecked();
    double delaySeconds = delaySpinBox->value();

    if (repeatCheckBox->isChecked()) {
        if (isRepeating) {
            isRepeating = false;
            repeatTimer->stop();
            timeUpdateTimer->stop();
            clickButton->setText("🎯 开始重复点击");
            showStatusMessage("⏹️ 重复点击已停止", false, true);
            executeSequenceButton->setEnabled(true);
            repeatSequenceButton->setEnabled(true);
            importActionsButton->setEnabled(true);
            exportActionsButton->setEnabled(true);
            progressBar->setValue(0);
            progressLabel->setText("就绪");
            unregisterGlobalHotkey();
            activateAndShowWindow();
        } else {
            registerGlobalHotkey();
            int countdownTime = countdownSpinBox->value();
            if (countdownTime > 0) {
                isRepeating = true;
                stopRequested = false;
                countdownSeconds = countdownTime;

                // 根据模式设置参数
                if (repeatModeCombo->currentIndex() == 0) {
                    // 按次数重复
                    if (infiniteRepeatCheck->isChecked()) {
                        totalRepeatCount = 0;
                        currentRepeatCount = 0;
                    } else {
                        totalRepeatCount = repeatCountSpinBox->value();
                        currentRepeatCount = repeatCountSpinBox->value();
                    }
                    totalRepeatTime = 0;
                } else {
                    // 按时间重复
                    if (infiniteRepeatCheck->isChecked()) {
                        totalRepeatTime = 0;
                        elapsedTime = 0;
                    } else {
                        totalRepeatTime = timeToSeconds(hoursSpinBox->value(),
                                                        minutesSpinBox->value(),
                                                        secondsSpinBox->value());
                        elapsedTime = 0;
                    }
                    totalRepeatCount = 0;
                }

                showStatusMessage(QString("⏱️ 倒计时: %1 秒后开始重复点击...").arg(countdownSeconds));
                countdownTimer->start();
                clickButton->setText("⏹️ 停止重复点击");
                executeSequenceButton->setEnabled(false);
                repeatSequenceButton->setEnabled(false);
                importActionsButton->setEnabled(false);
                exportActionsButton->setEnabled(false);
            } else {
                isRepeating = true;
                stopRequested = false;

                // 根据模式设置参数
                if (repeatModeCombo->currentIndex() == 0) {
                    // 按次数重复
                    if (infiniteRepeatCheck->isChecked()) {
                        totalRepeatCount = 0;
                        currentRepeatCount = 0;
                    } else {
                        totalRepeatCount = repeatCountSpinBox->value();
                        currentRepeatCount = repeatCountSpinBox->value();
                    }
                    totalRepeatTime = 0;
                } else {
                    // 按时间重复
                    if (infiniteRepeatCheck->isChecked()) {
                        totalRepeatTime = 0;
                        elapsedTime = 0;
                    } else {
                        totalRepeatTime = timeToSeconds(hoursSpinBox->value(),
                                                        minutesSpinBox->value(),
                                                        secondsSpinBox->value());
                        elapsedTime = 0;
                    }
                    totalRepeatCount = 0;
                }

                int delayMs = delayToMilliseconds(delaySeconds);
                repeatTimer->start(delayMs);

                // 如果是时间模式,启动时间更新定时器
                if (repeatModeCombo->currentIndex() == 1) {
                    timeUpdateTimer->start();
                }

                clickButton->setText("⏹️ 停止重复点击");

                // 显示开始消息
                if (repeatModeCombo->currentIndex() == 0) {
                    if (infiniteRepeatCheck->isChecked()) {
                        showStatusMessage(QString("🔁 开始无限重复点击 (间隔: %1秒)").arg(QString::number(delaySeconds, 'f', 3)));
                    } else {
                        showStatusMessage(QString("🔁 开始重复点击 %1 次 (间隔: %2秒)").arg(totalRepeatCount).arg(QString::number(delaySeconds, 'f', 3)));
                    }
                } else {
                    if (infiniteRepeatCheck->isChecked()) {
                        showStatusMessage(QString("🔁 开始无限重复点击 (间隔: %1秒)").arg(QString::number(delaySeconds, 'f', 3)));
                    } else {
                        showStatusMessage(QString("🔁 开始重复点击 (持续时间: %1, 间隔: %2秒)")
                                         .arg(formatTime(totalRepeatTime))
                                         .arg(QString::number(delaySeconds, 'f', 3)));
                    }
                }

                clickAt(x, y, leftButton, doubleClick);
                if (totalRepeatCount > 0) {
                    currentRepeatCount--;
                }

                // 检查是否立即完成
                if (totalRepeatCount > 0 && currentRepeatCount <= 0) {
                    isRepeating = false;
                    repeatTimer->stop();
                    timeUpdateTimer->stop();
                    clickButton->setText("🎯 开始重复点击");
                    showStatusMessage(QString("✅ 重复点击完成,共 %1 次").arg(totalRepeatCount), false, true);
                    executeSequenceButton->setEnabled(true);
                    repeatSequenceButton->setEnabled(true);
                    importActionsButton->setEnabled(true);
                    exportActionsButton->setEnabled(true);
                    progressBar->setValue(100);
                    progressLabel->setText("完成");
                    unregisterGlobalHotkey();
                    activateAndShowWindow();
                } else {
                    executeSequenceButton->setEnabled(false);
                    repeatSequenceButton->setEnabled(false);
                    importActionsButton->setEnabled(false);
                    exportActionsButton->setEnabled(false);
                }
                updateProgressInfo();
            }
        }
    } else {
        showStatusMessage(QString("🎯 正在点击 (%1, %2)").arg(x).arg(y));
        clickAt(x, y, leftButton, doubleClick);
        showStatusMessage(QString("✅ 点击完成 (%1, %2)").arg(x).arg(y), false, true);
        QTimer::singleShot(1000, this, [this]() {
            showStatusMessage("✅ 就绪", false, true);
        });
    }
}

void MainWindow::onRepeatTimeout()
{
    if (stopRequested) {
        isRepeating = false;
        repeatTimer->stop();
        timeUpdateTimer->stop();
        clickButton->setText("🎯 开始重复点击");
        showStatusMessage("⏹️ 重复点击已停止", false, true);
        executeSequenceButton->setEnabled(true);
        repeatSequenceButton->setEnabled(true);
        importActionsButton->setEnabled(true);
        exportActionsButton->setEnabled(true);
        progressBar->setValue(0);
        progressLabel->setText("就绪");
        unregisterGlobalHotkey();
        activateAndShowWindow();
        return;
    }

    int x = xSpinBox->value();
    int y = ySpinBox->value();
    bool leftButton = leftButtonCheck->isChecked();
    bool doubleClick = doubleClickCheck->isChecked();

    clickAt(x, y, leftButton, doubleClick);

    if (repeatModeCombo->currentIndex() == 0) {
        // 按次数重复
        if (totalRepeatCount > 0) {
            currentRepeatCount--;
            if (currentRepeatCount <= 0) {
                isRepeating = false;
                repeatTimer->stop();
                clickButton->setText("🎯 开始重复点击");
                showStatusMessage(QString("✅ 重复点击完成,共 %1 次").arg(totalRepeatCount), false, true);
                executeSequenceButton->setEnabled(true);
                repeatSequenceButton->setEnabled(true);
                importActionsButton->setEnabled(true);
                exportActionsButton->setEnabled(true);
                progressBar->setValue(100);
                progressLabel->setText("完成");
                unregisterGlobalHotkey();
                activateAndShowWindow();
            }
        }
    }
    // 按时间重复由 updateTimeDisplay 处理

    updateProgressInfo();
}

void MainWindow::onCountdownTimeout()
{
    countdownSeconds--;
    if (countdownSeconds > 0) {
        if (isRepeating) {
            showStatusMessage(QString("⏱️ 倒计时: %1 秒后开始重复点击...").arg(countdownSeconds));
        } else {
            QString modeText;
            if (isRepeatingSequence) {
                if (isInfiniteSequenceRepeat) {
                    modeText = "无限重复执行序列";
                } else {
                    modeText = QString("重复执行序列 (%1次)").arg(totalSequenceRepeat);
                }
            } else {
                modeText = "执行序列";
            }
            showStatusMessage(QString("⏱️ 倒计时: %1 秒后开始%2...").arg(countdownSeconds).arg(modeText));
        }
    } else {
        countdownTimer->stop();
        if (isRepeating) {
            int x = xSpinBox->value();
            int y = ySpinBox->value();
            bool leftButton = leftButtonCheck->isChecked();
            bool doubleClick = doubleClickCheck->isChecked();
            double delaySeconds = delaySpinBox->value();
            int delayMs = delayToMilliseconds(delaySeconds);
            repeatTimer->start(delayMs);

            // 如果是时间模式,启动时间更新定时器
            if (repeatModeCombo->currentIndex() == 1) {
                timeUpdateTimer->start();
            }

            if (repeatModeCombo->currentIndex() == 0) {
                if (infiniteRepeatCheck->isChecked()) {
                    showStatusMessage(QString("🔁 开始无限重复点击 (间隔: %1秒)").arg(QString::number(delaySeconds, 'f', 3)));
                } else {
                    showStatusMessage(QString("🔁 开始重复点击 %1 次 (间隔: %2秒)").arg(totalRepeatCount).arg(QString::number(delaySeconds, 'f', 3)));
                }
            } else {
                if (infiniteRepeatCheck->isChecked()) {
                    showStatusMessage(QString("🔁 开始无限重复点击 (间隔: %1秒)").arg(QString::number(delaySeconds, 'f', 3)));
                } else {
                    showStatusMessage(QString("🔁 开始重复点击 (持续时间: %1, 间隔: %2秒)")
                                     .arg(formatTime(totalRepeatTime))
                                     .arg(QString::number(delaySeconds, 'f', 3)));
                }
            }

            clickAt(x, y, leftButton, doubleClick);
            if (totalRepeatCount > 0) {
                currentRepeatCount--;
            }
            if (totalRepeatCount > 0 && currentRepeatCount <= 0) {
                isRepeating = false;
                repeatTimer->stop();
                timeUpdateTimer->stop();
                clickButton->setText("🎯 开始重复点击");
                showStatusMessage(QString("✅ 重复点击完成,共 %1 次").arg(totalRepeatCount), false, true);
                executeSequenceButton->setEnabled(true);
                repeatSequenceButton->setEnabled(true);
                importActionsButton->setEnabled(true);
                exportActionsButton->setEnabled(true);
                progressBar->setValue(100);
                progressLabel->setText("完成");
                unregisterGlobalHotkey();
                activateAndShowWindow();
            }
            updateProgressInfo();
        } else {
            QString modeText;
            if (isRepeatingSequence) {
                if (isInfiniteSequenceRepeat) {
                    modeText = "开始无限重复执行动作序列";
                } else {
                    modeText = QString("开始重复执行动作序列 (%1次)").arg(totalSequenceRepeat);
                }
            } else {
                modeText = "开始执行动作序列";
            }
            showStatusMessage(QString("▶️ %1").arg(modeText));
            currentActionIndex = 0;
            onSequenceTimeout();
        }
    }
}

void MainWindow::onAddActionClicked()
{
    int x = xSpinBox->value();
    int y = ySpinBox->value();
    double delaySeconds = delaySpinBox->value();
    bool leftButton = leftButtonCheck->isChecked();
    bool doubleClick = doubleClickCheck->isChecked();

    // 修改:延迟时间可以为0
    if (delaySeconds < 0.0 || delaySeconds > 10800.0) {
        showStatusMessage("⚠️ 延迟时间必须在0秒到3小时之间!", true);
        QMessageBox::warning(this, "警告", "延迟时间必须在0秒到3小时之间!");
        return;
    }

    QString description = QString("动作 %1: (%2, %3) 延迟: %4秒")
                         .arg(nextActionId).arg(x).arg(y).arg(QString::number(delaySeconds, 'f', 3));
    ClickAction newAction(nextActionId++, x, y, delaySeconds, leftButton, doubleClick, description);
    addActionToList(newAction);
    showStatusMessage(QString("✅ 已添加动作 %1").arg(newAction.id), false, true);
}

void MainWindow::onRemoveActionClicked()
{
    int currentRow = actionTable->currentRow();
    if (currentRow >= 0 && currentRow < (int)actionList.size()) {
        int id = actionList[currentRow].id;
        actionList.erase(actionList.begin() + currentRow);
        updateActionTable();
        showStatusMessage(QString("✅ 已移除动作 %1").arg(id), false, true);
    }
}

void MainWindow::onClearActionsClicked()
{
    if (!actionList.empty()) {
        QMessageBox::StandardButton reply;
        reply = QMessageBox::question(this, "确认清空",
                                     "确定要清空所有动作吗?此操作不可撤销!",
                                     QMessageBox::Yes | QMessageBox::No);
        if (reply == QMessageBox::Yes) {
            actionList.clear();
            updateActionTable();
            nextActionId = 1;
            showStatusMessage("✅ 所有动作已清空", false, true);
        }
    }
}

// 导入动作序列
void MainWindow::onImportActionsClicked()
{
    QString filePath = QFileDialog::getOpenFileName(this, "导入动作序列",
                                                   QDir::homePath(),
                                                   "JSON文件 (*.json);;所有文件 (*.*)");
    if (filePath.isEmpty()) {
        return;
    }

    if (loadActionsFromJson(filePath)) {
        showStatusMessage(QString("✅ 已从文件导入 %1 个动作").arg(actionList.size()), false, true);
    } else {
        showStatusMessage("❌ 导入失败:文件格式错误或无法读取", true);
        QMessageBox::critical(this, "导入失败",
                            "无法读取文件,请确保:\n"
                            "1. 文件是有效的JSON格式\n"
                            "2. 文件包含正确的动作数据\n"
                            "3. 每个动作都包含必需的字段:id, x, y, delay, button, double_click");
    }
}

// 导出动作序列
void MainWindow::onExportActionsClicked()
{
    if (actionList.empty()) {
        showStatusMessage("⚠️ 没有动作可以导出", true);
        QMessageBox::warning(this, "警告", "动作列表为空,无法导出!");
        return;
    }

    QString defaultFileName = QString("mouse_actions_%1.json")
                             .arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"));

    QString filePath = QFileDialog::getSaveFileName(this, "导出动作序列",
                                                   QDir::homePath() + "/" + defaultFileName,
                                                   "JSON文件 (*.json)");
    if (filePath.isEmpty()) {
        return;
    }

    // 确保文件扩展名
    if (!filePath.endsWith(".json", Qt::CaseInsensitive)) {
        filePath += ".json";
    }

    if (saveActionsToJson(filePath)) {
        showStatusMessage(QString("✅ 已导出 %1 个动作到文件").arg(actionList.size()), false, true);
        QMessageBox::information(this, "导出成功",
                                QString("动作序列已成功导出到:\n%1\n\n"
                                       "共 %2 个动作。\n\n"
                                       "文件采用易读的JSON格式,您可以使用文本编辑器直接修改。")
                                .arg(filePath).arg(actionList.size()));
    } else {
        showStatusMessage("❌ 导出失败:无法写入文件", true);
        QMessageBox::critical(this, "导出失败", "无法写入文件,请检查文件权限或磁盘空间。");
    }
}

void MainWindow::onExecuteSequenceClicked()
{
    startSequenceExecution(false);
}

void MainWindow::onRepeatSequenceClicked()
{
    startSequenceExecution(true);
}

void MainWindow::onStopSequenceClicked()
{
    stopRequested = true;
    isSequenceRunning = false;
    isRepeatingSequence = false;
    isInfiniteSequenceRepeat = false;
    sequenceTimer->stop();
    countdownTimer->stop();
    if (isRepeating) {
        isRepeating = false;
        repeatTimer->stop();
        timeUpdateTimer->stop();
        clickButton->setText("🎯 开始重复点击");
    }
    clickButton->setEnabled(true);
    executeSequenceButton->setEnabled(true);
    repeatSequenceButton->setEnabled(true);
    stopSequenceButton->setEnabled(false);
    addActionButton->setEnabled(true);
    removeActionButton->setEnabled(actionTable->currentRow() >= 0);
    clearActionsButton->setEnabled(true);
    sequenceRepeatSpinBox->setEnabled(true);
    infiniteSequenceRepeatCheck->setEnabled(true);
    importActionsButton->setEnabled(true);
    exportActionsButton->setEnabled(true);
    unregisterGlobalHotkey();
    resetSequenceExecution();
    showStatusMessage("⏹️ 动作序列已停止", false, true);
    progressBar->setValue(0);
    progressLabel->setText("已停止");
    activateAndShowWindow();

    // 清除表格高亮
    for (int i = 0; i < actionTable->rowCount(); ++i) {
        for (int j = 0; j < actionTable->columnCount(); ++j) {
            QTableWidgetItem *item = actionTable->item(i, j);
            if (item) {
                item->setBackground(QBrush());
                item->setForeground(QBrush());
                item->setFont(QFont());
            }
        }
    }
}

void MainWindow::onSequenceTimeout()
{
    if (stopRequested) {
        onStopSequenceClicked();
        return;
    }

    if (currentActionIndex >= (int)actionList.size()) {
        if (isRepeatingSequence) {
            if (!isInfiniteSequenceRepeat && currentSequenceRepeat >= totalSequenceRepeat) {
                onStopSequenceClicked();
                showStatusMessage(QString("✅ 序列重复执行完成,共 %1 次").arg(totalSequenceRepeat), false, true);
                progressBar->setValue(100);
                progressLabel->setText("完成");
                activateAndShowWindow();
                return;
            } else {
                currentSequenceRepeat++;
                currentActionIndex = 0;
                if (isInfiniteSequenceRepeat) {
                    showStatusMessage(QString("🔁 开始第 %1 次无限重复执行").arg(currentSequenceRepeat));
                } else {
                    showStatusMessage(QString("🔁 开始第 %1/%2 次重复执行").arg(currentSequenceRepeat).arg(totalSequenceRepeat));
                }
            }
        } else {
            onStopSequenceClicked();
            showStatusMessage("✅ 动作序列执行完成", false, true);
            progressBar->setValue(100);
            progressLabel->setText("完成");
            activateAndShowWindow();
            return;
        }
    }

    const ClickAction& action = actionList[currentActionIndex];
    clickAction(action);

    // 高亮当前执行的行
    highlightTableRow(currentActionIndex);

    currentActionIndex++;
    if (currentActionIndex < (int)actionList.size()) {
        const ClickAction& nextAction = actionList[currentActionIndex];
        int delayMs = delayToMilliseconds(nextAction.delay);
        sequenceTimer->start(delayMs);
    } else {
        QTimer::singleShot(100, this, &MainWindow::onSequenceTimeout);
    }
}

void MainWindow::onActionTableItemChanged(QTableWidgetItem *item)
{
    int row = item->row();
    int column = item->column();
    if (row >= 0 && row < (int)actionList.size()) {
        ClickAction& action = actionList[row];
        bool changed = false;

        switch (column) {
        case 1:
            if (action.x != item->text().toInt()) {
                action.x = item->text().toInt();
                changed = true;
            }
            break;
        case 2:
            if (action.y != item->text().toInt()) {
                action.y = item->text().toInt();
                changed = true;
            }
            break;
        case 3:
            {
                double newDelay = item->text().toDouble();
                if (qAbs(action.delay - newDelay) > 0.0001) {
                    // 修改:延迟可以为0
                    if (newDelay < 0.0 || newDelay > 10800.0) {
                        action.delay = qBound(0.0, newDelay, 10800.0);
                        item->setText(QString::number(action.delay, 'f', 3));
                        showStatusMessage("⚠️ 延迟时间已自动调整到有效范围", true);
                    } else {
                        action.delay = newDelay;
                    }
                    changed = true;
                }
            }
            break;
        case 4:
            {
                bool newLeftButton = (item->text() == "左键");
                if (action.leftButton != newLeftButton) {
                    action.leftButton = newLeftButton;
                    changed = true;
                }
            }
            break;
        case 5:
            {
                bool newDoubleClick = (item->text() == "双击");
                if (action.doubleClick != newDoubleClick) {
                    action.doubleClick = newDoubleClick;
                    changed = true;
                }
            }
            break;
        }

        if (changed) {
            action.description = QString("动作 %1: (%2, %3) 延迟: %4秒")
                               .arg(action.id).arg(action.x).arg(action.y).arg(QString::number(action.delay, 'f', 3));
            showStatusMessage(QString("📝 已更新动作 %1").arg(action.id), false, true);
        }
    }
}

void MainWindow::onActionTableSelectionChanged()
{
    bool hasSelection = actionTable->currentRow() >= 0;
    removeActionButton->setEnabled(hasSelection);
}

coordinatemarker.cpp

#include "mainwindow.h"
#include <QPainter>
#include <QApplication>
#include <QDesktopWidget>
#include <QTimer>

CoordinateMarker::CoordinateMarker(QWidget *parent)
    : QWidget(parent), posX(0), posY(0)
{
    // 设置窗口属性
    setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
    setAttribute(Qt::WA_TranslucentBackground);
    setAttribute(Qt::WA_ShowWithoutActivating);

    // 设置窗口大小
    resize(200, 200);

    // 设置窗口位置(默认在左上角)
    move(100, 100);
}

void CoordinateMarker::setPosition(int x, int y)
{
    posX = x;
    posY = y;

    // 调整窗口位置,使标记在坐标中心
    QDesktopWidget *desktop = QApplication::desktop();
    QRect screenRect = desktop->screenGeometry();

    // 确保标记窗口不会超出屏幕
    int windowX = x - width() / 2;
    int windowY = y - height() / 2;

    if (windowX < 0) windowX = 0;
    if (windowY < 0) windowY = 0;
    if (windowX + width() > screenRect.width())
        windowX = screenRect.width() - width();
    if (windowY + height() > screenRect.height())
        windowY = screenRect.height() - height();

    move(windowX, windowY);
    update();
}

void CoordinateMarker::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    // 绘制半透明背景
    painter.fillRect(rect(), QColor(0, 0, 0, 100));

    // 绘制中心十字线
    painter.setPen(QPen(Qt::red, 2));
    painter.drawLine(width()/2, 0, width()/2, height());
    painter.drawLine(0, height()/2, width(), height()/2);

    // 绘制坐标文本
    painter.setPen(Qt::white);
    painter.setFont(QFont("Arial", 12, QFont::Bold));
    QString coordText = QString("(%1, %2)").arg(posX).arg(posY);
    painter.drawText(rect().adjusted(10, 10, -10, -10),
                     Qt::AlignTop | Qt::AlignLeft, coordText);

    // 绘制圆圈
    painter.setPen(QPen(QColor(255, 255, 0, 200), 3));
    painter.setBrush(QBrush(QColor(255, 255, 0, 50)));
    painter.drawEllipse(width()/2 - 30, height()/2 - 30, 60, 60);

    // 绘制内圈
    painter.setPen(QPen(QColor(0, 255, 255, 200), 2));
    painter.setBrush(Qt::NoBrush);
    painter.drawEllipse(width()/2 - 15, height()/2 - 15, 30, 30);

    // 绘制方向指示
    painter.setPen(QPen(Qt::green, 2));
    painter.drawLine(width()/2, height()/2 - 40, width()/2, height()/2 - 20);
    painter.drawLine(width()/2, height()/2 + 20, width()/2, height()/2 + 40);
    painter.drawLine(width()/2 - 40, height()/2, width()/2 - 20, height()/2);
    painter.drawLine(width()/2 + 20, height()/2, width()/2 + 40, height()/2);
}

main.cpp

#include "mainwindow.h"
#include <QApplication>
#include <QStyleFactory>
#include <QFont>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 设置应用程序样式
    app.setStyle(QStyleFactory::create("Fusion"));

    // 设置应用程序字体
    QFont defaultFont("Microsoft YaHei", 9);
    app.setFont(defaultFont);

    // 设置应用程序名称和版本
    app.setApplicationName("智能鼠标点击器");
    app.setApplicationVersion("3.0");
    app.setOrganizationName("SmartClicker");

    // 创建并显示主窗口
    MainWindow window;
    window.show();

    return app.exec();
}

智能鼠标点击器 v3.0 使用说明书

一、软件简介

智能鼠标点击器 v3.0 是一款专业级的Windows自动化鼠标操作工具.

核心功能特点:

  • 基础点击功能:支持单次点击、重复点击(按次数或按时间)

  • 高级动作序列:创建、编辑、执行复杂的多步骤鼠标点击序列

  • 多种重复模式:支持按次数重复、按时间重复、无限循环

  • 全局热键控制:软件最小化时仍可通过热键控制

  • 智能坐标管理:实时坐标预览、坐标标记显示

  • 数据管理:支持JSON格式的导入导出

  • 进度可视化:实时显示执行进度和详细信息

  • 个性化设置:支持界面设置保存

二、系统要求

最低配置:

  • 操作系统:Windows 7/8/10/11(64位/32位)

  • 处理器:1 GHz或更高

  • 内存:512 MB RAM

  • 硬盘空间:10 MB可用空间

推荐配置:

  • 操作系统:Windows 10/11(64位)

  • 处理器:2 GHz双核或更高

  • 内存:1 GB RAM或更高

  • 硬盘空间:50 MB可用空间

软件依赖:

  • 运行环境:需要安装Microsoft Visual C++ Redistributable

  • 权限要求:需要管理员权限以正常使用全局热键功能

  • 显示要求:支持多显示器环境

三、界面布局详解

3.1 基础点击控制区域(🎯 绿色区域)

┌─────────────────────────────────────────┐
│ 🎯 基础点击控制                         │
│ ┌─────────────────┬─────────────────┐ │
│ │ 📌 X坐标: [100 px]  拾取坐标      │ │
│ │ 📌 Y坐标: [100 px]  立即点击      │ │
│ │ ⏱️ 延迟时间: [1.000 秒]           │ │
│ │ ⏱️ 开始倒计时: [3 秒]             │ │
│ └─────────────────┴─────────────────┘ │
│ 🖱️ 光标位置: (1920, 1080)            │ │
│ 🖱️ 左键点击  ⚡ 双击                │ │
│ 🔁 启用重复点击                       │ │
│   重复模式: [按次数重复▼]            │ │
│   重复次数: [10 次]  □ 无限循环      │ │
│ ⏰ 时间设置: [0 时] [1 分] [0 秒]    │ │
└─────────────────────────────────────────┘

3.2 动作序列管理区域(📋 蓝色区域)

┌─────────────────────────────────────────┐
│ 📋 动作序列管理                         │
│ ┌──────┬─────┬─────┬────────┬────┬────┐ │
│ │ ID   │ X   │ Y   │ 延迟   │按键│类型│ │
│ ├──────┼─────┼─────┼────────┼────┼────┤ │
│ │ 1    │ 100 │ 100 │ 1.000  │左键│单击│ │
│ │ 2    │ 200 │ 200 │ 0.500  │右键│双击│ │
│ └──────┴─────┴─────┴────────┴────┴────┘ │
│ 序列重复次数: [1 次] □ 无限循环         │ │
│ ┌─────────────────────────────────────┐ │
│ │ 操作:➕添加  ➖移除  🗑️清空         │ │
│ │ 文件:📥导入  📤导出                │ │
│ │ 执行:▶️执行  🔁重复执行  ⏹️停止    │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘

3.3 状态显示区域

┌─────────────────────────────────────────┐
│ 就绪                                    │ │
│ [===============                 ] 45%  │ │
│ ✅ 就绪 - 欢迎使用智能鼠标点击器 v3.0!│ │
└─────────────────────────────────────────┘

四、基础功能介绍

4.1 单次点击操作

设置坐标的三种方式:

  1. 手动输入:在X/Y坐标输入框中直接输入数值

  2. 快速拾取:按空格键快速获取当前鼠标位置

  3. 精确拾取

    • 点击"拾取坐标"按钮

    • 移动鼠标到目标位置

    • 按空格键确认拾取

配置点击参数:

  • 按键选择:左键、右键(通过复选框切换)

  • 点击类型:单击、双击(双击时会额外增加50ms间隔)

  • 延迟时间:0-10800秒(3小时),精度0.001秒

执行点击:

  • 确保"启用重复点击"未勾选

  • 点击"🎯 立即点击"按钮

  • 或按快捷键 Ctrl+S

4.2 重复点击操作

两种重复模式:

模式一:按次数重复

  1. 勾选"🔁 启用重复点击"

  2. 选择"重复模式"为"按次数重复"

  3. 设置重复次数(1-9999次)

  4. 或勾选"无限循环"无限重复

  5. 点击"开始重复点击"

  6. 执行中可随时按Ctrl+C停止

模式二:按时间重复

  1. 勾选"🔁 启用重复点击"

  2. 选择"重复模式"为"按时间重复"

  3. 设置持续时间(时、分、秒)

  4. 或勾选"无限循环"无限重复

  5. 点击"开始重复点击"

  6. 执行中会显示已运行时间和剩余时间

倒计时功能:

  • 默认3秒倒计时,可在"开始倒计时"中设置

  • 设为0则不显示倒计时

  • 倒计时期间可按Esc取消

五、动作序列功能

5.1 创建动作序列

方法一:逐个添加

  1. 在基础区域设置好点击参数

  2. 点击"➕ 添加"按钮(Ctrl+A

  3. 动作会添加到表格末尾

  4. 重复以上步骤添加多个动作

方法二:快速编辑

  • 直接编辑:双击表格单元格修改数值

  • 插入动作:右键菜单选择"插入动作"(Ctrl+I

  • 复制动作:右键菜单选择"复制动作"

  • 调整顺序:右键菜单选择"上移"/"下移"(Ctrl+↑/Ctrl+↓

方法三:文件导入

  1. 点击"📥 导入"按钮

  2. 选择JSON格式的配置文件

  3. 支持自动ID续号和格式验证

5.2 动作参数详解

表格列说明:

  • ID:动作编号,自动生成不可编辑

  • X坐标:点击位置的横坐标(0-屏幕宽度)

  • Y坐标:点击位置的纵坐标(0-屏幕高度)

  • 延迟(秒):执行完此动作后的等待时间

  • 按键:左键、右键、中键

  • 点击类型:单击、双击、按下、释放

特殊点击类型说明:

  • 单击:标准的点击操作(按下后立即释放)

  • 双击:连续两次单击,间隔50ms

  • 按下:只执行按下操作,不释放

  • 释放:只执行释放操作(需配合"按下"使用)

5.3 执行动作序列

单次执行序列:

  1. 添加至少一个动作到序列

  2. 点击"▶️ 执行"按钮(Ctrl+S

  3. 等待倒计时后开始执行

  4. 执行过程中当前动作会高亮显示

  5. 表格会自动滚动到当前执行行

重复执行序列:

  1. 设置"序列重复次数"(1-9999次)

  2. 或勾选"无限循环"

  3. 点击"🔁 重复执行"按钮(Ctrl+R

  4. 序列会按照设定次数循环执行

坐标标记显示:

  • 选中表格中的动作时,屏幕上会显示坐标标记窗口

  • 标记窗口3秒后自动隐藏

  • 标记包含十字线、坐标文本和方向指示

5.4 序列执行状态

进度显示信息:

  • 单次执行:显示"执行序列: 动作 X/Y"

  • 重复执行:显示"重复执行: 第 A/B 次 | 动作: X/Y"

  • 无限重复:显示"无限重复执行: 第 N 次 | 动作: X/Y"

高亮显示规则:

  • 当前执行的动作行显示黄色背景

  • 执行完成后恢复正常颜色

  • 可通过表格滚动条追踪执行位置

六、文件管理功能

6.1 导入动作序列

支持格式:JSON格式配置文件

导入步骤:

  1. 点击"📥 导入"按钮

  2. 选择JSON文件

  3. 系统自动验证格式并导入

  4. 导入成功后会显示动作数量

JSON文件结构示例:

json

{
  "app_name": "智能鼠标点击器",
  "version": "3.0",
  "total_actions": 2,
  "export_time": "2024-01-01 12:00:00",
  "actions": [
    {
      "id": 1,
      "x": 100,
      "y": 100,
      "delay": "1.000",
      "button": "left",
      "double_click": false,
      "description": "动作 1: (100, 100) 延迟: 1.000秒"
    }
  ]
}

6.2 导出动作序列

导出步骤:

  1. 确保动作列表不为空

  2. 点击"📤 导出"按钮

  3. 选择保存位置和文件名

  4. 系统自动生成带时间戳的JSON文件

导出文件特点:

  • 采用易读的格式化JSON

  • 包含完整的动作信息

  • 包含导出时间和版本信息

  • 可用文本编辑器直接修改

七、快捷键大全

7.1 全局快捷键(任何情况下有效)

快捷键功能使用场景
空格键拾取坐标快速将当前鼠标位置填入坐标框
Ctrl+C停止所有操作全局热键,即使软件最小化也有效
Esc停止当前操作停止正在执行的点击或序列

7.2 窗口内操作快捷键

快捷键功能说明
Ctrl+S开始/停止智能判断:有动作时执行序列,无动作时执行点击
Ctrl+R重复执行序列开始重复执行动作序列
Ctrl+A添加动作将当前设置添加到动作序列末尾
Ctrl+D删除动作删除当前选中的动作
Ctrl+I插入动作在当前选中行前插入新动作
Ctrl+↑上移动作将选中动作上移一位
Ctrl+↓下移动作将选中动作下移一位

7.3 表格操作快捷键

操作方法说明
选择行点击行首选中整行,可进行删除等操作
编辑单元格双击单元格进入编辑模式
确认编辑Enter保存编辑内容
取消编辑Esc取消编辑,恢复原值
快速导航方向键在单元格间移动

八、高级功能介绍

8.1 按时间重复模式

时间计算规则:

  • 总时间 = 小时×3600 + 分钟×60 + 秒

  • 显示格式:HH:MM:SS 或 MM:SS 或 X秒

  • 进度计算:已运行时间/总时间×100%

应用场景:

  • 需要定时执行的任务

  • 测试需要运行特定时间的场景

  • 避免手动计时的麻烦

8.2 坐标标记系统

标记窗口功能:

  • 实时显示坐标位置

  • 十字线精确定位

  • 圆圈范围标识

  • 方向指示箭头

  • 3秒自动隐藏

使用技巧:

  1. 点击表格中的动作行自动显示标记

  2. 标记窗口可拖动(但非设计功能)

  3. 标记不影响鼠标正常操作

8.3 延迟时间策略

延迟时间范围:

  • 最小值:0秒(立即执行)

  • 最大值:10800秒(3小时)

  • 精度:0.001秒(1毫秒)

延迟使用建议:

  • 动作间延迟:建议0.1-1.0秒,避免操作过快

  • 重复点击间隔:根据目标程序响应速度调整

  • 特殊场景

    • 游戏操作:0.05-0.2秒

    • 办公自动化:0.3-1.0秒

    • 网页操作:0.5-2.0秒

8.4 智能设置保存

自动保存项目:

  • 窗口位置和大小

  • 基础点击参数

  • 重复设置选项

  • 序列重复设置

保存位置:

  • Windows注册表:HKEY_CURRENT_USER\Software\SmartClicker\MouseClicker

  • 无需手动管理,程序自动处理

九、实战应用案例

9.1 网页自动化点击

场景:自动刷新网页并点击特定位置
步骤:
1. 设置坐标:拾取浏览器刷新按钮位置
2. 设置延迟:5秒(网页加载时间)
3. 启用重复:按时间重复,设置1小时
4. 开始执行:自动每小时刷新一次

9.2 游戏辅助操作

场景:游戏挂机打怪
步骤:
1. 动作1:拾取怪物位置,左键单击,延迟0.1秒
2. 动作2:拾取技能位置,左键单击,延迟2秒
3. 动作3:拾取拾取物品位置,左键单击,延迟0.5秒
4. 设置序列:无限循环重复
5. 开始执行:自动循环打怪

9.3 数据录入自动化

场景:批量填写表单
步骤:
1. 导入预配置的JSON动作文件
2. 每个字段设置相应坐标和点击类型
3. 字段间设置适当延迟(等待页面响应)
4. 执行序列:自动完成数据录入

十、故障排除指南

10.1 常见问题及解决方案

Q1: 点击操作没有反应

可能原因:
1. 坐标超出屏幕范围
2. 目标窗口被最小化或遮挡
3. 防病毒软件拦截
4. 权限不足

解决方案:
1. 检查坐标值是否在屏幕范围内
2. 确保目标窗口在最前面且未被遮挡
3. 暂时关闭防病毒软件或添加白名单
4. 以管理员身份运行程序

Q2: 全局热键Ctrl+C无效

可能原因:
1. 其他程序占用了Ctrl+C热键
2. 程序未以管理员权限运行
3. Windows热键服务异常

解决方案:
1. 关闭可能占用热键的程序(如QQ、微信)
2. 右键程序→以管理员身份运行
3. 重启Windows Explorer进程

Q3: 动作序列执行不稳定

可能原因:
1. 延迟时间设置过短
2. 系统资源不足
3. 动作数量过多

解决方案:
1. 适当增加动作间的延迟时间
2. 关闭不必要的程序释放资源
3. 将长序列拆分为多个短序列

Q4: 导入JSON文件失败

可能原因:
1. JSON格式错误
2. 文件编码不正确
3. 缺少必需字段

解决方案:
1. 使用JSON验证工具检查格式
2. 确保文件使用UTF-8编码
3. 检查是否包含id、x、y、delay等必需字段

Q5: 程序意外崩溃

处理步骤:
1. 重新启动程序
2. 检查Windows事件查看器日志
3. 删除配置文件让程序重新生成
   (注册表位置:HKEY_CURRENT_USER\Software\SmartClicker)
4. 更新显卡驱动程序

10.2 性能优化建议

降低资源占用:

  1. 减少同时运行的动作序列数量

  2. 适当增加延迟时间,降低操作频率

  3. 关闭坐标标记功能(不选中表格行)

  4. 最小化程序窗口执行

提高稳定性:

  1. 避免在动作序列中使用0延迟

  2. 为每个动作添加至少0.1秒延迟

  3. 定期保存动作序列到文件

  4. 使用"执行"前先使用"测试"少量次数

十一、安全使用指南

11.1 合法使用原则

  • ✅ 允许用途:办公自动化、测试脚本、辅助操作

  • ✅ 合理使用:个人学习、效率提升、重复性工作

  • ❌ 禁止用途:游戏作弊、恶意攻击、侵犯他人权益

  • ❌ 风险行为:绕过安全验证、破坏系统完整

11.2 隐私保护建议

  1. 敏感操作:不要在银行、支付等敏感窗口使用

  2. 密码保护:避免录制包含密码输入的操作

  3. 文件安全:妥善保管导出的JSON配置文件

  4. 使用环境:在可信的网络和安全环境中使用

11.3 责任声明

  1. 本软件为免费工具,仅供学习和合法用途

  2. 使用者需自行承担使用风险

  3. 开发者不对滥用造成的后果负责

  4. 禁止将软件用于任何违法活动

十二、更新日志

版本 v3.0(当前版本)新增功能:

  1. 全新界面设计:现代化UI,更好的视觉体验

  2. 增强动作序列:支持中键、按下/释放操作

  3. 时间重复模式:支持按持续时间重复执行

  4. JSON导入导出:标准化数据交换格式

  5. 坐标标记系统:可视化坐标位置显示

  6. 表格右键菜单:插入、复制、移动动作

  7. 智能快捷键:上下文感知的快捷键功能

  8. 设置持久化:自动保存窗口状态和配置

  9. 进度显示优化:更详细的执行信息

  10. 稳定性提升:改进的错误处理和资源管理

版本 v2.0 历史功能:

  1. 基础点击和重复功能

  2. 简单动作序列管理

  3. 全局热键支持

  4. 进度显示功能

  5. 基础数据保存

版本 v1.0 初始功能:

  1. 基本鼠标点击功能

  2. 坐标拾取功能

  3. 简单重复设置

十三、技术支持

获取帮助:

  • 查看帮助:程序内状态栏提示

  • 在线文档:查看本使用说明书

  • 常见问题:参考第十章节

  • 更新检查:关注软件发布页面

使用建议:

  1. 先测试后使用:正式运行前先用少量次数测试

  2. 备份配置:定期导出动作序列到文件

  3. 分步执行:复杂操作分解为多个简单序列

  4. 记录日志:重要操作前记录坐标和参数

注意事项:

  • 使用前请阅读完整说明书

  • 确保了解所有功能后再进行复杂操作

  • 定期检查软件更新以获得更好的体验

  • 合理使用,避免过度依赖自动化工具

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpp_learners

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值