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

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

软件截图:

操作流程

1.录入动作

2.执行序列动作

3.重复执行序列动作

4.鼠标连续点击测试


源码分享

.pro文件

cpp 复制代码
QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

TARGET = WinMouseClicker
TEMPLATE = app

SOURCES += \
    main.cpp \
    mainwindow.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

mainwindow.h

cpp 复制代码
#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 QListWidget;
class QListWidgetItem;
class QTableWidget;
class QTableWidgetItem;
class QProgressBar;
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 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 onRepeatStateChanged(int state);
    void onRepeatCountChanged(int value);  // 重复次数改变
    void onInfiniteSequenceRepeatChanged(int state);  // 新增:序列无限循环状态改变

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 saveActionsToFile();
    void loadActionsFromFile();

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

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

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

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

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

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

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

    // UI 组件
    QSpinBox *xSpinBox;
    QSpinBox *ySpinBox;
    QDoubleSpinBox *delaySpinBox;
    QSpinBox *repeatCountSpinBox;     // 基础重复次数
    QSpinBox *sequenceRepeatSpinBox;  // 序列重复次数
    QPushButton *clickButton;
    QPushButton *pickCoordButton;
    QCheckBox *repeatCheckBox;
    QCheckBox *leftButtonCheck;
    QCheckBox *doubleClickCheck;
    QCheckBox *infiniteRepeatCheck;   // 基础点击无限重复复选框
    QCheckBox *infiniteSequenceRepeatCheck;  // 新增:序列无限重复复选框
    QLabel *statusLabel;
    QLabel *cursorLabel;
    QProgressBar *progressBar;        // 进度条
    QLabel *progressLabel;            // 进度文本

    // 动作序列相关UI组件
    QPushButton *addActionButton;
    QPushButton *removeActionButton;
    QPushButton *clearActionsButton;
    QPushButton *executeSequenceButton;
    QPushButton *repeatSequenceButton;
    QPushButton *stopSequenceButton;
    QTableWidget *actionTable;

    QTimer *repeatTimer;
    QTimer *sequenceTimer;
    QTimer *countdownTimer;
    bool isRepeating;
    bool isSequenceRunning;
    bool isRepeatingSequence;
    bool isInfiniteSequenceRepeat;    // 新增:是否序列无限循环

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

    // 计数相关
    int currentRepeatCount;           // 当前重复点击计数
    int totalRepeatCount;             // 总重复次数
    int currentSequenceRepeat;        // 当前序列重复计数
    int totalSequenceRepeat;          // 序列总重复次数

    // 中断标志
    bool stopRequested;
};

#endif // MAINWINDOW_H

