"""手指滑动轨迹录制 → 生成轨迹图片 + JSON数据""" import sys, os, subprocess, re, time, json import cv2, numpy as np DEVICE = sys.argv[1] if len(sys.argv) > 1 else "JRLFJFSCGIGIS4LR" OUT_DIR = r"D:\pycharm\Project\project\tbsg\guiji_new" os.makedirs(OUT_DIR, exist_ok=True) # ── 找触摸设备 ── r = subprocess.run(["adb", "-s", DEVICE, "shell", "getevent", "-pl"], capture_output=True, text=True, timeout=10) touch_dev = None current = None axis_max_x = None axis_max_y = None for line in r.stdout.split('\n'): m = re.search(r'(/dev/input/event\d+)', line) if m: current = m.group(1) if current and 'ABS_MT_POSITION_X' in line and touch_dev is None: touch_dev = current am = re.search(r'max\s+(\d+)', line) if am: axis_max_x = int(am.group(1)) elif current == touch_dev and 'ABS_MT_POSITION_Y' in line and axis_max_y is None: am = re.search(r'max\s+(\d+)', line) if am: axis_max_y = int(am.group(1)) if touch_dev and axis_max_x and axis_max_y: break if not touch_dev: for d in ['/dev/input/event3', '/dev/input/event2', '/dev/input/event1']: r2 = subprocess.run(["adb", "-s", DEVICE, "shell", "getevent", "-pl", d], capture_output=True, text=True, timeout=5) if 'ABS_MT_POSITION' in r2.stdout: touch_dev = d mx = re.search(r'ABS_MT_POSITION_X.*?max\s+(\d+)', r2.stdout, re.S) my = re.search(r'ABS_MT_POSITION_Y.*?max\s+(\d+)', r2.stdout, re.S) axis_max_x = int(mx.group(1)) if mx else None axis_max_y = int(my.group(1)) if my else None break if not touch_dev: touch_dev = "/dev/input/event3" # ── 获取分辨率 ── size_r = subprocess.run(["adb", "-s", DEVICE, "shell", "wm", "size"], capture_output=True, text=True) m = re.search(r'(\d+)x(\d+)', size_r.stdout) W, H = (int(m.group(1)), int(m.group(2))) if m else (1220, 2712) print(f"设备: {DEVICE}") print(f"触摸设备: {touch_dev}") print(f"屏幕: {W}x{H} 原始触摸范围: {axis_max_x or '?'}x{axis_max_y or '?'}") print() print("在手机上滑动手指,手指抬起自动结束...") print() # ── 录制 ── proc = subprocess.Popen( ["adb", "-s", DEVICE, "shell", "getevent", "-lt", touch_dev], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) points = [] lx, ly, ts = None, None, None idle_count = 0 start_ts = None for line in proc.stdout: # 解析时间戳 [ 12345.678901] tm = re.search(r'\[\s*([\d.]+)\]', line) if tm: ts = float(tm.group(1)) if 'ABS_MT_POSITION_X' in line: mm = re.search(r'([0-9a-fA-F]{8})$', line.strip()) if mm: lx = int(mm.group(1), 16) elif 'ABS_MT_POSITION_Y' in line: mm = re.search(r'([0-9a-fA-F]{8})$', line.strip()) if mm: ly = int(mm.group(1), 16) elif 'SYN_REPORT' in line and lx is not None and ly is not None: if start_ts is None: start_ts = ts rel_ts = (ts - start_ts) * 1000 if ts and start_ts else 0 # 相对时间ms raw_x, raw_y = lx, ly x = int(round(raw_x * (W - 1) / axis_max_x)) if axis_max_x else raw_x y = int(round(raw_y * (H - 1) / axis_max_y)) if axis_max_y else raw_y points.append({"x": x, "y": y, "raw_x": raw_x, "raw_y": raw_y, "ts": ts, "rel_ms": round(rel_ts, 2)}) idle_count = 0 if len(points) % 15 == 0: print(f"\r 已录 {len(points)} 点 (x={x}, y={y})", end="", flush=True) elif 'BTN_TOUCH' in line and 'UP' in line: if len(points) > 3: print("\n 检测到手指抬起") break elif 'ABS_MT_TRACKING_ID' in line and 'ffffffff' in line: if len(points) > 3: print("\n 检测到手指抬起") break else: idle_count += 1 if idle_count > 300 and len(points) > 5: print("\n 超时自动结束") break proc.kill() print(f"\n共录制 {len(points)} 点") if len(points) < 3: print("点数太少,请重试(确保触摸了屏幕)") sys.exit(1) xs = [p["x"] for p in points] ys = [p["y"] for p in points] # ── 保存JSON ── ts_str = time.strftime("%Y%m%d_%H%M%S") + f"_{time.time_ns() % 1000000:06d}" json_path = os.path.join(OUT_DIR, f"track_{ts_str}.json") data = { "device": DEVICE, "screen": {"w": W, "h": H}, "touch_axis": {"max_x": axis_max_x, "max_y": axis_max_y}, "start_ts": start_ts, "total_points": len(points), "start": {"x": xs[0], "y": ys[0]}, "end": {"x": xs[-1], "y": ys[-1]}, "dx": xs[-1] - xs[0], "dy": ys[-1] - ys[0], "duration_ms": round(points[-1]["rel_ms"], 2) if points else 0, "points": points } with open(json_path, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False) print(f"数据: {json_path}") # ── 画轨迹: 多种颜色 ── margin_x = 40 margin_y = 300 # 上下大留白, 轨迹居中 min_x, max_x = min(xs), max(xs) min_y, max_y = min(ys), max(ys) width = max_x - min_x + margin_x * 2 height = max_y - min_y + margin_y * 2 width, height = max(width, 200), max(height, 800) canvas = np.ones((height, width, 3), dtype=np.uint8) * 255 total = len(points) # 找折回起点: X开始持续减小 peak_i = 0 for i in range(1, total): if xs[i] >= xs[peak_i]: peak_i = i else: break # 计算右段Y波动阈值 right_ys = ys[:peak_i+1] y_diffs = [abs(right_ys[j] - right_ys[j-1]) for j in range(1, len(right_ys))] avg_y_diff = sum(y_diffs) / len(y_diffs) if y_diffs else 0 for i in range(1, total): p1 = (xs[i-1] - min_x + margin_x, ys[i-1] - min_y + margin_y) p2 = (xs[i] - min_x + margin_x, ys[i] - min_y + margin_y) if i <= peak_i: color = (0, 200, 0) # 绿色=往右 else: color = (0, 0, 200) # 红色=折回 cv2.line(canvas, p1, p2, color, 30) # 起点(绿) 折回点(黄) 终点(红) p0 = (xs[0] - min_x + margin_x, ys[0] - min_y + margin_y) pp = (xs[peak_i] - min_x + margin_x, ys[peak_i] - min_y + margin_y) pe = (xs[-1] - min_x + margin_x, ys[-1] - min_y + margin_y) cv2.circle(canvas, p0, 16, (0, 200, 0), -1) cv2.circle(canvas, pp, 16, (0, 200, 200), -1) cv2.circle(canvas, pe, 16, (0, 0, 200), -1) cv2.putText(canvas, "START", (p0[0]+20, p0[1]+5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,150,0), 3) cv2.putText(canvas, "TURN", (pp[0]+20, pp[1]+5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (200,150,0), 3) cv2.putText(canvas, "END", (pe[0]+20, pe[1]+5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,150), 3) info = f"GREEN=right | RED=return | S({xs[0]},{ys[0]}) E({xs[-1]},{ys[-1]}) | {xs[-1]-xs[0]}px | {data['duration_ms']}ms" cv2.putText(canvas, info, (margin_x, height - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (120,120,120), 1) img_path = os.path.join(OUT_DIR, f"track_{ts_str}.png") cv2.imwrite(img_path, canvas) print(f"图片: {img_path}") print(f"起点({xs[0]},{ys[0]}) -> 终点({xs[-1]},{ys[-1]})") print(f"X: {xs[-1]-xs[0]}px Y: {ys[-1]-ys[0]}px 时长: {data['duration_ms']}ms")