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停止所有操作)

    • 进度可视化显示

    • 数据自动保存/加载

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

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

相关推荐
caimouse3 小时前
Reactos 第 5 章 进程与线程 — 5.8 Windows 的 APC 机制
c语言·windows
PHP隔壁老王邻居3 小时前
windows菜单搜索栏无法显示历史记录或者无法使用修复方法
windows
道一234 小时前
Windows系统查看端口占用进程的3种实用方法
windows·笔记
半条-咸鱼4 小时前
【INACCESSIBLE_BOOT_DEVICE】安装 Config Tool 后 Windows 蓝屏,最终通过 VMware 虚拟机解决
windows·stm32·vmware·芯片
人工小情绪5 小时前
Windows 安装 Codex 桌面版,并用 CC Switch 管理配置
人工智能·windows·codex·cc switch
ytttr8735 小时前
Qt 数字键盘实现
开发语言·qt
hoiii1876 小时前
Qt 实现屏幕截图功能
开发语言·qt·命令模式
满天星83035777 小时前
【Qt】信号和槽(三) (断开连接和lambda函数)
qt
caimouse7 小时前
Reactos 第 5 章 进程与线程 — 5.11 线程本地存储 TLS
c语言·windows
fpcc7 小时前
C++编程实践—C++实现类似Qt的信号槽机制
c++·qt