mainwindow.cpp

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 <QListWidget>
#include <QTableWidget>
#include <QHeaderView>
#include <QFile>
#include <QTextStream>
#include <QKeyEvent>
#include <QShortcut>
#include <QFileDialog>
#include <QDataStream>
#include <QProgressBar>
#include <QFont>
#include <QResizeEvent>  // 新增

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

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)
{
    // 设置窗口
    setWindowTitle("智能鼠标点击器 - 支持动作序列和重复执行");
    resize(1000, 800);  // 稍微增加默认窗口大小

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

    // 注册全局热键 Ctrl+C
    RegisterHotKey((HWND)winId(), HOTKEY_ID, MOD_CONTROL, 'C');

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

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

    // 创建主布局
    QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
    mainLayout->setSpacing(15);
    mainLayout->setContentsMargins(15, 15, 15, 15);

    // ========== 基础点击控制区域 ==========
    QGroupBox *basicGroup = new QGroupBox("🎯 基础点击控制", centralWidget);
    basicGroup->setStyleSheet(
        "QGroupBox {"
        "  font-weight: bold;"
        "  font-size: 16px;"  // 增大字体
        "  border: 2px solid #4CAF50;"
        "  border-radius: 8px;"
        "  margin-top: 10px;"
        "  padding-top: 15px;"  // 增加顶部内边距
        "}"
        "QGroupBox::title {"
        "  subcontrol-origin: margin;"
        "  left: 15px;"
        "  padding: 0 10px 0 10px;"  // 增加左右内边距
        "  color: #4CAF50;"
        "  font-size: 16px;"  // 增大字体
        "}"
    );

    QGridLayout *basicLayout = new QGridLayout(basicGroup);
    basicLayout->setVerticalSpacing(12);  // 增加垂直间距
    basicLayout->setHorizontalSpacing(20);  // 增加水平间距
    basicLayout->setContentsMargins(15, 15, 15, 15);  // 增加内边距

    // X坐标
    QLabel *xLabel = new QLabel("📌 X坐标:", basicGroup);
    xLabel->setToolTip("点击位置的X坐标 (0-" + QString::number(GetSystemMetrics(SM_CXSCREEN) - 1) + ")");
    xLabel->setStyleSheet("QLabel { font-size: 14px; }");
    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: 8px; font-size: 14px; }");
    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: 14px; }");
    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: 8px; font-size: 14px; }");
    basicLayout->addWidget(ySpinBox, 1, 1);

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

    delaySpinBox = new QDoubleSpinBox(basicGroup);
    delaySpinBox->setRange(0.01, 10800.0);
    delaySpinBox->setValue(1.0);
    delaySpinBox->setDecimals(2);
    delaySpinBox->setSingleStep(0.1);
    delaySpinBox->setSuffix(" 秒");
    delaySpinBox->setToolTip("重复点击时的间隔时间\n范围: 0.01秒 到 3小时");
    delaySpinBox->setStyleSheet("QDoubleSpinBox { padding: 8px; font-size: 14px; }");
    basicLayout->addWidget(delaySpinBox, 2, 1);

    // 拾取坐标按钮
    pickCoordButton = new QPushButton("🎯 拾取坐标", basicGroup);
    pickCoordButton->setToolTip("点击后移动鼠标到目标位置,按空格键拾取坐标");
    pickCoordButton->setStyleSheet(
        "QPushButton {"
        "  background-color: #FF9800;"
        "  color: white;"
        "  font-weight: bold;"
        "  font-size: 14px;"
        "  padding: 10px 20px;"
        "  border-radius: 5px;"
        "}"
        "QPushButton:hover {"
        "  background-color: #F57C00;"
        "}"
    );
    basicLayout->addWidget(pickCoordButton, 0, 2, 2, 1);
    connect(pickCoordButton, &QPushButton::clicked, this, &MainWindow::onPickCoordClicked);

    // 光标位置显示
    cursorLabel = new QLabel("🖱️ 光标位置: (0, 0)", basicGroup);
    cursorLabel->setStyleSheet("QLabel { color: #666; font-style: italic; font-size: 13px; }");
    basicLayout->addWidget(cursorLabel, 3, 0, 1, 3);

    // 点击选项
    QHBoxLayout *optionsLayout = new QHBoxLayout();
    optionsLayout->setSpacing(25);  // 增加间距

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

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

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

    // 重复点击设置
    QHBoxLayout *repeatSettingsLayout = new QHBoxLayout();
    repeatSettingsLayout->setSpacing(10);

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

    QLabel *repeatCountLabel = new QLabel("次数:", basicGroup);
    repeatCountLabel->setStyleSheet("QLabel { font-size: 14px; }");
    repeatSettingsLayout->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: 14px; padding: 5px; }");
    repeatSettingsLayout->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: 14px; }");
    repeatSettingsLayout->addWidget(infiniteRepeatCheck);
    connect(infiniteRepeatCheck, &QCheckBox::stateChanged, this, [this](int state) {
        repeatCountSpinBox->setEnabled(state == Qt::Unchecked);
    });

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

    // 立即点击按钮
    clickButton = new QPushButton("🎯 立即点击", basicGroup);
    clickButton->setStyleSheet(
        "QPushButton {"
        "  background-color: #2196F3;"
        "  color: white;"
        "  font-size: 15px;"
        "  font-weight: bold;"
        "  padding: 14px;"
        "  border-radius: 6px;"
        "  min-width: 180px;"
        "}"
        "QPushButton:hover {"
        "  background-color: #1976D2;"
        "}"
        "QPushButton:disabled {"
        "  background-color: #BDBDBD;"
        "}"
    );
    clickButton->setToolTip("重复点击启用时:开始/停止重复点击\n重复点击未启用时:执行单次点击\n快捷键: Ctrl+S");
    basicLayout->addWidget(clickButton, 6, 0, 1, 3);
    connect(clickButton, &QPushButton::clicked, this, &MainWindow::onClickButtonClicked);

    mainLayout->addWidget(basicGroup);

    // ========== 动作序列区域 ==========
    QGroupBox *sequenceGroup = new QGroupBox("📋 动作序列管理", centralWidget);
    sequenceGroup->setStyleSheet(
        "QGroupBox {"
        "  font-weight: bold;"
        "  font-size: 16px;"  // 增大字体
        "  border: 2px solid #2196F3;"
        "  border-radius: 8px;"
        "  margin-top: 10px;"
        "  padding-top: 15px;"  // 增加顶部内边距
        "}"
        "QGroupBox::title {"
        "  subcontrol-origin: margin;"
        "  left: 15px;"
        "  padding: 0 10px 0 10px;"  // 增加左右内边距
        "  color: #2196F3;"
        "  font-size: 16px;"  // 增大字体
        "}"
    );

    QVBoxLayout *sequenceLayout = new QVBoxLayout(sequenceGroup);
    sequenceLayout->setSpacing(12);  // 增加间距
    sequenceLayout->setContentsMargins(15, 15, 15, 15);  // 增加内边距

    // 动作表格 - 重新设计样式
    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(250);  // 增加最小高度
    actionTable->setMaximumHeight(450);  // 设置最大高度

    // 重新设计表格样式 - 现代化设计
    actionTable->setStyleSheet(
        "QTableWidget {"
        "  background-color: white;"
        "  alternate-background-color: #f8fafc;"  // 设置交替行颜色
        "  border: 1px solid #e1e4e8;"
        "  border-radius: 8px;"
        "  padding: 2px;"
        "  gridline-color: #eef2f7;"
        "  font-size: 13px;"
        "  outline: 0;"
        "}"
        "QTableWidget::item {"
        "  padding: 10px 5px;"
        "  border-bottom: 1px solid #f0f0f0;"
        "  color: #333333;"
        "}"
        "QTableWidget::item:selected {"
        "  background-color: rgba(25, 118, 210, 0.2);"  // 半透明蓝色背景
        "  color: #1976D2;"
        "  font-weight: bold;"
        "  border: 1px solid #1976D2;"
        "  border-radius: 4px;"
        "}"
        "QTableWidget::item:hover:!selected {"
        "  background-color: #f8fafc;"
        "}"
        "QHeaderView {"
        "  background-color: transparent;"
        "  border: none;"
        "}"
        "QHeaderView::section {"
        "  background-color: #2196F3;"  // 蓝色背景
        "  color: white;"
        "  padding: 14px 8px;"  // 增加内边距
        "  font-weight: bold;"
        "  font-size: 14px;"
        "  border: none;"
        "  border-right: 1px solid #1976D2;"  // 分隔线
        "}"
        "QHeaderView::section:first {"
        "  border-top-left-radius: 6px;"
        "}"
        "QHeaderView::section:last {"
        "  border-top-right-radius: 6px;"
        "  border-right: none;"
        "}"
        "QTableCornerButton::section {"
        "  background-color: #2196F3;"  // 表格角落按钮颜色
        "  border-top-left-radius: 6px;"
        "}"
        "QScrollBar:vertical {"
        "  border: none;"
        "  background: #f8f9fa;"
        "  width: 12px;"
        "  margin: 0px;"
        "}"
        "QScrollBar::handle:vertical {"
        "  background: #c1c1c1;"
        "  border-radius: 6px;"
        "  min-height: 30px;"
        "}"
        "QScrollBar::handle:vertical:hover {"
        "  background: #a8a8a8;"
        "}"
        "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(70);  // 增加最小列宽
    header->setDefaultSectionSize(120); // 设置默认列宽
    header->setCascadingSectionResizes(true);

    // 设置固定列宽
    actionTable->setColumnWidth(0, 70);   // ID列
    actionTable->setColumnWidth(1, 120);  // X坐标列
    actionTable->setColumnWidth(2, 120);  // Y坐标列
    actionTable->setColumnWidth(3, 140);  // 延迟列
    actionTable->setColumnWidth(4, 100);  // 按键列
    actionTable->setColumnWidth(5, 100);  // 双击列

    // 设置行高
    actionTable->verticalHeader()->setDefaultSectionSize(45);  // 增加行高
    actionTable->verticalHeader()->setVisible(false);  // 隐藏垂直表头

    // 设置表格属性
    actionTable->setShowGrid(false);  // 不显示网格线
    actionTable->setFocusPolicy(Qt::StrongFocus);
    actionTable->setSelectionMode(QAbstractItemView::SingleSelection);
    actionTable->setSelectionBehavior(QAbstractItemView::SelectRows);
    actionTable->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
    actionTable->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
    actionTable->setAutoScroll(true);
    actionTable->setCornerButtonEnabled(false);  // 禁用角落按钮

    sequenceLayout->addWidget(actionTable, 1);  // 设置拉伸因子为1

    // 连接表格信号
    connect(actionTable, &QTableWidget::itemChanged, this, &MainWindow::onActionTableItemChanged);
    connect(actionTable, &QTableWidget::itemSelectionChanged, this, &MainWindow::onActionTableSelectionChanged);

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

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

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

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

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

    // 序列控制按钮
    QHBoxLayout *sequenceBtnLayout = new QHBoxLayout();
    sequenceBtnLayout->setSpacing(12);  // 增加按钮间距

    addActionButton = new QPushButton("➕ 添加动作", sequenceGroup);
    addActionButton->setToolTip("将当前设置的点击参数添加到序列中\n快捷键: Ctrl+A");
    addActionButton->setStyleSheet(
        "QPushButton {"
        "  background-color: #4CAF50;"
        "  color: white;"
        "  font-size: 14px;"
        "  font-weight: 500;"
        "  padding: 10px 18px;"
        "  border-radius: 6px;"
        "  border: none;"
        "}"
        "QPushButton:hover {"
        "  background-color: #388E3C;"
        "  box-shadow: 0 2px 4px rgba(0,0,0,0.2);"
        "}"
    );
    sequenceBtnLayout->addWidget(addActionButton);
    connect(addActionButton, &QPushButton::clicked, this, &MainWindow::onAddActionClicked);

    removeActionButton = new QPushButton("➖ 移除动作", sequenceGroup);
    removeActionButton->setToolTip("移除选中的动作\n快捷键: Ctrl+D");
    removeActionButton->setStyleSheet(
        "QPushButton {"
        "  background-color: #FF9800;"
        "  color: white;"
        "  font-size: 14px;"
        "  font-weight: 500;"
        "  padding: 10px 18px;"
        "  border-radius: 6px;"
        "  border: none;"
        "}"
        "QPushButton:hover {"
        "  background-color: #F57C00;"
        "  box-shadow: 0 2px 4px rgba(0,0,0,0.2);"
        "}"
        "QPushButton:disabled {"
        "  background-color: #FFCC80;"
        "  color: #666;"
        "}"
    );
    removeActionButton->setEnabled(false);
    sequenceBtnLayout->addWidget(removeActionButton);
    connect(removeActionButton, &QPushButton::clicked, this, &MainWindow::onRemoveActionClicked);

    clearActionsButton = new QPushButton("🗑️ 清空动作", sequenceGroup);
    clearActionsButton->setToolTip("清空所有动作");
    clearActionsButton->setStyleSheet(
        "QPushButton {"
        "  background-color: #F44336;"
        "  color: white;"
        "  font-size: 14px;"
        "  font-weight: 500;"
        "  padding: 10px 18px;"
        "  border-radius: 6px;"
        "  border: none;"
        "}"
        "QPushButton:hover {"
        "  background-color: #D32F2F;"
        "  box-shadow: 0 2px 4px rgba(0,0,0,0.2);"
        "}"
    );
    sequenceBtnLayout->addWidget(clearActionsButton);
    connect(clearActionsButton, &QPushButton::clicked, this, &MainWindow::onClearActionsClicked);

    executeSequenceButton = new QPushButton("▶️ 执行序列", sequenceGroup);
    executeSequenceButton->setToolTip("执行动作序列一次\n快捷键: Ctrl+S");
    executeSequenceButton->setStyleSheet(
        "QPushButton {"
        "  background-color: #2196F3;"
        "  color: white;"
        "  font-weight: 600;"
        "  font-size: 14px;"
        "  padding: 10px 22px;"
        "  border-radius: 6px;"
        "  border: none;"
        "}"
        "QPushButton:hover {"
        "  background-color: #1976D2;"
        "  box-shadow: 0 2px 4px rgba(0,0,0,0.2);"
        "}"
    );
    sequenceBtnLayout->addWidget(executeSequenceButton);
    connect(executeSequenceButton, &QPushButton::clicked, this, &MainWindow::onExecuteSequenceClicked);

    repeatSequenceButton = new QPushButton("🔁 重复执行序列", sequenceGroup);
    repeatSequenceButton->setToolTip("重复执行动作序列\n快捷键: Ctrl+R");
    repeatSequenceButton->setStyleSheet(
        "QPushButton {"
        "  background-color: #9C27B0;"
        "  color: white;"
        "  font-weight: 600;"
        "  font-size: 14px;"
        "  padding: 10px 22px;"
        "  border-radius: 6px;"
        "  border: none;"
        "}"
        "QPushButton:hover {"
        "  background-color: #7B1FA2;"
        "  box-shadow: 0 2px 4px rgba(0,0,0,0.2);"
        "}"
    );
    sequenceBtnLayout->addWidget(repeatSequenceButton);
    connect(repeatSequenceButton, &QPushButton::clicked, this, &MainWindow::onRepeatSequenceClicked);

    stopSequenceButton = new QPushButton("⏹️ 停止序列", sequenceGroup);
    stopSequenceButton->setToolTip("停止正在执行的序列\n快捷键: Ctrl+C 或 Esc");
    stopSequenceButton->setStyleSheet(
        "QPushButton {"
        "  background-color: #757575;"
        "  color: white;"
        "  font-size: 14px;"
        "  font-weight: 500;"
        "  padding: 10px 18px;"
        "  border-radius: 6px;"
        "  border: none;"
        "}"
        "QPushButton:hover {"
        "  background-color: #616161;"
        "  box-shadow: 0 2px 4px rgba(0,0,0,0.2);"
        "}"
        "QPushButton:disabled {"
        "  background-color: #BDBDBD;"
        "  color: #999;"
        "}"
    );
    stopSequenceButton->setEnabled(false);
    sequenceBtnLayout->addWidget(stopSequenceButton);
    connect(stopSequenceButton, &QPushButton::clicked, this, &MainWindow::onStopSequenceClicked);

    sequenceLayout->addLayout(sequenceBtnLayout);

    mainLayout->addWidget(sequenceGroup, 1);  // 设置拉伸因子为1

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

    progressLabel = new QLabel("就绪", centralWidget);
    progressLabel->setAlignment(Qt::AlignLeft);
    progressLabel->setStyleSheet(
        "QLabel {"
        "  color: #333;"
        "  padding: 8px;"
        "  min-height: 28px;"
        "  font-size: 14px;"
        "}"
    );

    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: 24px;"
        "  font-size: 13px;"
        "  font-weight: 500;"
        "}"
        "QProgressBar::chunk {"
        "  background-color: #4CAF50;"
        "  border-radius: 5px;"
        "  border: none;"
        "}"
    );

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

    // ========== 状态显示 ==========
    statusLabel = new QLabel("✅ 就绪 - 欢迎使用智能鼠标点击器!", centralWidget);
    statusLabel->setAlignment(Qt::AlignCenter);
    statusLabel->setStyleSheet(
        "QLabel {"
        "  background-color: #e8f5e9;"
        "  color: #2e7d32;"
        "  border: 2px solid #c8e6c9;"
        "  padding: 14px;"
        "  border-radius: 8px;"
        "  font-weight: 600;"
        "  font-size: 14px;"  // 增大字体
        "}"
    );
    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);

    // 定时更新光标位置
    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);

    // 设置快捷键
    setupShortcuts();

    // 加载保存的动作
    loadActionsFromFile();
}

