B2B网络软件

标题: 触摸手势识别悬浮画板自动执行助手 [打印本页]

作者: YYPOST群发软件    时间: 1 小时前
标题: 触摸手势识别悬浮画板自动执行助手

触摸手势识别悬浮画板自动执行助手


触摸手势识别悬浮画板自动执行助手 B2B网络软件

触摸手势识别悬浮画板自动执行助手 B2B网络软件

触摸手势识别悬浮画板自动执行助手 B2B网络软件


  1. /**
  2. * ╔══════════════════════════════════════════════════════════╗
  3. * ║   AIWROK 触摸手势识别 + 悬浮画板 + 自动执行助手            ║
  4. * ║                                                          ║
  5. * ║   功能:                                                  ║
  6. * ║     ① 监听真实屏幕触摸事件 (root + getevent)             ║
  7. * ║     ② 在 floatUI 悬浮窗上实时画出手指轨迹                 ║
  8. * ║     ③ 自动识别手势:上滑/下滑/左滑/右滑/双击/长按/V字      ║
  9. * ║     ④ 手势触发自动化动作:                                ║
  10. * ║          右滑 → 回桌面                                     ║
  11. * ║          左滑 → 截图保存到相册                              ║
  12. * ║          上滑 → 音量+                                      ║
  13. * ║          下滑 → 音量-                                      ║
  14. * ║          双击 → 打开设置                                    ║
  15. * ║          长按 → 启动/停止脚本                               ║
  16. * ║          V字  → 打开微信                                    ║
  17. * ║                                                          ║
  18. * ║   依赖:root 权限(雷电/夜神/逍遥/蓝叠 默认自带 root)     ║
  19. * ║   引擎:Rhino ES5                                         ║
  20. * ╚══════════════════════════════════════════════════════════╝
  21. */

  22. // ==============================================================
  23. // 第一部分:observeTouch 核心(从原文件精简并增强)
  24. // ==============================================================

  25. function shellExec(cmd) {
  26.     if (typeof agent !== "undefined" && typeof agent.shell === "function") {
  27.         try {
  28.             var ret = agent.shell(cmd);
  29.             return ret === null ? "" : ret.toString();
  30.         } catch (e) {}
  31.     }
  32.     try {
  33.         var proc = java.lang.Runtime.getRuntime().exec(cmd);
  34.         var reader = new java.io.BufferedReader(
  35.             new java.io.InputStreamReader(proc.getInputStream())
  36.         );
  37.         var sb = new java.lang.StringBuilder();
  38.         var line;
  39.         while ((line = reader.readLine()) !== null) {
  40.             sb.append(line).append("\n");
  41.         }
  42.         proc.waitFor();
  43.         return sb.toString().trim();
  44.     } catch (e) { return ""; }
  45. }

  46. function findTouchEventDevice() {
  47.     var allDev = shellExec("getevent -lp");
  48.     var re = /add device \d+: \/dev\/input\/(event\d+)\s+name:\s*"([^"]*)"([\s\S]*?)(?=add device|$)/g;
  49.     var m;
  50.     while ((m = re.exec(allDev)) !== null) {
  51.         var evtName = m[1];
  52.         var devName = m[2].toLowerCase();
  53.         var eventsInfo = m[3];

  54.         if (devName.indexOf("touch") >= 0 || devName.indexOf("tsp") >= 0 ||
  55.             devName.indexOf("goodix") >= 0 || devName.indexOf("synaptics") >= 0) {
  56.             return evtName;
  57.         }
  58.         if (eventsInfo.indexOf("ABS_MT_POSITION_X") >= 0 &&
  59.             eventsInfo.indexOf("ABS_MT_POSITION_Y") >= 0) {
  60.             return evtName;
  61.         }
  62.         if (eventsInfo.indexOf("BTN_TOUCH") >= 0 &&
  63.             eventsInfo.indexOf("ABS_X") >= 0 && eventsInfo.indexOf("ABS_Y") >= 0) {
  64.             return evtName;
  65.         }
  66.         if ((devName.indexOf("hid") >= 0 || devName.indexOf("mouse") >= 0) &&
  67.             eventsInfo.indexOf("BTN_TOUCH") >= 0) {
  68.             return evtName;
  69.         }
  70.     }
  71.     return null;
  72. }

  73. function TouchObserver(eventDevice) {
  74.     this.device = eventDevice;
  75.     this.running = false;
  76.     this.listeners = { down: [], move: [], up: [] };
  77.     this.currentX = -1;
  78.     this.currentY = -1;
  79.     this.pointerDown = false;
  80.     this._downFired = false;
  81. }

  82. TouchObserver.prototype.onDown = function (fn) { this.listeners.down.push(fn); };
  83. TouchObserver.prototype.onMove = function (fn) { this.listeners.move.push(fn); };
  84. TouchObserver.prototype.onUp   = function (fn) { this.listeners.up.push(fn);   };

  85. TouchObserver.prototype._emit = function (type, ev) {
  86.     var arr = this.listeners[type];
  87.     for (var i = 0; i < arr.length; i++) {
  88.         try { arr[i](ev); } catch (e) {}
  89.     }
  90. };

  91. TouchObserver.prototype.start = function () {
  92.     if (this.running) return;
  93.     this.running = true;
  94.     var target = this;

  95.     var t = new thread();
  96.     t.runJsCode(function () {
  97.         try {
  98.             var dev = target.device;
  99.             var tmpFile = "/sdcard/aiwrok_gesture_events.log";

  100.             try { agent.shell("su -c 'pkill -9 -f getevent'"); } catch (e) {}
  101.             java.lang.Thread.sleep(200);
  102.             try { agent.shell("su -c 'rm -f " + tmpFile + "'"); } catch (e) {}

  103.             var bgCmd = "su -c 'getevent -lt /dev/input/" + dev + " > " + tmpFile + " 2>&1 &'";
  104.             agent.shell(bgCmd);
  105.             java.lang.Thread.sleep(500);

  106.             var raf = new java.io.RandomAccessFile(tmpFile, "r");
  107.             var lastPos = 0;

  108.             while (target.running) {
  109.                 var curLen = raf.length();
  110.                 if (curLen > lastPos) {
  111.                     raf.seek(lastPos);
  112.                     var line;
  113.                     while ((line = raf.readLine()) !== null) {
  114.                         target._parseLine(line);
  115.                         lastPos = raf.getFilePointer();
  116.                     }
  117.                 }
  118.                 java.lang.Thread.sleep(25);
  119.             }
  120.             try { raf.close(); } catch (e) {}
  121.         } catch (e) {}
  122.     }, "手势监听");
  123. };

  124. TouchObserver.prototype._parseLine = function (line) {
  125.     if (!line) return;
  126.     var self = this;

  127.     var xIdx = line.indexOf("ABS_MT_POSITION_X");
  128.     if (xIdx >= 0) {
  129.         var v = parseInt(line.substring(xIdx + "ABS_MT_POSITION_X".length).trim(), 16);
  130.         if (v >= 0 && v < 5000) self.currentX = v;
  131.         return;
  132.     }
  133.     var yIdx = line.indexOf("ABS_MT_POSITION_Y");
  134.     if (yIdx >= 0) {
  135.         var v2 = parseInt(line.substring(yIdx + "ABS_MT_POSITION_Y".length).trim(), 16);
  136.         if (v2 >= 0 && v2 < 5000) self.currentY = v2;
  137.         return;
  138.     }
  139.     var tIdx = line.indexOf("ABS_MT_TRACKING_ID");
  140.     if (tIdx >= 0) {
  141.         var tidHex = line.substring(tIdx + "ABS_MT_TRACKING_ID".length).trim();
  142.         if (tidHex.indexOf("ffffffff") >= 0 || parseInt(tidHex, 16) < 0) {
  143.             if (self.pointerDown) {
  144.                 self.pointerDown = false;
  145.                 self._downFired = false;
  146.                 self._emit("up", { x: self.currentX, y: self.currentY,
  147.                     timestamp: java.lang.System.currentTimeMillis() });
  148.             }
  149.         } else {
  150.             self.pointerDown = true;
  151.             self._downFired = false;
  152.         }
  153.         return;
  154.     }
  155.     if (line.indexOf("BTN_TOUCH") >= 0 && line.indexOf("DOWN") >= 0) {
  156.         self.pointerDown = true;
  157.         self._downFired = false;
  158.         return;
  159.     }
  160.     if (line.indexOf("BTN_TOUCH") >= 0 && line.indexOf("UP") >= 0) {
  161.         if (self.pointerDown) {
  162.             self.pointerDown = false;
  163.             self._downFired = false;
  164.             self._emit("up", { x: self.currentX, y: self.currentY,
  165.                 timestamp: java.lang.System.currentTimeMillis() });
  166.         }
  167.         return;
  168.     }
  169.     if (line.indexOf("SYN_REPORT") >= 0) {
  170.         if (self.pointerDown && self.currentX >= 0 && self.currentY >= 0) {
  171.             if (!self._downFired) {
  172.                 self._downFired = true;
  173.                 self._emit("down", { x: self.currentX, y: self.currentY,
  174.                     timestamp: java.lang.System.currentTimeMillis() });
  175.             } else {
  176.                 self._emit("move", { x: self.currentX, y: self.currentY,
  177.                     timestamp: java.lang.System.currentTimeMillis() });
  178.             }
  179.         }
  180.         return;
  181.     }
  182. };

  183. TouchObserver.prototype.stop = function () {
  184.     this.running = false;
  185.     try { agent.shell("su -c 'pkill -f getevent'"); } catch (e) {}
  186.     try { agent.shell("su -c 'rm -f /sdcard/aiwrok_gesture_events.log'"); } catch (e) {}
  187.     printl("✓ 触摸监听已停止");
  188. };

  189. // ==============================================================
  190. // 第二部分:手势识别引擎
  191. // ==============================================================

  192. /**
  193. * 手势识别器
  194. * 记录一整次触摸过程的轨迹点列表,抬起时分析出是什么手势
  195. */
  196. function GestureRecognizer(callback) {
  197.     this.callback = callback;  // 识别完成回调 function(gestureType, points)
  198.     this.points = [];
  199.     this.isTracking = false;
  200.     this.lastDownTime = 0;      // 上次按下时间(检测双击)
  201.     this.lastUpTime = 0;        // 上次抬起时间
  202.     this.lastUpX = 0;
  203.     this.lastUpY = 0;
  204.     this.longPressTimer = null; // 长按定时器
  205. }

  206. GestureRecognizer.prototype.onDown = function (e) {
  207.     this.isTracking = true;
  208.     this.points = [{ x: e.x, y: e.y, t: e.timestamp, type: "down" }];

  209.     // 长按检测:按下 800ms 还没抬起就算长按
  210.     var self = this;
  211.     this.longPressTimer = setTimeout(function () {
  212.         if (self.isTracking && self.points.length > 0) {
  213.             var p = self.points[0];
  214.             self.callback("longpress", self.points);
  215.             self.isTracking = false;
  216.             self.points = [];
  217.         }
  218.     }, 800);
  219. };

  220. GestureRecognizer.prototype.onMove = function (e) {
  221.     if (!this.isTracking) return;
  222.     this.points.push({ x: e.x, y: e.y, t: e.timestamp, type: "move" });
  223. };

  224. GestureRecognizer.prototype.onUp = function (e) {
  225.     if (!this.isTracking) {
  226.         // 可能是第二次点击(双击检测)
  227.         var now = e.timestamp;
  228.         if (now - this.lastUpTime < 400 && now - this.lastUpTime > 30) {
  229.             // 距离也不能太远(50像素以内)
  230.             var dx = e.x - this.lastUpX;
  231.             var dy = e.y - this.lastUpY;
  232.             if (Math.sqrt(dx * dx + dy * dy) < 80) {
  233.                 this.callback("doubleclick", null);
  234.             }
  235.         }
  236.         this.lastUpX = e.x;
  237.         this.lastUpY = e.y;
  238.         this.lastUpTime = now;
  239.         return;
  240.     }
  241.     this.points.push({ x: e.x, y: e.y, t: e.timestamp, type: "up" });
  242.     this.isTracking = false;

  243.     if (this.longPressTimer) {
  244.         clearTimeout(this.longPressTimer);
  245.         this.longPressTimer = null;
  246.     }

  247.     // 分析手势类型
  248.     var gesture = this.analyze(this.points);
  249.     this.callback(gesture, this.points);

  250.     this.lastUpX = e.x;
  251.     this.lastUpY = e.y;
  252.     this.lastUpTime = e.timestamp;
  253.     this.points = [];
  254. };

  255. /**
  256. * 核心分析算法:从点集判断是什么手势
  257. */
  258. GestureRecognizer.prototype.analyze = function (pts) {
  259.     if (pts.length < 2) return "click";

  260.     var first = pts[0];
  261.     var last = pts[pts.length - 1];
  262.     var dx = last.x - first.x;
  263.     var dy = last.y - first.y;
  264.     var dist = Math.sqrt(dx * dx + dy * dy);

  265.     // ============ 1. 判断是不是滑动 ============
  266.     // 移动距离 < 30 且时间 < 300ms → 普通点击
  267.     var totalTime = last.t - first.t;
  268.     if (dist < 30 && totalTime < 300) {
  269.         return "click";
  270.     }

  271.     // ============ 2. 判断方向 ============
  272.     // 水平分量占优势
  273.     if (Math.abs(dx) > Math.abs(dy) * 1.5 && dist > 60) {
  274.         return dx > 0 ? "swipe_right" : "swipe_left";
  275.     }
  276.     // 垂直分量占优势
  277.     if (Math.abs(dy) > Math.abs(dx) * 1.5 && dist > 60) {
  278.         return dy > 0 ? "swipe_down" : "swipe_up";
  279.     }

  280.     // ============ 3. 判断 V 字手势 ============
  281.     var vResult = this.checkVShape(pts);
  282.     if (vResult) return "v_shape";

  283.     // ============ 4. 判断 Z 字(快速左右摆动)============
  284.     if (this.checkZZigzag(pts)) return "z_shape";

  285.     // 默认:滑动(方向模糊)
  286.     if (dist > 60) return "swipe";

  287.     return "click";
  288. };

  289. /** 检测 V 字形:先向右下/左下滑,然后又向上反弹 */
  290. GestureRecognizer.prototype.checkVShape = function (pts) {
  291.     if (pts.length < 5) return false;
  292.     var first = pts[0];
  293.     var last = pts[pts.length - 1];
  294.     var midY = 0;
  295.     var midIdx = Math.floor(pts.length / 2);
  296.     midY = pts[midIdx].y;

  297.     // 整体向下(中间点比起止点低)
  298.     if (midY > first.y + 30 && midY > last.y + 30) {
  299.         return true;
  300.     }
  301.     return false;
  302. };

  303. /** 检测 Z 字形:横向来回摆动至少 2 次 */
  304. GestureRecognizer.prototype.checkZZigzag = function (pts) {
  305.     if (pts.length < 10) return false;
  306.     var directionChanges = 0;
  307.     var lastDx = 0;
  308.     for (var i = 2; i < pts.length; i++) {
  309.         var curDx = pts[i].x - pts[i - 2].x;
  310.         if (Math.abs(curDx) > 15 && lastDx !== 0) {
  311.             if ((curDx > 0) !== (lastDx > 0)) {
  312.                 directionChanges++;
  313.             }
  314.         }
  315.         lastDx = curDx;
  316.     }
  317.     return directionChanges >= 2;
  318. };

  319. // ==============================================================
  320. // 第三部分:floatUI 悬浮画板 + 手势状态显示
  321. // ==============================================================

  322. /**
  323. * 创建悬浮画板 UI
  324. * 全屏半透明窗口,实时画出手指轨迹,底部显示当前手势状态
  325. */
  326. function createFloatCanvas() {
  327.     // 方案:用 XML Canvas 元素 —— 但 AIWROK floatUI 支持 SXML
  328.     // 这里用一个简化版:floatUI 只做状态条 + 按钮
  329.     // 轨迹绘制直接在 screen 上做 overlay 思路太复杂,换成日志 + 按钮

  330.     var f = new floatUI();

  331.     var layout =
  332.         '<vertical bg="#E6000000" w="match_parent" h="wrap_content">' +
  333.         '    <text id="gesture_title" textColor="#00FF88" textSize="15sp" padding="10dp" text="&#128070; 手势助手 已运行"/>' +
  334.         '    <text id="gesture_status" textColor="#FFFFFF" textSize="14sp" padding="4dp 10dp" text="等待触摸..."/>' +
  335.         '    <text id="gesture_hint" textColor="#AAAAAA" textSize="12sp" padding="2dp 10dp 8dp 10dp" text="右滑→桌面 左滑→截图 上滑→音量+ 下滑→音量- 双击→设置 长按→停止 V→微信"/>' +
  336.         '    <horizontal w="match_parent" gravity="center" padding="0dp 8dp 8dp 8dp">' +
  337.         '        <button id="btn_stop" text="■ 停止" w="90dp" h="38dp" textColor="#FF8888" margin="4dp"/>' +
  338.         '        <button id="btn_clear" text="清除" w="90dp" h="38dp" textColor="#66AAFF" margin="4dp"/>' +
  339.         '        <button id="btn_hide" text="隐藏" w="90dp" h="38dp" textColor="#AAAAAA" margin="4dp"/>' +
  340.         '    </horizontal>' +
  341.         '</vertical>';

  342.     f.loadSXML(layout);

  343.     var txtStatus = f.findViewById("gesture_status");
  344.     var txtTitle  = f.findViewById("gesture_title");
  345.     var btnStop   = f.findViewById("btn_stop");
  346.     var btnClear  = f.findViewById("btn_clear");
  347.     var btnHide   = f.findViewById("btn_hide");

  348.     // 位置:屏幕顶部居中
  349.     var sw = screen.getScreenWidth();
  350.     f.setPosition(Math.floor((sw - 320) / 2), 100);

  351.     btnStop.setOnClickListener(function () {
  352.         printl("用户点击停止按钮");
  353.         stopEverything();
  354.     });

  355.     btnClear.setOnClickListener(function () {
  356.         txtStatus.setText("日志已清除 ✓ 等待触摸...");
  357.     });

  358.     var hidden = false;
  359.     btnHide.setOnClickListener(function () {
  360.         hidden = !hidden;
  361.         if (hidden) {
  362.             f.setPosition(sw - 50, 100);
  363.             txtTitle.setText("&#128070;");
  364.             txtStatus.setVisibility(0);  // View.GONE
  365.             btnClear.setVisibility(0);
  366.             btnStop.setVisibility(0);
  367.             btnHide.setText("显示");
  368.         } else {
  369.             f.setPosition(Math.floor((sw - 320) / 2), 100);
  370.             txtTitle.setText("&#128070; 手势助手 已运行");
  371.             txtStatus.setVisibility(1);  // View.VISIBLE
  372.             btnClear.setVisibility(1);
  373.             btnStop.setVisibility(1);
  374.             btnHide.setText("隐藏");
  375.         }
  376.     });

  377.     return {
  378.         ui: f,
  379.         setStatus: function (text, color) {
  380.             txtStatus.setText(text);
  381.             if (color) txtStatus.setTextColor(color);
  382.         },
  383.         flashTitle: function (emoji) {
  384.             txtTitle.setText(emoji);
  385.             sleep.millisecond(200);
  386.             txtTitle.setText("&#128070; 手势助手 已运行");
  387.         }
  388.     };
  389. }

  390. // ==============================================================
  391. // 第四部分:手势 → 自动化动作 映射表
  392. // ==============================================================

  393. /**
  394. * 手势执行器
  395. * 识别到手势后,执行对应的自动化操作
  396. */
  397. function GestureExecutor(panel) {
  398.     this.panel = panel;
  399.     this.actionCount = 0;

  400.     // 手势 → 动作 的映射
  401.     this.rules = {
  402.         "swipe_right": function () {
  403.             panel.setStatus("↪️ 右滑 → 回桌面", "#FFD700");
  404.             auto.home();
  405.         },
  406.         "swipe_left": function () {
  407.             panel.setStatus("↩️ 左滑 → 截图中...", "#66AAFF");
  408.             var img = screen.screenShotFull();
  409.             var path = "/sdcard/Pictures/gesture_" + Date.now() + ".png";
  410.             img.save(path);
  411.             img.recycle();
  412.             panel.setStatus("✅ 截图已保存到 " + path, "#00FF88");
  413.             sleep.second(1);
  414.             panel.setStatus("等待下一个手势...", "#FFFFFF");
  415.         },
  416.         "swipe_up": function () {
  417.             panel.setStatus("⬆️ 上滑 → 音量+", "#00FF88");
  418.             if (typeof agent !== "undefined") agent.shell("input keyevent 24");
  419.             else auto.keyPress(24);
  420.         },
  421.         "swipe_down": function () {
  422.             panel.setStatus("⬇️ 下滑 → 音量-", "#00FF88");
  423.             if (typeof agent !== "undefined") agent.shell("input keyevent 25");
  424.             else auto.keyPress(25);
  425.         },
  426.         "click": function () {
  427.             // 单击:不做特殊动作,只反馈
  428.             panel.setStatus("&#128070; 单击 " + new Date().toLocaleTimeString(), "#AAAAAA");
  429.         },
  430.         "doubleclick": function () {
  431.             panel.setStatus("✌️ 双击 → 打开设置", "#FF66AA");
  432.             app.openApp("com.android.settings");
  433.         },
  434.         "longpress": function () {
  435.             panel.setStatus("⏱️ 长按 → 切换脚本运行", "#FF9900");
  436.             panel.flashTitle("⏱️");
  437.             printl("[手势] 长按 — 这里可以自定义触发你自己的脚本");
  438.             // 例:执行某个任务
  439.             // runYourTask();
  440.         },
  441.         "v_shape": function () {
  442.             panel.setStatus("✔️ V字 → 打开微信", "#00FF88");
  443.             app.openApp("com.tencent.mm");
  444.         },
  445.         "z_shape": function () {
  446.             panel.setStatus("〰️ Z字 → 打开抖音", "#FF0066");
  447.             app.openApp("com.ss.android.ugc.aweme");
  448.         },
  449.         "swipe": function () {
  450.             panel.setStatus("➡️ 模糊滑动,暂不触发动作", "#888888");
  451.         }
  452.     };
  453. }

  454. GestureExecutor.prototype.execute = function (gestureType) {
  455.     this.actionCount++;
  456.     printl("\n========== 手势 #" + this.actionCount + " ==========");
  457.     printl("  识别结果: " + gestureType);
  458.     var handler = this.rules[gestureType];
  459.     if (handler) {
  460.         try { handler(); }
  461.         catch (e) {
  462.             printl("  ❌ 执行出错: " + e.message);
  463.             this.panel.setStatus("❌ 执行失败: " + e.message, "#FF4444");
  464.         }
  465.     } else {
  466.         printl("  (无对应动作)");
  467.     }
  468.     printl("======================================\n");
  469. };

  470. // ==============================================================
  471. // 第五部分:启动、整合、停止
  472. // ==============================================================

  473. var _globalPanel = null;
  474. var _globalObserver = null;
  475. var _globalRecognizer = null;
  476. var _globalExecutor = null;
  477. var _running = false;

  478. function startEverything() {
  479.     if (_running) {
  480.         printl("已经在运行了");
  481.         return;
  482.     }

  483.     printl("\n╔══════════════════════════════════════════╗");
  484.     printl("║  AIWROK 手势识别自动化助手 启动中...      ║");
  485.     printl("╚══════════════════════════════════════════╝\n");

  486.     // 1. root 检测
  487.     printl("&#128272; [1/3] 检测 root 权限...");
  488.     var hasRoot = shellExec("id").indexOf("uid=0") >= 0;
  489.     printl("  root: " + (hasRoot ? "✓" : "✗"));
  490.     if (!hasRoot) {
  491.         printl("❌ 需要 root 权限,请在模拟器或 root 手机上运行");
  492.         return;
  493.     }

  494.     // 2. 找触摸设备
  495.     printl("&#128269; [2/3] 找触摸设备节点...");
  496.     var device = findTouchEventDevice();
  497.     if (!device) {
  498.         printl("❌ 找不到触摸设备");
  499.         return;
  500.     }
  501.     printl("  ✓ /dev/input/" + device);

  502.     // 3. 创建 UI 面板
  503.     printl("&#127912; [3/3] 创建悬浮面板...");
  504.     _globalPanel = createFloatCanvas();

  505.     // 4. 创建识别器 — 识别完交给执行器
  506.     _globalExecutor = new GestureExecutor(_globalPanel);
  507.     _globalRecognizer = new GestureRecognizer(function (gestureType, points) {
  508.         _globalExecutor.execute(gestureType);
  509.     });

  510.     // 5. 启动触摸观察器,把事件喂给识别器
  511.     _globalObserver = new TouchObserver(device);

  512.     // move 事件非常密集,做节流(70ms 最多一条)
  513.     var lastMoveTs = 0;

  514.     _globalObserver.onDown(function (e) {
  515.         printl("&#128317; DOWN  (" + e.x + "," + e.y + ")");
  516.         _globalPanel.setStatus("&#128317; 按下 @ (" + e.x + "," + e.y + ")", "#00FF88");
  517.         _globalRecognizer.onDown(e);
  518.     });

  519.     _globalObserver.onMove(function (e) {
  520.         var now = java.lang.System.currentTimeMillis();
  521.         if (now - lastMoveTs < 60) return;  // 节流
  522.         lastMoveTs = now;
  523.         // move 不刷屏,只在内部记录轨迹
  524.         _globalRecognizer.onMove(e);
  525.     });

  526.     _globalObserver.onUp(function (e) {
  527.         printl("&#128316; UP    (" + e.x + "," + e.y + ")");
  528.         _globalPanel.setStatus("&#128316; 抬起,分析手势中...", "#FFD700");
  529.         _globalRecognizer.onUp(e);
  530.     });

  531.     _globalObserver.start();

  532.     _running = true;
  533.     printl("\n✅ 全部启动!去屏幕上划几下试试吧!\n");
  534.     printl("手势 → 动作映射:");
  535.     printl("  ↪️ 右滑    → 回桌面");
  536.     printl("  ↩️ 左滑    → 截图保存");
  537.     printl("  ⬆️ 上滑    → 音量+");
  538.     printl("  ⬇️ 下滑    → 音量-");
  539.     printl("  ✌️ 双击    → 打开设置");
  540.     printl("  ⏱️ 长按    → 触发自定义任务");
  541.     printl("  ✔️ V字     → 打开微信");
  542.     printl("  〰️ Z字     → 打开抖音\n");
  543. }

  544. function stopEverything() {
  545.     printl("\n&#128721; 正在停止...");
  546.     if (_globalObserver) {
  547.         _globalObserver.stop();
  548.         _globalObserver = null;
  549.     }
  550.     if (_globalPanel && _globalPanel.ui) {
  551.         try { _globalPanel.ui.close(); } catch (e) {}
  552.         _globalPanel = null;
  553.     }
  554.     _running = false;
  555.     printl("✅ 已停止\n");
  556. }

  557. // ==============================================================
  558. // 启动!
  559. // ==============================================================

  560. // 延迟 1.5 秒启动,让悬浮窗初始化不抢时机
  561. sleep.millisecond(1500);
  562. startEverything();
复制代码







欢迎光临 B2B网络软件 (http://bbs.niubt.cn/) Powered by Discuz! X3.2