fix(wanglanmei-ref): 双修真输入坐标断层——页面壳状态行改浮层(canvas顶到0,0满幅,旧布局下推29px且裁底致真机底部按钮不可点)+driver加rect坐标映射(zone canvas系→页面CSS系),轨迹双系留痕

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
zizi 2026-06-12 14:25:22 +00:00
parent 43623609bd
commit 572b3721b5
2 changed files with 38 additions and 14 deletions

View File

@ -25,29 +25,35 @@
font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
overflow: hidden;
}
/* 收编修(轮1评估段):状态行改浮层、wrap 零内边距——canvas 必须顶在 (0,0) 满幅 390×844。
旧 flex 列布局把 canvas 下推 ≈29px:e2e 真输入坐标整体偏移,且 844 视口裁掉 canvas 底部 29px
(真机亲玩底部按钮点不到)。状态行 pointer-events:none 防截触摸。 */
#wrap {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
padding: 6px 0;
position: relative;
width: 390px;
margin: 0 auto;
}
#game {
width: 390px;
height: 844px;
background: #f6e7c9;
display: block;
border-radius: 8px;
touch-action: none; /* 触摸全交 JS(pointer 桥接),禁浏览器默认手势 */
}
#status {
position: absolute; /* 浮层叠于 canvas 顶部,不占布局流 */
top: 0;
left: 0;
right: 0;
z-index: 2;
pointer-events: none; /* 绝不截触摸 */
font-size: 12px;
line-height: 1.4;
min-height: 15px;
max-width: 390px;
text-align: center;
word-break: break-all;
opacity: 0.85;
text-shadow: 0 1px 2px rgba(46, 35, 27, 0.8); /* 深底浮字可读性 */
}
</style>
</head>

View File

@ -103,11 +103,27 @@ async function listZones(phaseTag) {
if (phaseTag) evidence.zonesSeenByPhase[phaseTag] = zs.map((z) => z.id);
return zs;
}
/** CDP 真触摸点按(touchStart→touchEnd 成对;轨迹留痕)。 */
/* 坐标映射:geometry() 的 zone 坐标在 canvas 逻辑空间(VIEW),CDP dispatch 用页面 CSS 坐标。
首跑实翻教训:页面壳曾把 canvas 下推 ≈29px,zone 坐标直发全部偏移 → 一律经 rect 映射换算。 */
let MAP = { l: 0, t: 0, sx: 1, sy: 1 };
async function initMapping() {
const m = await cdp.evaluate(`(function(){
var c = document.getElementById('game'); var r = c.getBoundingClientRect();
var dpr = window.devicePixelRatio || 1;
return { l: r.left, t: r.top, w: r.width, h: r.height, vw: c.width / dpr, vh: c.height / dpr };
})()`);
MAP = { l: m.l, t: m.t, sx: m.w / m.vw, sy: m.h / m.vh };
evidence.meta.coordMap = { rect: m, map: MAP };
console.log(' · 坐标映射:', JSON.stringify(evidence.meta.coordMap));
}
const toClient = (x, y) => ({ x: MAP.l + x * MAP.sx, y: MAP.t + y * MAP.sy });
/** CDP 真触摸点按(touchStart→touchEnd 成对;轨迹留痕,zone 系与页面系双记)。 */
async function tapAt(x, y, zoneId) {
await cdp.send('Input.dispatchTouchEvent', { type: 'touchStart', touchPoints: [{ x, y }] });
const c = toClient(x, y);
await cdp.send('Input.dispatchTouchEvent', { type: 'touchStart', touchPoints: [{ x: c.x, y: c.y }] });
await cdp.send('Input.dispatchTouchEvent', { type: 'touchEnd', touchPoints: [] });
trajectory.push({ seq: trajectory.length, wallMs: Date.now(), kind: 'tap', zoneId: zoneId || null, x, y });
trajectory.push({ seq: trajectory.length, wallMs: Date.now(), kind: 'tap', zoneId: zoneId || null, x, y, clientX: c.x, clientY: c.y });
await delay(90); // 让真事件经浏览器→输入桥落地
await stepFrames(3); // 推帧消化(反馈注册/状态机流转)
}
@ -119,16 +135,17 @@ async function tapZone(id) {
await tapAt(z.x, z.y, id);
return true;
}
/** 真触摸拖拽(touchStart→分段 touchMove→touchEnd;价格滑条用)。 */
/** 真触摸拖拽(touchStart→分段 touchMove→touchEnd;价格滑条用;坐标同样经 rect 映射)。 */
async function dragTouch(x0, y0, x1, y1, zoneId, steps = 8) {
await cdp.send('Input.dispatchTouchEvent', { type: 'touchStart', touchPoints: [{ x: x0, y: y0 }] });
const a = toClient(x0, y0), b = toClient(x1, y1);
await cdp.send('Input.dispatchTouchEvent', { type: 'touchStart', touchPoints: [{ x: a.x, y: a.y }] });
for (let i = 1; i <= steps; i++) {
const x = x0 + ((x1 - x0) * i) / steps, y = y0 + ((y1 - y0) * i) / steps;
const x = a.x + ((b.x - a.x) * i) / steps, y = a.y + ((b.y - a.y) * i) / steps;
await cdp.send('Input.dispatchTouchEvent', { type: 'touchMove', touchPoints: [{ x, y }] });
await delay(16);
}
await cdp.send('Input.dispatchTouchEvent', { type: 'touchEnd', touchPoints: [] });
trajectory.push({ seq: trajectory.length, wallMs: Date.now(), kind: 'drag', zoneId: zoneId || null, x: x0, y: y0, x1, y1 });
trajectory.push({ seq: trajectory.length, wallMs: Date.now(), kind: 'drag', zoneId: zoneId || null, x: x0, y: y0, x1, y1, clientX: a.x, clientY: a.y });
await delay(90);
await stepFrames(3);
}
@ -156,6 +173,7 @@ async function shot(name, withHash) {
/* 门 A:boot+probe 链(FORENSICS §4-1/2) */
cdp = await connectRef(URL_EVIDENCE);
try {
await initMapping(); // zone(canvas 逻辑系)→页面 CSS 系映射,一切真输入坐标经此换算
const probe = await F('FZ.probe()');
fs.writeFileSync(path.join(OUT_DIR, 'probe.jsonl'), (probe.jsonl || '') + '\n');
check(probe.verify && probe.verify.ok === true, `probe 链 verify.ok(实际:${JSON.stringify(probe.verify)})`);