MainWindow::~MainWindow()
{
    // 注销全局热键
    UnregisterHotKey((HWND)winId(), HOTKEY_ID);

    // 保存动作到文件
    saveActionsToFile();
}

// 处理窗口大小变化事件
void MainWindow::resizeEvent(QResizeEvent *event)
{
    QMainWindow::resizeEvent(event);

    // 根据窗口高度调整表格行高
    int tableHeight = actionTable->height();
    int rowCount = actionTable->rowCount();

    if (rowCount > 0) {
        // 计算合适的行高,最小35,最大50
        int suggestedRowHeight = qMin(50, qMax(35, tableHeight / qMax(1, rowCount) - 2));
        actionTable->verticalHeader()->setDefaultSectionSize(suggestedRowHeight);
    }
}

// Windows消息处理 - 用于全局热键
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) {
            // Ctrl+C 被按下
            stopRequested = true;

            if (isSequenceRunning) {
                sequenceTimer->stop();
                countdownTimer->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);

                showStatusMessage("⏹️ 动作序列已通过全局快捷键 Ctrl+C 停止", false, true);

                // 激活窗口
                activateAndShowWindow();
            }

            if (isRepeating) {
                isRepeating = false;
                repeatTimer->stop();
                if (repeatCheckBox->isChecked()) {
                    clickButton->setText("🎯 开始重复点击");
                } else {
                    clickButton->setText("🎯 立即点击");
                }
                executeSequenceButton->setEnabled(true);
                repeatSequenceButton->setEnabled(true);
                showStatusMessage("⏹️ 重复点击已通过全局快捷键 Ctrl+C 停止", false, true);

                // 激活窗口
                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;
        }

        // Esc键停止
        if (keyEvent->key() == Qt::Key_Escape && !keyEvent->isAutoRepeat()) {
            if (isSequenceRunning || isRepeating) {
                onStopSequenceClicked();
                return true;
            }
        }
    }

    return QMainWindow::eventFilter(obj, event);
}

