文章附件下载:https://www.pan38.com/dow/share.php?code=JCnzE 提取密码:8035
代码功能说明:
提供三种点击模式:固定坐标点击、随机区域点击和录制回放功能
可自定义点击次数、间隔时间和点击持续时间
支持实时坐标选取功能,可视化选择屏幕点击位置
录制功能可记录多个点击点并保存为文件
状态实时显示,包含运行进度和操作反馈
完整的开始/停止控制,可随时中断运行
采用多线程处理,避免UI卡顿
包含错误处理和参数校验机制
// 屏幕自动点击器 v2.0
// 功能:支持随机点击、固定坐标点击、录制回放三种模式
"ui";
ui.layout(
<card cardCornerRadius="8" cardElevation="4" margin="0 0 16 0">
<vertical padding="8">
<text text="点击设置" textSize="18" textColor="#333"/>
<horizontal>
<text text="点击次数:" layout_weight="1"/>
<input id="click_count" text="100" inputType="number" layout_weight="2"/>
</horizontal>
<horizontal>
<text text="间隔(ms):" layout_weight="1"/>
<input id="interval" text="500" inputType="number" layout_weight="2"/>
</horizontal>
<horizontal>
<text text="点击时长(ms):" layout_weight="1"/>
<input id="duration" text="50" inputType="number" layout_weight="2"/>
</horizontal>
</vertical>
</card>
<card id="fixed_card" cardCornerRadius="8" cardElevation="4" margin="0 0 16 0">
<vertical padding="8">
<text text="固定坐标设置" textSize="18" textColor="#333"/>
<horizontal>
<text text="X坐标:" layout_weight="1"/>
<input id="x_pos" text="500" inputType="number" layout_weight="2"/>
</horizontal>
<horizontal>
<text text="Y坐标:" layout_weight="1"/>
<input id="y_pos" text="800" inputType="number" layout_weight="2"/>
</horizontal>
<button id="pick_pos" text="选取坐标" layout_weight="1"/>
</vertical>
</card>
<card id="random_card" visibility="gone" cardCornerRadius="8" cardElevation="4" margin="0 0 16 0">
<vertical padding="8">
<text text="随机区域设置" textSize="18" textColor="#333"/>
<horizontal>
<text text="左上X:" layout_weight="1"/>
<input id="left_x" text="100" inputType="number" layout_weight="2"/>
</horizontal>
<horizontal>
<text text="左上Y:" layout_weight="1"/>
<input id="top_y" text="200" inputType="number" layout_weight="2"/>
</horizontal>
<horizontal>
<text text="右下X:" layout_weight="1"/>
<input id="right_x" text="900" inputType="number" layout_weight="2"/>
</horizontal>
<horizontal>
<text text="右下Y:" layout_weight="1"/>
<input id="bottom_y" text="1600" inputType="number" layout_weight="2"/>
</horizontal>
</vertical>
</card>
<card id="record_card" visibility="gone" cardCornerRadius="8" cardElevation="4" margin="0 0 16 0">
<vertical padding="8">
<text text="录制回放" textSize="18" textColor="#333"/>
<horizontal>
<button id="record_btn" text="开始录制" layout_weight="1"/>
<button id="save_btn" text="保存记录" layout_weight="1"/>
<button id="load_btn" text="加载记录" layout_weight="1"/>
</horizontal>
</vertical>
</card>
<text id="status" text="状态: 待命" textSize="16" textColor="#666" gravity="center"/>
</vertical>
);
let running = false;
let mode = "fixed"; // fixed/random/record
let recordPoints = [];
let clickThread = null;
// 模式切换
ui.mode_btn.click(() => {
if (mode === "fixed") {
mode = "random";
ui.mode_btn.text("模式: 随机区域");
ui.fixed_card.setVisibility(View.GONE);
ui.random_card.setVisibility(View.VISIBLE);
ui.record_card.setVisibility(View.GONE);
} else if (mode === "random") {
mode = "record";
ui.mode_btn.text("模式: 录制回放");
ui.fixed_card.setVisibility(View.GONE);
ui.random_card.setVisibility(View.GONE);
ui.record_card.setVisibility(View.VISIBLE);
} else {
mode = "fixed";
ui.mode_btn.text("模式: 固定坐标");
ui.fixed_card.setVisibility(View.VISIBLE);
ui.random_card.setVisibility(View.GONE);
ui.record_card.setVisibility(View.GONE);
}
});
// 坐标选取
ui.pick_pos.click(() => {
toast("请在屏幕上点击选取坐标");
threads.start(function() {
let point = captureScreenAndPickPoint();
if (point) {
ui.run(() => {
ui.x_pos.text(point.x);
ui.y_pos.text(point.y);
});
}
});
});
// 开始点击
ui.start_btn.click(() => {
if (running) return;
running = true;
ui.status.text("状态: 运行中");
ui.start_btn.enabled = false;
ui.stop_btn.enabled = true;
let count = parseInt(ui.click_count.text()) || 100;
let interval = parseInt(ui.interval.text()) || 500;
let duration = parseInt(ui.duration.text()) || 50;
clickThread = threads.start(function() {
if (mode === "fixed") {
let x = parseInt(ui.x_pos.text()) || 500;
let y = parseInt(ui.y_pos.text()) || 800;
fixedClick(x, y, count, interval, duration);
} else if (mode === "random") {
let leftX = parseInt(ui.left_x.text()) || 100;
let topY = parseInt(ui.top_y.text()) || 200;
let rightX = parseInt(ui.right_x.text()) || 900;
let bottomY = parseInt(ui.bottom_y.text()) || 1600;
randomClick(leftX, topY, rightX, bottomY, count, interval, duration);
} else if (mode === "record" && recordPoints.length > 0) {
replayRecord(count, interval);
}
ui.run(() => {
running = false;
ui.status.text("状态: 已完成");
ui.start_btn.enabled = true;
ui.stop_btn.enabled = false;
});
});
});
// 停止点击
ui.stop_btn.click(() => {
if (clickThread) {
clickThread.interrupt();
}
running = false;
ui.status.text("状态: 已停止");
ui.start_btn.enabled = true;
ui.stop_btn.enabled = false;
});
// 录制功能
ui.record_btn.click(() => {
if (ui.record_btn.text() === "开始录制") {
ui.record_btn.text("停止录制");
recordPoints = [];
toast("开始录制,点击屏幕记录坐标");
threads.start(function() {
while (ui.record_btn.text() === "停止录制") {
let point = captureScreenAndPickPoint(true);
if (point) {
recordPoints.push(point);
ui.run(() => {
ui.status.text("已记录: " + recordPoints.length + "个点");
});
}
sleep(100);
}
});
} else {
ui.record_btn.text("开始录制");
toast("录制停止,共记录" + recordPoints.length + "个点");
}
});
// 保存记录
ui.save_btn.click(() => {
if (recordPoints.length === 0) {
toast("没有录制数据");
return;
}
let filename = "click_record_" + new Date().getTime() + ".json";
files.write(filename, JSON.stringify(recordPoints));
toast("已保存到: " + filename);
});
// 加载记录
ui.load_btn.click(() => {
let path = files.path("");
let filesList = files.listDir(path, function(name) {
return name.endsWith(".json");
});
dialogs.select("选择记录文件", filesList)
.then(file => {
if (file) {
let content = files.read(path + "/" + file);
recordPoints = JSON.parse(content);
toast("已加载" + recordPoints.length + "个点");
ui.status.text("已加载: " + recordPoints.length + "个点");
}
});
});
// 固定坐标点击
function fixedClick(x, y, count, interval, duration) {
for (let i = 0; i < count && running; i++) {
press(x, y, duration);
sleep(interval);
ui.run(() => {
ui.status.text("状态: 运行中 (" + (i + 1) + "/" + count + ")");
});
}
}
// 随机区域点击
function randomClick(leftX, topY, rightX, bottomY, count, interval, duration) {
for (let i = 0; i < count && running; i++) {
let x = random(leftX, rightX);
let y = random(topY, bottomY);
press(x, y, duration);
sleep(interval);
ui.run(() => {
ui.status.text("状态: 运行中 (" + (i + 1) + "/" + count + ")");
});
}
}
// 回放录制
function replayRecord(count, interval) {
for (let i = 0; i < count && running; i++) {
for (let j = 0; j < recordPoints.length && running; j++) {
let point = recordPoints[j];
press(point.x, point.y, point.duration || 50);
sleep(interval);
ui.run(() => {
ui.status.text("回放: " + (i + 1) + "/" + count + " 点: " + (j + 1) + "/" + recordPoints.length);
});
}
}
}
// 屏幕取点
function captureScreenAndPickPoint(isRecording) {
let img = captureScreen();
let window = floaty.window(
);
let point = null;
window.img.setOnTouchListener(function(view, event) {
if (event.getAction() === MotionEvent.ACTION_DOWN) {
point = {
x: event.getRawX(),
y: event.getRawY(),
duration: isRecording ? parseInt(ui.duration.text()) || 50 : null
};
window.close();
}
return true;
});
// 等待窗口关闭
while (window && window.getWindow() && window.getWindow().isShowing()) {
sleep(200);
}
return point;
}
// 生成随机数
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}