From 1e39f5490a85262b9457669844b93ea9eac06b19 Mon Sep 17 00:00:00 2001 From: butubb <1422726308@qq.com> Date: Thu, 20 Aug 2026 13:22:21 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A4=A7=E5=B1=8F=E8=A7=A6=E6=8E=A7?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E2=80=94=E2=80=94=E2=91=A0=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E9=94=99=E4=BD=8D=EF=BC=9Actrl-img=20object-fit:contain=20?= =?UTF-8?q?=E6=97=B6=E5=9B=BE=E7=89=87=E7=BB=98=E5=88=B6=E5=8C=BA=E5=B0=8F?= =?UTF-8?q?=E4=BA=8E=E7=9B=92=E5=AD=90=EF=BC=88=E5=B1=85=E4=B8=AD=E9=BB=91?= =?UTF-8?q?=E8=BE=B9=EF=BC=89=EF=BC=8C=E5=9D=90=E6=A0=87=E6=8D=A2=E7=AE=97?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E6=8C=89=E5=AE=9E=E9=99=85=E7=BB=98=E5=88=B6?= =?UTF-8?q?=E5=8C=BA=E5=9F=9F=EF=BC=8C=E9=BB=91=E8=BE=B9=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E5=BF=BD=E7=95=A5=EF=BC=9B=E2=91=A1=E6=BB=91=E5=8A=A8=E5=8D=A1?= =?UTF-8?q?=E9=A1=BF=EF=BC=9Atap/swipe/key/text=20=E6=AF=8F=E6=AC=A1=20u2.?= =?UTF-8?q?connect=20=E9=87=8D=E5=BB=BA=E8=BF=9E=E6=8E=A5=EF=BC=881-3s=20?= =?UTF-8?q?=E6=8F=A1=E6=89=8B=EF=BC=89=EF=BC=8C=E5=8A=A0=2060s=20=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E7=BC=93=E5=AD=98=EF=BC=8C=E5=A4=B1=E8=B4=A5=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=B8=85=E7=BC=93=E5=AD=98=E9=87=8D=E5=BB=BA=EF=BC=88?= =?UTF-8?q?=E5=AE=9E=E6=B5=8B=E7=82=B9=E5=87=BB=202.97s=E2=86=921.13s?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/admin/wall.html | 14 ++++++---- web/monitor.py | 59 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/templates/admin/wall.html b/templates/admin/wall.html index 34ec3b7..e057783 100644 --- a/templates/admin/wall.html +++ b/templates/admin/wall.html @@ -391,14 +391,18 @@ function updateCtrlHead(){ document.getElementById('ctrl-sub').textContent=_ctrlSerial+(d.present?'':'(离线)'); } // 坐标映射:显示尺寸 -> 设备原生分辨率 +// 图片 object-fit:contain 时实际绘制区域小于盒子(居中留黑边), +// 必须按绘制区域换算,否则黑边/偏移导致点击错位 function ctrlCoords(ev){ const img=document.getElementById('ctrl-img'); - if(!img.naturalWidth)return[null,null]; + if(!img.naturalWidth||!img.naturalHeight)return[null,null]; const r=img.getBoundingClientRect(); - return[ - Math.round((ev.clientX-r.left)/r.width*img.naturalWidth), - Math.round((ev.clientY-r.top)/r.height*img.naturalHeight), - ]; + const scale=Math.min(r.width/img.naturalWidth,r.height/img.naturalHeight); + const drawW=img.naturalWidth*scale, drawH=img.naturalHeight*scale; + const ox=(r.width-drawW)/2, oy=(r.height-drawH)/2; // contain 偏移 + const px=ev.clientX-r.left, py=ev.clientY-r.top; + if(pxox+drawW||pyoy+drawH)return[null,null]; // 黑边点击忽略 + return[Math.round((px-ox)/scale),Math.round((py-oy)/scale)]; } function ctrlTap(x,y){ if(x==null||!x)return; diff --git a/web/monitor.py b/web/monitor.py index 653ec78..52f33c8 100644 --- a/web/monitor.py +++ b/web/monitor.py @@ -416,10 +416,34 @@ def api_screen_stream(): mimetype="multipart/x-mixed-replace; boundary=frame") +_screen_u2_cache = {} # serial -> (ts, device):大屏高频触控复用连接(60s TTL) + + def _screen_get_device(serial): - """远程看屏用的 u2 连接(连接失败抛异常由调用方转 503)。""" + """远程看屏用的 u2 连接(60s 缓存复用,避免每次 tap/swipe 都重建连接)。 + + 大屏高频操作(点击/滑动/按键)每次 u2.connect 有 1-3s 握手开销(atx-agent + 探测),体验卡顿。缓存 60s 内复用;连接失败(设备离线/重启)时清缓存重建, + 由调用方把异常转 503。 + """ + import time import uiautomator2 as u2 - return u2.connect(serial) + now = time.time() + cached = _screen_u2_cache.get(serial) + if cached and now - cached[0] < 60: + return cached[1] + d = u2.connect(serial) + _screen_u2_cache[serial] = (now, d) + if len(_screen_u2_cache) > 30: # 惰性清理过期项 + for k in list(_screen_u2_cache): + if now - _screen_u2_cache[k][0] >= 60: + del _screen_u2_cache[k] + return d + + +def _screen_invalidate(serial): + """u2 调用失败时清掉缓存(设备离线/atx-agent 重启),下次请求重新连接。""" + _screen_u2_cache.pop(serial, None) @bp.route("/api/screen/thumb") @perm_required(PERM_DEVICES) @@ -464,6 +488,7 @@ def api_screen_tap(): _screen_get_device(serial).click(int(x), int(y)) return jsonify({"ok": True}) except Exception as e: + _screen_invalidate(serial) return jsonify({"ok": False, "error": f"点击失败: {e}"}), 503 @bp.route("/api/screen/swipe", methods=["POST"]) @@ -480,6 +505,7 @@ def api_screen_swipe(): duration=float(data.get("duration", 0.2))) return jsonify({"ok": True}) except Exception as e: + _screen_invalidate(serial) return jsonify({"ok": False, "error": f"滑动失败: {e}"}), 503 @@ -498,6 +524,7 @@ def api_screen_key(): _screen_get_device(serial).press(key) return jsonify({"ok": True}) except Exception as e: + _screen_invalidate(serial) return jsonify({"ok": False, "error": f"按键失败: {e}"}), 503 @bp.route("/api/screen/text", methods=["POST"]) @@ -528,8 +555,32 @@ def _current_focus_pkg(serial): except Exception: return "" +_screen_u2_cache = {} # serial -> (ts, device):大屏高频触控复用连接(60s TTL) + + def _screen_get_device(serial): - """远程看屏用的 u2 连接(连接失败抛异常由调用方转 503)。""" + """远程看屏用的 u2 连接(60s 缓存复用,避免每次 tap/swipe 都重建连接)。 + + 大屏高频操作(点击/滑动/按键)每次 u2.connect 有 1-3s 握手开销(atx-agent + 探测),体验卡顿。缓存 60s 内复用;连接失败(设备离线/重启)时清缓存重建, + 由调用方把异常转 503。 + """ + import time import uiautomator2 as u2 - return u2.connect(serial) + now = time.time() + cached = _screen_u2_cache.get(serial) + if cached and now - cached[0] < 60: + return cached[1] + d = u2.connect(serial) + _screen_u2_cache[serial] = (now, d) + if len(_screen_u2_cache) > 30: # 惰性清理过期项 + for k in list(_screen_u2_cache): + if now - _screen_u2_cache[k][0] >= 60: + del _screen_u2_cache[k] + return d + + +def _screen_invalidate(serial): + """u2 调用失败时清掉缓存(设备离线/atx-agent 重启),下次请求重新连接。""" + _screen_u2_cache.pop(serial, None)