// 设置快捷键
void MainWindow::setupShortcuts()
{
    // Ctrl+S 开始/停止序列
    QShortcut *shortcutStartStop = new QShortcut(QKeySequence("Ctrl+S"), this);
    connect(shortcutStartStop, &QShortcut::activated, [this]() {
        if (isSequenceRunning) {
            onStopSequenceClicked();
        } else {
            if (actionList.empty()) {
                onClickButtonClicked();
            } else {
                onExecuteSequenceClicked();
            }
        }
    });

    // Ctrl+R 重复执行序列
    QShortcut *shortcutRepeat = new QShortcut(QKeySequence("Ctrl+R"), this);
    connect(shortcutRepeat, &QShortcut::activated, this, &MainWindow::onRepeatSequenceClicked);

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

    // Ctrl+D 删除选中动作
    QShortcut *shortcutDelete = new QShortcut(QKeySequence("Ctrl+D"), this);
    connect(shortcutDelete, &QShortcut::activated, this, &MainWindow::onRemoveActionClicked);

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

// 激活窗口并显示在最前面
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-color: #ffebee;"
            "  color: #c62828;"
            "  border: 2px solid #ffcdd2;"
            "  padding: 14px;"
            "  border-radius: 8px;"
            "  font-weight: 600;"
            "  font-size: 14px;"
            "}"
        );
    } else if (isSuccess) {
        statusLabel->setStyleSheet(
            "QLabel {"
            "  background-color: #e8f5e9;"
            "  color: #2e7d32;"
            "  border: 2px solid #c8e6c9;"
            "  padding: 14px;"
            "  border-radius: 8px;"
            "  font-weight: 600;"
            "  font-size: 14px;"
            "}"
        );
    } else {
        statusLabel->setStyleSheet(
            "QLabel {"
            "  background-color: #e3f2fd;"
            "  color: #1565c0;"
            "  border: 2px solid #bbdefb;"
            "  padding: 14px;"
            "  border-radius: 8px;"
            "  font-weight: 600;"
            "  font-size: 14px;"
            "}"
        );
    }

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

