diff --git a/i18n/MouseClick_en_US.ts b/i18n/MouseClick_en_US.ts
index 6d6df54..fe190c6 100644
--- a/i18n/MouseClick_en_US.ts
+++ b/i18n/MouseClick_en_US.ts
@@ -79,6 +79,21 @@
Set Max Random Interval
Set Max Random Interval
+
+
+ Random Click Offset
+ Random Click Offset
+
+
+
+ Set Max Random Offset
+ Set Max Random Offset
+
+
+
+ px
+ px
+
Memory Configuration
diff --git a/i18n/MouseClick_zh_CN.ts b/i18n/MouseClick_zh_CN.ts
index 9988634..d95f61f 100644
--- a/i18n/MouseClick_zh_CN.ts
+++ b/i18n/MouseClick_zh_CN.ts
@@ -79,6 +79,21 @@
Set Max Random Interval
最大随机时间
+
+
+ Random Click Offset
+ 随机点击偏移
+
+
+
+ Set Max Random Offset
+ 最大随机偏移
+
+
+
+ px
+ 像素
+
Memory Configuration
diff --git a/i18n/MouseClick_zh_TW.ts b/i18n/MouseClick_zh_TW.ts
index d18aac1..9451b8f 100644
--- a/i18n/MouseClick_zh_TW.ts
+++ b/i18n/MouseClick_zh_TW.ts
@@ -79,6 +79,21 @@
Set Max Random Interval
最大隨機時間
+
+
+ Random Click Offset
+ 隨機點擊偏移
+
+
+
+ Set Max Random Offset
+ 最大隨機偏移
+
+
+
+ px
+ 像素
+
Memory Configuration
diff --git a/src/modules/nav_pages/mouseclickpage.cpp b/src/modules/nav_pages/mouseclickpage.cpp
index 809b197..93b7095 100644
--- a/src/modules/nav_pages/mouseclickpage.cpp
+++ b/src/modules/nav_pages/mouseclickpage.cpp
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include
#include "../../utils/clicker.h"
@@ -153,7 +154,11 @@ MouseClickPage::MouseClickPage(const QString& title, SettingsPage& settings_page
random_interval_time->setMinimum(0.02);
random_interval_time->setSingleStep(0.01);
random_interval_time->setValue(app_settings.RandomIntervalTime());
- random_interval_time->setEnabled(false);
+ random_interval_time->setEnabled(random_interval_toggle_btn->isChecked());
+
+ if (random_interval_toggle_btn->isChecked()) {
+ interval_time->setEnabled(false);
+ }
random_interval_time_content_layout->addWidget(random_interval_time_desc);
random_interval_time_content_layout->addWidget(random_interval_time);
@@ -161,6 +166,61 @@ MouseClickPage::MouseClickPage(const QString& title, SettingsPage& settings_page
/********************/
+ QWidget* random_offset_toggle_content = new QWidget(page_content);
+ random_offset_toggle_content->setFixedHeight(pageContentUniformHeight);
+
+ QHBoxLayout* random_offset_toggle_content_layout = new QHBoxLayout(random_offset_toggle_content);
+ random_offset_toggle_content_layout->setSpacing(0);
+ random_offset_toggle_content_layout->setContentsMargins(QMargins());
+
+ QLabel* random_offset_toggle_desc = new QLabel(random_offset_toggle_content);
+ random_offset_toggle_desc->setObjectName(QStringLiteral("random-offset-toggle-desc"));
+ random_offset_toggle_desc->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ random_offset_toggle_desc->setFocusPolicy(Qt::NoFocus);
+ random_offset_toggle_desc->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+ random_offset_toggle_desc->setText(tr("Random Click Offset"));
+
+ QRadioButton* random_offset_toggle_btn = new QRadioButton(random_offset_toggle_content);
+ random_offset_toggle_btn->setObjectName(QStringLiteral("random-offset-toggle-btn"));
+ random_offset_toggle_btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ random_offset_toggle_btn->setChecked(app_settings.EnableRandomOffset());
+
+ random_offset_toggle_content_layout->addWidget(random_offset_toggle_desc);
+ random_offset_toggle_content_layout->addWidget(random_offset_toggle_btn);
+ random_offset_toggle_content->setLayout(random_offset_toggle_content_layout);
+
+ /********************/
+
+ QWidget* random_offset_distance_content = new QWidget(page_content);
+ random_offset_distance_content->setFixedHeight(pageContentUniformHeight);
+
+ QHBoxLayout* random_offset_distance_content_layout = new QHBoxLayout(random_offset_distance_content);
+ random_offset_distance_content_layout->setSpacing(0);
+ random_offset_distance_content_layout->setContentsMargins(QMargins());
+
+ QLabel* random_offset_distance_desc = new QLabel(random_offset_distance_content);
+ random_offset_distance_desc->setObjectName(QStringLiteral("random-offset-distance-desc"));
+ random_offset_distance_desc->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ random_offset_distance_desc->setFocusPolicy(Qt::NoFocus);
+ random_offset_distance_desc->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+ random_offset_distance_desc->setText(tr("Set Max Random Offset"));
+
+ QSpinBox* random_offset_distance = new QSpinBox(random_offset_distance_content);
+ random_offset_distance->setObjectName(QStringLiteral("random-offset-distance"));
+ random_offset_distance->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ random_offset_distance->setSuffix(tr(" px"));
+ random_offset_distance->setMaximum(1000);
+ random_offset_distance->setMinimum(0);
+ random_offset_distance->setSingleStep(1);
+ random_offset_distance->setValue(app_settings.RandomOffsetDistance());
+ random_offset_distance->setEnabled(random_offset_toggle_btn->isChecked());
+
+ random_offset_distance_content_layout->addWidget(random_offset_distance_desc);
+ random_offset_distance_content_layout->addWidget(random_offset_distance);
+ random_offset_distance_content->setLayout(random_offset_distance_content_layout);
+
+ /********************/
+
QWidget* memory_configuration_toggle_content = new QWidget(page_content);
memory_configuration_toggle_content->setFixedHeight(pageContentUniformHeight);
@@ -190,6 +250,8 @@ MouseClickPage::MouseClickPage(const QString& title, SettingsPage& settings_page
page_content_layout->addWidget(interval_time_content);
page_content_layout->addWidget(random_interval_toggle_content);
page_content_layout->addWidget(random_interval_time_content);
+ page_content_layout->addWidget(random_offset_toggle_content);
+ page_content_layout->addWidget(random_offset_distance_content);
page_content_layout->addWidget(memory_configuration_toggle_content);
page_content_layout->addStretch();
@@ -210,6 +272,12 @@ MouseClickPage::MouseClickPage(const QString& title, SettingsPage& settings_page
});
connect(random_interval_time, &QDoubleSpinBox::valueChanged, &SettingsAgent::instance(), &SettingsAgent::setRandomIntervalTime);
+ connect(random_offset_toggle_btn, &QRadioButton::toggled, random_offset_distance, [random_offset_distance](bool checked) {
+ random_offset_distance->setEnabled(checked);
+ SettingsAgent::instance().setEnableRandomOffset(checked);
+ });
+
+ connect(random_offset_distance, &QSpinBox::valueChanged, &SettingsAgent::instance(), &SettingsAgent::setRandomOffsetDistance);
connect(memory_configuration_toggle_btn, &QRadioButton::toggled, &SettingsAgent::instance(), &SettingsAgent::setEnableMemoryConfiguration);
// hotkey event
@@ -223,6 +291,8 @@ MouseClickPage::MouseClickPage(const QString& title, SettingsPage& settings_page
interval_time->setEnabled(!random_interval_toggle_btn->isChecked());
random_interval_toggle_btn->setEnabled(true);
random_interval_time->setEnabled(random_interval_toggle_btn->isChecked());
+ random_offset_toggle_btn->setEnabled(true);
+ random_offset_distance->setEnabled(random_offset_toggle_btn->isChecked());
memory_configuration_toggle_btn->setEnabled(true);
} else {
Qt::MouseButton btn_type;
@@ -239,14 +309,19 @@ MouseClickPage::MouseClickPage(const QString& title, SettingsPage& settings_page
int interval = static_cast(interval_time->value() * 1000); // 转为毫秒值
bool random_interval_flag = random_interval_toggle_btn->isChecked();
int max_random_interval = static_cast(random_interval_time->value() * 1000); // 转为毫秒值
+ bool random_offset_flag = random_offset_toggle_btn->isChecked();
+ int max_random_offset = random_offset_distance->value(); // 像素值
- NavPage::_clicker->initParameters(btn_type, interval, random_interval_flag, max_random_interval);
+ NavPage::_clicker->initParameters(btn_type, interval, random_interval_flag, max_random_interval,
+ random_offset_flag, max_random_offset);
NavPage::_clicker_thread->start(); // Note: This should be initiated through a sub-thread.
click_type_list->setEnabled(false);
interval_time->setEnabled(false);
random_interval_toggle_btn->setEnabled(false);
random_interval_time->setEnabled(false);
+ random_offset_toggle_btn->setEnabled(false);
+ random_offset_distance->setEnabled(false);
memory_configuration_toggle_btn->setEnabled(false);
}
});
diff --git a/src/modules/settingsagent.cpp b/src/modules/settingsagent.cpp
index 557f0a1..a73d764 100644
--- a/src/modules/settingsagent.cpp
+++ b/src/modules/settingsagent.cpp
@@ -102,6 +102,26 @@ void SettingsAgent::setRandomIntervalTime(const double random_interval_time)
_config["RandomIntervalTime"] = random_interval_time;
}
+bool SettingsAgent::EnableRandomOffset() const
+{
+ return _config["EnableRandomOffset"].toBool();
+}
+
+void SettingsAgent::setEnableRandomOffset(bool enable_random_offset)
+{
+ _config["EnableRandomOffset"] = enable_random_offset;
+}
+
+int SettingsAgent::RandomOffsetDistance() const
+{
+ return _config["RandomOffsetDistance"].toInt();
+}
+
+void SettingsAgent::setRandomOffsetDistance(const int random_offset_distance)
+{
+ _config["RandomOffsetDistance"] = random_offset_distance;
+}
+
bool SettingsAgent::EnableMemoryConfiguration() const
{
return _config["EnableMemoryConfiguration"].toBool();
@@ -159,6 +179,8 @@ SettingsAgent::SettingsAgent(QObject *parent)
_config["IntervalTime"] = settings.value("IntervalTime", _DEFAULT_INTERVALTIME);
_config["EnableRandomInterval"] = settings.value("EnableRandomInterval", _DEFAULT_RANDOMINTERVAL);
_config["RandomIntervalTime"] = settings.value("RandomIntervalTime", _DEFAULT_RANDOMINTERVALTIME);
+ _config["EnableRandomOffset"] = settings.value("EnableRandomOffset", _DEFAULT_RANDOMOFFSET);
+ _config["RandomOffsetDistance"] = settings.value("RandomOffsetDistance", _DEFAULT_RANDOMOFFSETDISTANCE);
_config["EnableMemoryConfiguration"] = settings.value("EnableMemoryConfiguration", _DEFAULT_MEMORYCONFIGURATION);
settings.endGroup();
@@ -187,6 +209,12 @@ SettingsAgent::SettingsAgent(QObject *parent)
if (!_config["RandomIntervalTime"].isValid() || _config["RandomIntervalTime"].metaType().id() == QMetaType::UnknownType) {
_config["RandomIntervalTime"] = _DEFAULT_RANDOMINTERVALTIME;
}
+ if (!_config["EnableRandomOffset"].isValid() || _config["EnableRandomOffset"].metaType().id() == QMetaType::UnknownType) {
+ _config["EnableRandomOffset"] = _DEFAULT_RANDOMOFFSET;
+ }
+ if (!_config["RandomOffsetDistance"].isValid() || _config["RandomOffsetDistance"].metaType().id() == QMetaType::UnknownType) {
+ _config["RandomOffsetDistance"] = _DEFAULT_RANDOMOFFSETDISTANCE;
+ }
if (!_config["EnableMemoryConfiguration"].isValid() || _config["EnableMemoryConfiguration"].metaType().id() == QMetaType::UnknownType) {
_config["EnableMemoryConfiguration"] = _DEFAULT_MEMORYCONFIGURATION;
}
@@ -214,6 +242,8 @@ SettingsAgent::SettingsAgent(QObject *parent)
_config["IntervalTime"] = _DEFAULT_INTERVALTIME;
_config["EnableRandomInterval"] = _DEFAULT_RANDOMINTERVAL;
_config["RandomIntervalTime"] = _DEFAULT_RANDOMINTERVALTIME;
+ _config["EnableRandomOffset"] = _DEFAULT_RANDOMOFFSET;
+ _config["RandomOffsetDistance"] = _DEFAULT_RANDOMOFFSETDISTANCE;
}
@@ -245,6 +275,8 @@ SettingsAgent::~SettingsAgent()
settings.setValue("IntervalTime", _config["IntervalTime"]);
settings.setValue("EnableRandomInterval", _config["EnableRandomInterval"]);
settings.setValue("RandomIntervalTime", _config["RandomIntervalTime"]);
+ settings.setValue("EnableRandomOffset", _config["EnableRandomOffset"]);
+ settings.setValue("RandomOffsetDistance", _config["RandomOffsetDistance"]);
settings.setValue("EnableMemoryConfiguration", _config["EnableMemoryConfiguration"]);
settings.endGroup();
}
diff --git a/src/modules/settingsagent.h b/src/modules/settingsagent.h
index 07902f1..9efa00f 100644
--- a/src/modules/settingsagent.h
+++ b/src/modules/settingsagent.h
@@ -41,6 +41,12 @@ class SettingsAgent : public QObject
double RandomIntervalTime() const;
void setRandomIntervalTime(const double random_interval_time);
+ bool EnableRandomOffset() const;
+ void setEnableRandomOffset(bool enable_random_offset);
+
+ int RandomOffsetDistance() const;
+ void setRandomOffsetDistance(const int random_offset_distance);
+
bool EnableMemoryConfiguration() const;
void setEnableMemoryConfiguration(bool memory_configuration);
/***********************************/
@@ -76,6 +82,8 @@ class SettingsAgent : public QObject
const double _DEFAULT_INTERVALTIME = 0.01;
const bool _DEFAULT_RANDOMINTERVAL = false;
const double _DEFAULT_RANDOMINTERVALTIME = 0.02;
+ const bool _DEFAULT_RANDOMOFFSET = false;
+ const int _DEFAULT_RANDOMOFFSETDISTANCE = 0;
const bool _DEFAULT_MEMORYCONFIGURATION = false;
};
diff --git a/src/utils/clicker.cpp b/src/utils/clicker.cpp
index 51828d1..2fcc458 100644
--- a/src/utils/clicker.cpp
+++ b/src/utils/clicker.cpp
@@ -13,7 +13,9 @@ Clicker::Clicker(QObject* parent)
_btn_type(Qt::LeftButton),
_interval(10),
_random_interval_flag(false),
- _max_random_interval(20)
+ _max_random_interval(20),
+ _random_offset_flag(false),
+ _max_random_offset(0)
{}
Clicker::~Clicker()
@@ -23,12 +25,16 @@ Clicker::~Clicker()
Clicker& Clicker::initParameters(Qt::MouseButton btnType,
int interval,
bool randomIntervalFlag,
- int maxRandomInterval)
+ int maxRandomInterval,
+ bool randomOffsetFlag,
+ int maxRandomOffset)
{
_btn_type = btnType;
_interval = interval;
_random_interval_flag = randomIntervalFlag;
_max_random_interval = maxRandomInterval;
+ _random_offset_flag = randomOffsetFlag;
+ _max_random_offset = maxRandomOffset;
return (*this);
}
@@ -86,13 +92,50 @@ void Clicker::msleep(int ms)
}
#if defined(Q_OS_WIN)
+POINT Clicker::randomClickPosition(const POINT& base_pos) const
+{
+ if (!_random_offset_flag || _max_random_offset <= 0) {
+ return base_pos;
+ }
+
+ int dx = 0;
+ int dy = 0;
+ const int max_offset_squared = _max_random_offset * _max_random_offset;
+ do {
+ dx = QRandomGenerator::global()->bounded(-_max_random_offset, _max_random_offset + 1);
+ dy = QRandomGenerator::global()->bounded(-_max_random_offset, _max_random_offset + 1);
+ } while (dx * dx + dy * dy > max_offset_squared);
+
+ POINT click_pos {base_pos.x + dx, base_pos.y + dy};
+
+ const int min_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
+ const int min_y = GetSystemMetrics(SM_YVIRTUALSCREEN);
+ const int max_x = min_x + GetSystemMetrics(SM_CXVIRTUALSCREEN) - 1;
+ const int max_y = min_y + GetSystemMetrics(SM_CYVIRTUALSCREEN) - 1;
+
+ click_pos.x = qBound(min_x, click_pos.x, max_x);
+ click_pos.y = qBound(min_y, click_pos.y, max_y);
+
+ return click_pos;
+}
+
+void Clicker::clickAtPosition(DWORD down_event, DWORD up_event, const POINT& base_pos, const POINT& click_pos) const
+{
+ SetCursorPos(click_pos.x, click_pos.y);
+ mouse_event(down_event | up_event, click_pos.x, click_pos.y, 0, 0);
+
+ if (click_pos.x != base_pos.x || click_pos.y != base_pos.y) {
+ SetCursorPos(base_pos.x, base_pos.y);
+ }
+}
+
void Clicker::leftClick()
{
POINT mouse_pos;
while (_run) {
GetCursorPos(&mouse_pos);
- mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, mouse_pos.x, mouse_pos.y, 0, 0);
+ clickAtPosition(MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, mouse_pos, randomClickPosition(mouse_pos));
msleep(_interval);
}
}
@@ -103,7 +146,7 @@ void Clicker::rightClick()
while (_run) {
GetCursorPos(&mouse_pos);
- mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, mouse_pos.x, mouse_pos.y, 0, 0);
+ clickAtPosition(MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, mouse_pos, randomClickPosition(mouse_pos));
msleep(_interval);
}
}
@@ -114,7 +157,7 @@ void Clicker::middleClick()
while (_run) {
GetCursorPos(&mouse_pos);
- mouse_event(MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_MIDDLEUP, mouse_pos.x, mouse_pos.y, 0, 0);
+ clickAtPosition(MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, mouse_pos, randomClickPosition(mouse_pos));
msleep(_interval);
}
}
@@ -125,7 +168,7 @@ void Clicker::leftRandomClick()
while (_run) {
GetCursorPos(&mouse_pos);
- mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, mouse_pos.x, mouse_pos.y, 0, 0);
+ clickAtPosition(MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, mouse_pos, randomClickPosition(mouse_pos));
msleep(QRandomGenerator::global()->bounded(0, _max_random_interval));
}
}
@@ -136,7 +179,7 @@ void Clicker::rightRandomClick()
while (_run) {
GetCursorPos(&mouse_pos);
- mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, mouse_pos.x, mouse_pos.y, 0, 0);
+ clickAtPosition(MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP, mouse_pos, randomClickPosition(mouse_pos));
msleep(QRandomGenerator::global()->bounded(0, _max_random_interval));
}
}
@@ -147,7 +190,7 @@ void Clicker::middleRandomClick()
while (_run) {
GetCursorPos(&mouse_pos);
- mouse_event(MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_MIDDLEUP, mouse_pos.x, mouse_pos.y, 0, 0);
+ clickAtPosition(MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, mouse_pos, randomClickPosition(mouse_pos));
msleep(QRandomGenerator::global()->bounded(0, _max_random_interval));
}
}
diff --git a/src/utils/clicker.h b/src/utils/clicker.h
index fb270db..cbfa715 100644
--- a/src/utils/clicker.h
+++ b/src/utils/clicker.h
@@ -5,6 +5,10 @@
#include
#include
+#if defined(Q_OS_WIN)
+#include
+#endif
+
class Clicker : public QObject
{
Q_OBJECT
@@ -14,7 +18,9 @@ class Clicker : public QObject
Clicker& initParameters(Qt::MouseButton btnType,
int interval,
bool randomIntervalFlag,
- int maxRandomInterval);
+ int maxRandomInterval,
+ bool randomOffsetFlag,
+ int maxRandomOffset);
public Q_SLOTS:
void start();
@@ -26,6 +32,8 @@ public Q_SLOTS:
int _interval;
bool _random_interval_flag;
int _max_random_interval;
+ bool _random_offset_flag;
+ int _max_random_offset;
QMutex _interrupt_sleep_immediately;
QWaitCondition _sleep_timer;
@@ -38,6 +46,11 @@ public Q_SLOTS:
void leftRandomClick();
void rightRandomClick();
void middleRandomClick();
+
+#if defined(Q_OS_WIN)
+ POINT randomClickPosition(const POINT& base_pos) const;
+ void clickAtPosition(DWORD down_event, DWORD up_event, const POINT& base_pos, const POINT& click_pos) const;
+#endif
};
#endif // CLICKER_H