|
|
资讯缩略图:
资讯发布日期:2026-09-21
资讯发布简介:AIWROK 屏幕触摸事件监听工具
资讯关键词:AIWROK 屏幕触摸事件监听工具
资讯所属分类:IT资讯
联系:
① 本信息收集于网络,如有不对的地方欢迎联系我纠正! ② 本信息免费收录,不存在价格的问题! ③ 如果您的网站也想这样出现在这里,请您加好友情链接,我当天会审核通过!
④友情链接关键字:软件网站分类目录 网址:http://www.postbbs.com/
资讯详细描述
 | |  |  | AIWROK 屏幕触摸事件监听工具
- /**
- * ╔══════════════════════════════════════════════════╗
- * ║ AIWROK 屏幕触摸事件监听工具 ║
- * ║ (模拟 events.observeTouch 功能) ║
- * ╚══════════════════════════════════════════════════╝
- *
- * 核心能力:
- * ① 检测是否有 root 权限
- * ② 自动查找触摸设备节点(/dev/input/eventX)
- * ③ 实时解析触摸事件 → 回调 onTouchDown/Move/Up
- * ④ 自动坐标转换(ABS_MT_POSITION_X/Y)
- * ⑤ 提供 observeTouch() 统一入口
- *
- * 原理:通过 su + getevent -lt 读取 /dev/input/eventX 原始事件流
- *
- * 依赖:需要 root 权限(雷电/夜神/逍遥模拟器默认自带 root)
- */
- // ======================== Shell 执行工具 ========================
- /**
- * 统一 shell 执行入口
- * 优先用 AIWROK 自带的 agent.shell(已经处理了 root)
- * 兜底用 java.lang.Runtime.exec
- */
- function shellExec(cmd) {
- // 优先走 agent.shell
- if (typeof agent !== "undefined" && typeof agent.shell === "function") {
- try {
- var ret = agent.shell(cmd);
- return ret === null ? "" : ret.toString();
- } catch (e) {
- printl("[shell] agent.shell('" + cmd + "') 异常: " + e.message);
- }
- }
- // 兜底:Runtime.exec(不要 su -c,雷电自带 root 直接跑就行)
- try {
- var proc = java.lang.Runtime.getRuntime().exec(cmd);
- var reader = new java.io.BufferedReader(
- new java.io.InputStreamReader(proc.getInputStream())
- );
- var errReader = new java.io.BufferedReader(
- new java.io.InputStreamReader(proc.getErrorStream())
- );
- var sb = new java.lang.StringBuilder();
- var errSb = new java.lang.StringBuilder();
- var line;
- while ((line = reader.readLine()) !== null) {
- sb.append(line).append("\n");
- }
- while ((line = errReader.readLine()) !== null) {
- errSb.append(line).append("\n");
- }
- proc.waitFor();
- var stdout = sb.toString();
- var stderr = errSb.toString();
- if (stderr && stderr.length() > 0) {
- printl("[shell] cmd=" + cmd + " stderr=" + stderr.trim());
- }
- return stdout.trim();
- } catch (e2) {
- printl("[shell] Runtime.exec('" + cmd + "') 异常: " + e2.message);
- return "";
- }
- }
- // ======================== 设备检测 ========================
- /**
- * 检测设备是否有 root 权限
- * 直接跑 id 看 uid=0
- */
- function isRootAvailable() {
- // AIWROK 里 agent.shell 本身就需要 root 才能用
- if (typeof agent !== "undefined" && typeof agent.shell === "function") {
- try {
- var ret = shellExec("id");
- printl("[root检测] agent.shell('id') → " + ret);
- if (ret && ret.indexOf("uid=0") >= 0) return true;
- } catch (e) {}
- }
- // 再试 Runtime 方式
- try {
- var r2 = shellExec("id");
- printl("[root检测] Runtime exec('id') → " + r2);
- if (r2 && r2.indexOf("uid=0") >= 0) return true;
- } catch (e2) {}
- printl("[root检测] 所有策略均失败");
- return false;
- }
- /**
- * 查找触摸设备 eventX 节点
- * 策略1: cat /proc/bus/input/devices 找 Name 含 touch 的
- * 策略2(兜底): getevent -lp 找含 ABS_MT_POSITION_X/Y 的
- */
- function findTouchEventDevice() {
- // 先把每个 eventX 的完整配置都打出来
- printl("[触摸检测] ========= 所有设备完整信息 ==========");
- var allDev = shellExec("getevent -lp");
- // 按 "add device" 分段
- var devBlocks = allDev.split(/add device \d+: /);
- for (var b = 0; b < devBlocks.length; b++) {
- var block = devBlocks[b].trim();
- if (!block) continue;
- // 提取 eventX 名
- var evtMatch = block.match(/^\/dev\/input\/(event\d+)/);
- if (!evtMatch) continue;
- // 提取 name
- var nameMatch = block.match(/name:\s*"([^"]*)"/);
- // 提取 events 描述
- var eventsStr = "";
- var evMatch = block.match(/events:([\s\S]*?)(?=input props|add device|$)/);
- if (evMatch) eventsStr = evMatch[1].trim();
- printl("");
- printl(" 设备: " + evtMatch[1]);
- printl(" 名称: " + (nameMatch ? nameMatch[1] : "(无)"));
- // 只看前 300 字的 events,别太长
- printl(" events: " + eventsStr.substring(0, Math.min(300, eventsStr.length())));
- }
- printl("[触摸检测] ====================================");
- // 再扫一遍完整输出找触摸特征
- if (allDev && allDev.length() > 0) {
- var re = /add device \d+: \/dev\/input\/(event\d+)\s+name:\s*"([^"]*)"([\s\S]*?)(?=add device|$)/g;
- var m;
- while ((m = re.exec(allDev)) !== null) {
- var evtName = m[1];
- var devName = m[2].toLowerCase();
- var eventsInfo = m[3];
- // 策略 A: 名字含触摸关键词
- if (devName.indexOf("touch") >= 0 ||
- devName.indexOf("tsp") >= 0 ||
- devName.indexOf("panel") >= 0 ||
- devName.indexOf("goodix") >= 0 ||
- devName.indexOf("synaptics") >= 0) {
- printl("[触摸检测] ✓ 名字匹配: " + evtName + " (" + m[2] + ")");
- return evtName;
- }
- // 策略 B: events 含 ABS_MT_POSITION(多点触控)
- if (eventsInfo.indexOf("ABS_MT_POSITION_X") >= 0 &&
- eventsInfo.indexOf("ABS_MT_POSITION_Y") >= 0) {
- printl("[触摸检测] ✓ 多点触控特征: " + evtName + " (" + m[2] + ")");
- return evtName;
- }
- // 策略 C: events 含 BTN_TOUCH + ABS_X + ABS_Y(单点触控)
- if (eventsInfo.indexOf("BTN_TOUCH") >= 0 &&
- eventsInfo.indexOf("ABS_X") >= 0 &&
- eventsInfo.indexOf("ABS_Y") >= 0) {
- printl("[触摸检测] ✓ 单点触控特征: " + evtName + " (" + m[2] + ")");
- return evtName;
- }
- // 策略 D: HID 触摸(雷电常见)
- if ((devName.indexOf("hid") >= 0 || devName.indexOf("mouse") >= 0) &&
- eventsInfo.indexOf("BTN_TOUCH") >= 0) {
- printl("[触摸检测] ✓ HID 触摸: " + evtName + " (" + m[2] + ")");
- return evtName;
- }
- }
- }
- printl("[触摸检测] 所有策略均未找到触摸设备");
- return null;
- }
- // ======================== 触摸观察器 ========================
- /**
- * 触摸观察器
- * 后台线程跑 getevent -lt,解析后回调 down/move/up
- */
- function TouchObserver(eventDevice) {
- this.device = eventDevice;
- this.running = false;
- this.process = null;
- this.listeners = { down: [], move: [], up: [], touch: [] };
- this.currentX = -1;
- this.currentY = -1;
- this.currentPointer = -1;
- this.pointerDown = false;
- this._downFired = false;
- }
- TouchObserver.prototype.onDown = function (fn) { this.listeners.down.push(fn); };
- TouchObserver.prototype.onMove = function (fn) { this.listeners.move.push(fn); };
- TouchObserver.prototype.onUp = function (fn) { this.listeners.up.push(fn); };
- TouchObserver.prototype.onTouch = function (fn) { this.listeners.touch.push(fn); };
- TouchObserver.prototype._emit = function (type, ev) {
- var i, arr;
- // 专属回调
- arr = this.listeners[type];
- for (i = 0; i < arr.length; i++) {
- try { arr[i](ev); } catch (e) { printl("[触摸回调错] " + e.message); }
- }
- // 统一回调:(type, event)
- arr = this.listeners.touch;
- for (i = 0; i < arr.length; i++) {
- try { arr[i](type, ev); } catch (e2) { printl("[触摸回调错] " + e2.message); }
- }
- };
- TouchObserver.prototype.start = function () {
- if (this.running) { printl("[触摸] 已在运行"); return; }
- if (!this.device) { printl("[触摸] 无有效设备节点"); return; }
- var target = this;
- target.running = true;
- // AIWROK 正确的线程写法:new thread().runJsCode(fn, "线程名")
- var t = new thread();
- target._thread = t;
- t.runJsCode(function () {
- try {
- var dev = target.device;
- var tmpFile = "/sdcard/aiwrok_touch_events.log";
- target._tmpFile = tmpFile;
- // 先杀掉可能残留的旧 getevent 进程,避免重复输出
- try { agent.shell("su -c 'pkill -9 -f getevent'"); } catch (e) {}
- java.lang.Thread.sleep(200);
- // 清理旧文件
- try { agent.shell("su -c 'rm -f " + tmpFile + "'"); } catch (e) {}
- // 后台运行 getevent,输出重定向到临时文件
- var bgCmd = "su -c 'getevent -lt /dev/input/" + dev + " > " + tmpFile + " 2>&1 &'";
- printl("[触摸] 启动 getevent: " + bgCmd);
- agent.shell(bgCmd);
- // 等一下让进程启动
- java.lang.Thread.sleep(500);
- printl("[触摸] ✓ 启动完成,去屏幕上滑动吧!");
- // 用 RandomAccessFile 自己的 readLine(),自己维护偏移量
- var raf = new java.io.RandomAccessFile(tmpFile, "r");
- var lastPos = 0; // 上次读到的位置
- var gotFirst = false;
- while (target.running) {
- try {
- var curLen = raf.length();
- if (curLen > lastPos) {
- raf.seek(lastPos);
- var line;
- while ((line = raf.readLine()) !== null) {
- if (!gotFirst) {
- gotFirst = true;
- printl("[触摸] ✓✓✓ 收到触摸事件!滑动中...");
- }
- target._parseLine(line);
- lastPos = raf.getFilePointer();
- }
- }
- java.lang.Thread.sleep(30);
- } catch (ie) {
- printl("[触摸] 读异常: " + ie.message);
- break;
- }
- }
- try { raf.close(); } catch (e) {}
- printl("[触摸] 监听线程已退出");
- } catch (e) {
- if (target.running) {
- printl("[触摸] 线程异常: " + e.message);
- }
- }
- }, "触摸监听");
- };
- /** 解析一行 getevent 输出 */
- TouchObserver.prototype._parseLine = function (line) {
- if (!line) return;
- // 雷电格式:
- // [ 1950.000612] EV_ABS ABS_MT_POSITION_X 00000385
- // [ 1950.152524] EV_ABS ABS_MT_TRACKING_ID ffffffff
- // [ 1950.152524] EV_KEY BTN_TOUCH UP
- // [ 1952.376642] EV_ABS ABS_MT_TRACKING_ID 00000096
- // [ 1952.376642] EV_KEY BTN_TOUCH DOWN
- // [ 1952.376642] EV_SYN SYN_REPORT 00000000
- // 直接字符串匹配,绕开 split 的各种坑
- var self = this;
- // ABS_MT_POSITION_X
- var xIdx = line.indexOf("ABS_MT_POSITION_X");
- if (xIdx >= 0) {
- var hex = line.substring(xIdx + "ABS_MT_POSITION_X".length).trim();
- var v = parseInt(hex, 16);
- // 过滤异常值:屏幕分辨率 1080x1920,超过 2000 或负数都是垃圾数据
- if (v >= 0 && v < 5000) self.currentX = v;
- return;
- }
- // ABS_MT_POSITION_Y
- var yIdx = line.indexOf("ABS_MT_POSITION_Y");
- if (yIdx >= 0) {
- var hex2 = line.substring(yIdx + "ABS_MT_POSITION_Y".length).trim();
- var v2 = parseInt(hex2, 16);
- if (v2 >= 0 && v2 < 5000) self.currentY = v2;
- return;
- }
- // ABS_MT_TRACKING_ID
- var tIdx = line.indexOf("ABS_MT_TRACKING_ID");
- if (tIdx >= 0) {
- var hex3 = line.substring(tIdx + "ABS_MT_TRACKING_ID".length).trim();
- var tid = parseInt(hex3, 16);
- if (tid < 0 || hex3.indexOf("ffffffff") >= 0) {
- // 抬起
- if (self.pointerDown) {
- self.pointerDown = false;
- self._downFired = false;
- self._emit("up", {
- x: self.currentX, y: self.currentY,
- pointerId: self.currentPointer,
- timestamp: java.lang.System.currentTimeMillis()
- });
- }
- } else {
- // 按下
- self.currentPointer = tid;
- self.pointerDown = true;
- self._downFired = false;
- }
- return;
- }
- // BTN_TOUCH DOWN
- if (line.indexOf("BTN_TOUCH") >= 0 && line.indexOf("DOWN") >= 0) {
- self.pointerDown = true;
- self._downFired = false;
- return;
- }
- // BTN_TOUCH UP
- if (line.indexOf("BTN_TOUCH") >= 0 && line.indexOf("UP") >= 0) {
- if (self.pointerDown) {
- self.pointerDown = false;
- self._downFired = false;
- self._emit("up", {
- x: self.currentX, y: self.currentY,
- pointerId: self.currentPointer,
- timestamp: java.lang.System.currentTimeMillis()
- });
- }
- return;
- }
- // SYN_REPORT —— 一帧数据结束,触发回调
- if (line.indexOf("SYN_REPORT") >= 0) {
- if (self.pointerDown && self.currentX >= 0 && self.currentY >= 0) {
- if (!self._downFired) {
- self._downFired = true;
- self._emit("down", {
- x: self.currentX, y: self.currentY,
- pointerId: self.currentPointer,
- timestamp: java.lang.System.currentTimeMillis()
- });
- } else {
- self._emit("move", {
- x: self.currentX, y: self.currentY,
- pointerId: self.currentPointer,
- timestamp: java.lang.System.currentTimeMillis()
- });
- }
- }
- return;
- }
- };
- TouchObserver.prototype.stop = function () {
- this.running = false;
- // 用 agent.shell kill 后台 getevent 进程
- try {
- agent.shell("su -c 'pkill -f getevent'");
- } catch (e) {}
- // 清理临时文件
- try {
- if (this._tmpFile) {
- agent.shell("su -c 'rm -f " + this._tmpFile + "'");
- }
- } catch (e) {}
- if (this.process) {
- try { this.process.destroy(); } catch (e) {}
- this.process = null;
- }
- if (this._thread) {
- try { this._thread.stop(); } catch (e) {}
- this._thread = null;
- }
- printl("[触摸] 已停止");
- };
- // ======================== 统一入口 observeTouch ========================
- var _currentObserver = null;
- /**
- * 启动屏幕触摸监听(模拟 Hamibot events.observeTouch)
- * @param {Object} options
- * @param {Function} [options.onTouchDown] 按下回调 function(event){}
- * @param {Function} [options.onTouchMove] 移动回调 function(event){}
- * @param {Function} [options.onTouchUp] 抬起回调 function(event){}
- * @param {Function} [options.onTouch] 统一回调 function(type, event){}
- * @returns {TouchObserver} 可调用 .stop() 停止;无 root 返回 null
- *
- * event 结构: { x, y, pointerId, timestamp }
- * type: "down" | "move" | "up"
- */
- function observeTouch(options) {
- options = options || {};
- if (!isRootAvailable()) {
- printl("✗ observeTouch 需要 root 权限,当前设备无 root");
- printl(" 雷电 / 夜神 / 逍遥 模拟器默认自带 root");
- return null;
- }
- printl("🔍 正在检测触摸设备节点...");
- var device = findTouchEventDevice();
- if (!device) {
- printl("✗ 找不到触摸设备节点");
- return null;
- }
- printl("✓ 触摸设备: /dev/input/" + device);
- var obs = new TouchObserver(device);
- if (typeof options.onTouchDown === "function") obs.onDown(options.onTouchDown);
- if (typeof options.onTouchMove === "function") obs.onMove(options.onTouchMove);
- if (typeof options.onTouchUp === "function") obs.onUp(options.onTouchUp);
- if (typeof options.onTouch === "function") obs.onTouch(options.onTouch);
- obs.start();
- _currentObserver = obs;
- return obs;
- }
- /** 停止全局触摸监听 */
- function stopObserveTouch() {
- if (_currentObserver) {
- _currentObserver.stop();
- _currentObserver = null;
- }
- }
- // ======================== demo ========================
- function demo() {
- printl("╔══════════════════════════════════════════════╗");
- printl("║ AIWROK 屏幕触摸事件监听 - 演示 ║");
- printl("╚══════════════════════════════════════════════╝");
- sleep.millisecond(600);
- // ---- 步骤 1: 检查 root ----
- printl("\n🔐 [1/4] 检查 root 权限...");
- sleep.millisecond(300);
- var hasRoot = isRootAvailable();
- printl(" root 权限: " + (hasRoot ? "✓ 可用" : "✗ 不可用"));
- sleep.millisecond(800);
- if (!hasRoot) {
- printl("\n⚠️ 无 root,演示停止。请先 root 设备后再试。");
- return;
- }
- // ---- 步骤 2: 找设备 ----
- printl("\n🔍 [2/4] 扫描触摸设备节点...");
- sleep.millisecond(300);
- var device = findTouchEventDevice();
- if (device) {
- printl(" ✓ 找到: /dev/input/" + device);
- } else {
- printl(" ✗ 未找到触摸设备");
- return;
- }
- sleep.millisecond(800);
- // ---- 步骤 3: 启动监听 ----
- printl("\n👆 [3/4] 启动触摸监听");
- sleep.millisecond(300);
- printl(" 👉 请在屏幕上滑动/点击,观察日志");
- printl(" 15 秒后自动停止(也可手动按停止按钮)");
- sleep.millisecond(500);
- var lastMoveLog = 0; // 节流 move 日志
- var obs = observeTouch({
- onTouchDown: function (e) {
- printl(" 🔽 DOWN x=" + e.x + " y=" + e.y);
- },
- onTouchMove: function (e) {
- // move 很密集,每 80ms 最多打一条
- var now = java.lang.System.currentTimeMillis();
- if (now - lastMoveLog > 80) {
- lastMoveLog = now;
- printl(" ➡️ MOVE x=" + e.x + " y=" + e.y);
- }
- },
- onTouchUp: function (e) {
- printl(" 🔼 UP x=" + e.x + " y=" + e.y);
- }
- });
- // ---- 步骤 4: 15 秒后自动停 ----
- sleep.millisecond(15000);
- if (obs) obs.stop();
- printl("\n╔══════════════════════════════════════════════╗");
- printl("║ 演示结束! ║");
- printl("║ observeTouch() 可直接集成到你的脚本 ║");
- printl("╚══════════════════════════════════════════════╝");
- }
- demo();
复制代码
| |  | |  |
|
untoAIWROK 日志打印方法完整集合nextnocontent
|