// 开始倒计时
void MainWindow::startCountdown(int seconds)
{
    countdownSeconds = seconds;

    QString modeText;
    if (isRepeatingSequence) {
        if (isInfiniteSequenceRepeat) {
            modeText = "无限重复执行序列";
        } else {
            modeText = QString("重复执行序列 (%1次)").arg(totalSequenceRepeat);
        }
    } else {
        modeText = "执行序列";
    }

    showStatusMessage(QString("⏱️ 倒计时: %1 秒后开始%2...").arg(countdownSeconds).arg(modeText));
    countdownTimer->start();
}

// 转换延迟值为毫秒
int MainWindow::delayToMilliseconds(double seconds)
{
    return static_cast<int>(seconds * 1000);
}

// 开始执行序列
void MainWindow::startSequenceExecution(bool repeatMode)
{
    if (actionList.empty()) {
        showStatusMessage("⚠️ 动作列表为空,请先添加动作", true);
        QMessageBox::warning(this, "警告", "动作列表为空,请先添加动作!");
        return;
    }

    if (isRepeating) {
        isRepeating = false;
        repeatTimer->stop();
        clickButton->setText("🎯 开始重复点击");
        showStatusMessage("⏹️ 重复点击已停止", false, true);
    }

    // 设置执行模式
    isRepeatingSequence = repeatMode;
    isInfiniteSequenceRepeat = infiniteSequenceRepeatCheck->isChecked();

    // 设置重复次数
    if (isRepeatingSequence) {
        if (isInfiniteSequenceRepeat) {
            totalSequenceRepeat = 0;  // 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);

    // 开始3秒倒计时
    startCountdown(3);
    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(action.delay));

    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)
{
    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];

        // ID
        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));  // 存储ID作为用户数据
        actionTable->setItem(i, 0, idItem);

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

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

        // 延迟时间(秒)
        QTableWidgetItem *delayItem = new QTableWidgetItem(QString::number(action.delay, 'f', 2));
        delayItem->setTextAlignment(Qt::AlignCenter);
        actionTable->setItem(i, 3, delayItem);

        // 按键类型
        QTableWidgetItem *buttonItem = new QTableWidgetItem(action.leftButton ? "左键" : "右键");
        buttonItem->setTextAlignment(Qt::AlignCenter);
        actionTable->setItem(i, 4, buttonItem);

        // 是否双击
        QTableWidgetItem *doubleItem = new QTableWidgetItem(action.doubleClick ? "是" : "否");
        doubleItem->setTextAlignment(Qt::AlignCenter);
        actionTable->setItem(i, 5, doubleItem);
    }

    // 重新连接信号
    actionTable->blockSignals(false);

    // 调整表格行高
    resizeEvent(nullptr);
}

// 保存动作到文件 - 使用QDataStream二进制格式
void MainWindow::saveActionsToFile()
{
    QFile file("actions.dat");
    if (file.open(QIODevice::WriteOnly)) {
        QDataStream out(&file);
        out.setVersion(QDataStream::Qt_5_12);

        // 写入文件版本标识(用于兼容性)
        out << QString("CLICKER_V4");

        // 写入动作数量
        out << (int)actionList.size();

        for (const auto& action : actionList) {
            out << action.id
                << action.x
                << action.y
                << action.delay
                << action.leftButton
                << action.doubleClick
                << action.description;
        }

        file.close();
        qDebug() << "动作已保存到文件,数量:" << actionList.size();
    } else {
        qDebug() << "无法打开文件进行保存";
    }
}

// 从文件加载动作 - 使用QDataStream二进制格式
void MainWindow::loadActionsFromFile()
{
    QFile file("actions.dat");
    if (file.open(QIODevice::ReadOnly)) {
        QDataStream in(&file);
        in.setVersion(QDataStream::Qt_5_12);

        // 检查文件版本
        QString fileVersion;
        in >> fileVersion;

        if (fileVersion != "CLICKER_V4" && fileVersion != "CLICKER_V3" && fileVersion != "CLICKER_V2") {
            // 旧版本文件,不加载
            qDebug() << "检测到旧版本文件,跳过加载";
            file.close();
            return;
        }

        int count;
        in >> count;

        qDebug() << "从文件加载动作,数量:" << count;

        for (int i = 0; i < count; ++i) {
            ClickAction action;
            in >> action.id
               >> action.x
               >> action.y
               >> action.delay
               >> action.leftButton
               >> action.doubleClick
               >> action.description;

            // 如果是旧版本数据(延迟为int),需要转换
            if (action.delay < 0.01 && action.delay > 0) {
                // 可能是旧的毫秒值,转换为秒
                action.delay = action.delay / 1000.0;
            }

            actionList.push_back(action);
            nextActionId = qMax(nextActionId, action.id + 1);
        }

        updateActionTable();
        file.close();

        if (!actionList.empty()) {
            showStatusMessage(QString("✅ 已加载 %1 个动作").arg(actionList.size()), false, true);
        }

        qDebug() << "动作加载完成,当前动作数量:" << actionList.size();
    } else {
        qDebug() << "无法打开动作文件或文件不存在";
    }
}

// 重复点击状态改变
void MainWindow::onRepeatStateChanged(int state)
{
    bool enabled = (state == Qt::Checked);
    repeatCountSpinBox->setEnabled(enabled);
    infiniteRepeatCheck->setEnabled(enabled);

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

        // 如果正在重复点击,停止它
        if (isRepeating) {
            isRepeating = false;
            repeatTimer->stop();
            clickButton->setText("🎯 立即点击");
            executeSequenceButton->setEnabled(true);
            repeatSequenceButton->setEnabled(true);

            // 激活窗口
            activateAndShowWindow();
        }
    }
}

// 重复次数改变
void MainWindow::onRepeatCountChanged(int value)
{
    infiniteRepeatCheck->setChecked(false);
}

// 序列无限循环状态改变
void MainWindow::onInfiniteSequenceRepeatChanged(int state)
{
    bool enabled = (state == Qt::Checked);
    sequenceRepeatSpinBox->setEnabled(!enabled);
}

// ========== 基础功能槽函数 ==========
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();
            clickButton->setText("🎯 开始重复点击");
            showStatusMessage("⏹️ 重复点击已停止", false, true);
            executeSequenceButton->setEnabled(true);
            repeatSequenceButton->setEnabled(true);
            progressBar->setValue(0);
            progressLabel->setText("就绪");

            // 激活窗口
            activateAndShowWindow();
        } else {
            // 开始重复点击
            isRepeating = true;
            stopRequested = false;

            // 设置重复次数
            if (infiniteRepeatCheck->isChecked()) {
                totalRepeatCount = 0;  // 0表示无限
                currentRepeatCount = 0;
            } else {
                totalRepeatCount = repeatCountSpinBox->value();
                currentRepeatCount = repeatCountSpinBox->value();
            }

            int delayMs = delayToMilliseconds(delaySeconds);
            repeatTimer->start(delayMs);
            clickButton->setText("⏹️ 停止重复点击");

            if (infiniteRepeatCheck->isChecked()) {
                showStatusMessage(QString("🔁 开始无限重复点击 (间隔: %1秒)").arg(delaySeconds));
            } else {
                showStatusMessage(QString("🔁 开始重复点击 %1 次 (间隔: %2秒)").arg(totalRepeatCount).arg(delaySeconds));
            }

            // 立即执行第一次点击
            clickAt(x, y, leftButton, doubleClick);
            if (totalRepeatCount > 0) {
                currentRepeatCount--;
            }

            // 如果是有限次数,检查是否完成
            if (totalRepeatCount > 0 && currentRepeatCount <= 0) {
                isRepeating = false;
                repeatTimer->stop();
                clickButton->setText("🎯 开始重复点击");
                showStatusMessage(QString("✅ 重复点击完成,共 %1 次").arg(totalRepeatCount), false, true);
                executeSequenceButton->setEnabled(true);
                repeatSequenceButton->setEnabled(true);
                progressBar->setValue(100);
                progressLabel->setText("完成");

                // 激活窗口
                activateAndShowWindow();
            } else {
                // 禁用其他按钮
                executeSequenceButton->setEnabled(false);
                repeatSequenceButton->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);

        // 更新状态1秒后恢复
        QTimer::singleShot(1000, this, [this]() {
            showStatusMessage("✅ 就绪", false, true);
        });
    }
}

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::onRepeatTimeout()
{
    if (stopRequested) {
        isRepeating = false;
        repeatTimer->stop();
        clickButton->setText("🎯 开始重复点击");
        showStatusMessage("⏹️ 重复点击已停止", false, true);
        executeSequenceButton->setEnabled(true);
        repeatSequenceButton->setEnabled(true);
        progressBar->setValue(0);
        progressLabel->setText("就绪");

        // 激活窗口
        activateAndShowWindow();
        return;
    }

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

    // 执行点击
    clickAt(x, y, leftButton, doubleClick);

    // 更新计数(如果是有限次数)
    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);
            progressBar->setValue(100);
            progressLabel->setText("完成");

            // 激活窗口
            activateAndShowWindow();
        }
    }

    updateProgressInfo();
}

// ========== 倒计时相关 ==========
void MainWindow::onCountdownTimeout()
{
    countdownSeconds--;

    if (countdownSeconds > 0) {
        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();

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

    // 验证延迟范围
    if (delaySeconds < 0.01 || delaySeconds > 10800.0) {
        showStatusMessage("⚠️ 延迟时间必须在0.01秒到3小时之间!", true);
        QMessageBox::warning(this, "警告", "延迟时间必须在0.01秒到3小时之间!");
        return;
    }

    QString description = QString("动作 %1: (%2, %3) 延迟: %4秒")
                         .arg(nextActionId).arg(x).arg(y).arg(delaySeconds);

    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::onExecuteSequenceClicked()
{
    startSequenceExecution(false);  // 单次执行模式
}

void MainWindow::onRepeatSequenceClicked()
{
    startSequenceExecution(true);  // 重复执行模式
}

void MainWindow::onStopSequenceClicked()
{
    stopRequested = true;
    isSequenceRunning = false;
    isRepeatingSequence = false;
    isInfiniteSequenceRepeat = false;
    sequenceTimer->stop();
    countdownTimer->stop();

    // 更新按钮状态
    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);

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

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

    // 高亮显示当前执行的行
    if (currentActionIndex < actionTable->rowCount()) {
        // 清除之前的高亮
        for (int i = 0; i < actionTable->rowCount(); ++i) {
            for (int j = 0; j < actionTable->columnCount(); ++j) {
                QTableWidgetItem *item = actionTable->item(i, j);
                if (item) {
                    // 如果是之前高亮的行,清除背景色
                    if (i == currentActionIndex - 1) {
                        item->setBackground(QBrush());
                        item->setForeground(QBrush());
                    }
                    // 当前执行行设置高亮
                    if (i == currentActionIndex) {
                        item->setBackground(QColor(255, 235, 180));  // 浅黄色背景
                        item->setForeground(QColor(102, 60, 0));     // 深棕色文字
                        item->setFont(QFont("", -1, QFont::Bold));   // 加粗字体
                    }
                }
            }
        }
        actionTable->scrollToItem(actionTable->item(currentActionIndex, 0), QAbstractItemView::EnsureVisible);
    }

    // 移动到下一个动作
    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];

        switch (column) {
        case 1: // X坐标
            action.x = item->text().toInt();
            break;
        case 2: // Y坐标
            action.y = item->text().toInt();
            break;
        case 3: // 延迟时间(秒)
            action.delay = item->text().toDouble();
            // 验证延迟范围
            if (action.delay < 0.01 || action.delay > 10800.0) {
                action.delay = qBound(0.01, action.delay, 10800.0);
                item->setText(QString::number(action.delay, 'f', 2));
                showStatusMessage("⚠️ 延迟时间已自动调整到有效范围", true);
            }
            break;
        case 4: // 按键类型
            action.leftButton = (item->text() == "左键");
            break;
        case 5: // 是否双击
            action.doubleClick = (item->text() == "是");
            break;
        }

        // 更新描述
        action.description = QString("动作 %1: (%2, %3) 延迟: %4秒")
                           .arg(action.id).arg(action.x).arg(action.y).arg(action.delay);

        showStatusMessage(QString("📝 已更新动作 %1").arg(action.id), false, true);
    }
}

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

main.cpp

cpp 复制代码
#include "mainwindow.h"
#include <QApplication>
#include <QTextCodec>

int main(int argc, char *argv[])
{
    // 设置应用程序编码
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));

    QApplication app(argc, argv);

    // 设置应用程序信息
    app.setApplicationName("动作序列鼠标点击器");
    app.setApplicationVersion("1.0");

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

    return app.exec();
}

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

一、软件简介

智能鼠标点击器是一款功能强大的Windows自动化工具,支持:

  • 基础点击功能:单次点击、重复点击(支持无限循环)

  • 动作序列功能:创建、编辑、执行复杂的鼠标点击序列

  • 全局热键控制:即使软件不在前台也能控制

  • 坐标拾取功能:快速获取鼠标当前位置

  • 进度可视化:实时显示执行进度

  • 数据保存:自动保存动作列表


二、系统要求

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

  • 运行环境:需要安装Qt运行库或编译为独立可执行文件

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


三、界面布局

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

  • X/Y坐标输入框:设置点击位置的屏幕坐标

  • 延迟时间:设置点击间隔(0.01秒~3小时)

  • 拾取坐标按钮:快速获取当前鼠标位置

  • 点击选项:选择左键/右键、单击/双击

  • 重复点击设置:启用重复点击、设置次数或无限循环

  • 立即点击按钮:执行点击操作

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

  • 动作表格:显示所有已添加的动作

    • ID:动作编号(自动生成)

    • X/Y坐标:点击位置

    • 延迟:执行后等待时间

    • 按键:左键或右键

    • 双击:是否执行双击操作

  • 序列重复设置:设置序列重复次数或无限循环

  • 控制按钮:添加、移除、清空、执行、停止动作序列

3.3 状态显示区域

  • 进度条:显示当前执行进度

  • 进度文本:显示详细执行信息

  • 状态栏:显示软件当前状态和提示信息

  • 光标位置:实时显示鼠标当前位置


四、基础功能介绍

4.1 单次点击

  1. 设置坐标

    • 手动输入X、Y坐标值

    • 或点击"拾取坐标"按钮,移动鼠标到目标位置后按空格键

  2. 配置点击参数

    • 选择点击按钮(左键/右键)

    • 选择点击类型(单击/双击)

    • 设置延迟时间(如果需要)

  3. 执行点击

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

    • 点击"立即点击"按钮

    • 或按快捷键Ctrl+S

4.2 重复点击

  1. 启用重复功能

    • 勾选"🔁 启用重复点击"

    • 设置重复次数(或勾选"无限循环")

  2. 开始重复点击

    • 点击"立即点击"按钮(按钮文本变为"⏹️ 停止重复点击")

    • 软件会按照设定的间隔重复执行点击

  3. 停止重复点击

    • 再次点击"立即点击"按钮

    • 或按Ctrl+C(全局热键)

    • 或按Esc

4.3 坐标拾取技巧

  • 快速拾取 :随时按空格键可拾取当前鼠标位置

  • 精确拾取:点击"拾取坐标"按钮进入拾取模式,移动鼠标到目标位置后按空格键


五、动作序列功能

5.1 创建动作序列

方法一:逐个添加动作
  1. 在基础区域设置好点击参数

  2. 点击"➕ 添加动作"按钮(快捷键:Ctrl+A

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

方法二:编辑已有动作
  • 修改参数:双击表格中的单元格直接编辑

  • 调整顺序:目前不支持直接拖拽,需按执行顺序添加

5.2 管理动作序列

  • 删除动作 :选中表格中的行,点击"➖ 移除动作"(快捷键:Ctrl+D

  • 清空所有:点击"🗑️ 清空动作"按钮(需确认)

  • 自动保存:退出软件时自动保存,下次启动自动加载

5.3 执行动作序列

单次执行序列
  1. 添加至少一个动作到序列

  2. 点击"▶️ 执行序列"按钮(快捷键:Ctrl+S

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

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

重复执行序列
  1. 设置重复次数(或勾选"无限循环")

  2. 点击"🔁 重复执行序列"按钮(快捷键:Ctrl+R

  3. 序列会按照设定的次数重复执行

停止执行
  • 点击"⏹️ 停止序列"按钮

  • 或按Ctrl+C(全局热键,即使软件最小化也有效)

  • 或按Esc

5.4 序列执行说明

  • 倒计时机制:开始执行前有3秒倒计时,便于准备

  • 进度显示:执行过程中显示详细进度信息

  • 表格高亮:当前执行的动作行会高亮显示

  • 自动滚动:表格会自动滚动到当前执行的动作


六、快捷键说明

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

快捷键 功能 说明
空格键 拾取坐标 拾取当前鼠标位置到X/Y输入框
Ctrl+C 停止所有操作 全局热键,即使软件不在前台也有效
Esc 停止当前操作 停止正在执行的点击或序列

窗口内快捷键

快捷键 功能 说明
Ctrl+S 开始/停止 根据情况开始或停止操作
Ctrl+R 重复执行序列 开始重复执行动作序列
Ctrl+A 添加动作 将当前设置添加到动作序列
Ctrl+D 删除动作 删除选中的动作

七、高级功能

7.1 无限循环模式

基础点击无限循环
  1. 勾选"启用重复点击"

  2. 勾选"无限循环"

  3. 点击"立即点击"开始

  4. Ctrl+CEsc停止

动作序列无限循环
  1. 添加动作到序列

  2. 勾选"无限循环"

  3. 点击"重复执行序列"

  4. 序列将无限重复执行直到手动停止

7.2 延迟时间设置

  • 范围:0.01秒 ~ 3小时(10800秒)

  • 精度:支持两位小数(0.01秒)

  • 用途

    • 重复点击间隔

    • 动作序列中动作之间的等待时间

7.3 坐标范围

  • X坐标:0 ~ (屏幕宽度-1)

  • Y坐标:0 ~ (屏幕高度-1)

  • 自动限制:输入超出范围的值会自动调整

7.4 数据持久化

  • 自动保存 :退出程序时自动保存动作序列到actions.dat文件

  • 自动加载:启动程序时自动加载上次保存的动作序列

  • 文件位置 :与程序同目录下的actions.dat文件


八、常见问题

Q1: 点击没有反应怎么办?

可能原因及解决方法:

  1. 坐标超出屏幕范围:检查坐标值是否在屏幕范围内

  2. 目标窗口被遮挡:确保目标窗口在最前面

  3. 权限问题:尝试以管理员身份运行程序

  4. 防病毒软件拦截:检查防病毒软件是否阻止了程序

Q2: 全局热键Ctrl+C无效?

解决方法:

  1. 确保程序正在运行

  2. 检查是否有其他程序占用了Ctrl+C热键

  3. 以管理员身份重新启动程序

Q3: 动作序列执行顺序错乱?

可能原因:

  1. 延迟时间设置过短,系统来不及响应

  2. 动作之间没有足够的等待时间
    建议: 适当增加延迟时间,特别是连续点击相同位置时

Q4: 如何精确设置坐标?

建议方法:

  1. 使用"拾取坐标"功能配合空格键

  2. 对于需要精确计算的位置,可以使用屏幕标尺工具

  3. 先设置大致位置,再通过微调找到最佳位置

Q5: 程序崩溃或异常退出?

处理措施:

  1. 重新启动程序

  2. 检查actions.dat文件是否损坏(可删除该文件让程序重新创建)

  3. 查看Windows事件查看器中的错误日志


九、注意事项

9.1 使用建议

  1. 测试再使用:正式使用前先用少量次数测试

  2. 合理设置延迟:避免设置过短的延迟导致系统响应不过来

  3. 注意目标窗口:确保执行时目标窗口处于活动状态

  4. 备份动作序列 :定期备份actions.dat文件

9.2 安全提示

  1. 合法使用:请勿用于游戏作弊等非法用途

  2. 避免滥用:不要设置过快的点击频率,避免对系统造成负担

  3. 注意隐私:不要在涉及隐私信息的窗口使用自动点击

9.3 性能优化

  1. 减少动作数量:动作序列过长可能影响执行稳定性

  2. 适当增加延迟:在连续操作之间留出足够时间

  3. 关闭不必要的程序:执行时关闭其他占用资源的程序

9.4 故障处理

  1. 停止无效时:尝试多次按Ctrl+C或Esc

  2. 程序无响应:通过任务管理器结束进程

  3. 配置丢失 :删除actions.dat文件后重新配置


十、更新日志

  • 版本1.0(当前版本)

    • 基础点击功能(单次、重复、无限循环)

    • 动作序列管理(添加、编辑、删除、执行)

    • 全局热键支持(Ctrl+C停止所有操作)

    • 进度可视化显示

    • 数据自动保存/加载

    • 快捷键支持(空格键拾取坐标等)

注意:本软件为免费工具,不提供技术支持。使用过程中请自行承担风险。

相关推荐
love530love2 小时前
Windows 11 下 Z-Image-Turbo 完整部署与 Flash Attention 2.8.3 本地编译复盘
人工智能·windows·python·aigc·flash-attn·z-image·cuda加速
Liu-Eleven6 小时前
Qt/C++开发嵌入式项目日志库选型
开发语言·c++·qt
Halo_tjn6 小时前
Java IO流实现文件操作知识点
java·开发语言·windows·算法
FL16238631296 小时前
VTK源码编译时候选qt5路径
开发语言·qt
love530love6 小时前
Windows 下 Z-Image-Turbo 专业版 Gradio 生成器实战:功能增强全记录
人工智能·windows·python·大模型·gradio·博客之星·z-image
離離原上譜9 小时前
Windows 环境下 Node.js + Claude Code 安装与配置教程
windows·node.js
小鸡脚来咯9 小时前
怎么配置主机名映射?
linux·windows·macos
龚建波10 小时前
《QDebug 2025年12月》
qt
石像鬼₧魂石11 小时前
SQLMap 注入完整操作流程(新手通关手册)
linux·人工智能·windows·学习