fix: 用 Pointer Events 替代 touch+mouse 事件,修复移动端双触发导致按钮卡死
- pointerdown/pointerup/pointerleave/pointercancel 统一处理所有输入 - 移除分离的 touchstart/touchend/mousedown/mouseup 事件绑定 - WS 断连时清理 pendingStart 状态,防止按钮永久卡死 - 添加 contextmenu 阻止长按弹出菜单
This commit is contained in:
50
web/app.ts
50
web/app.ts
@@ -133,6 +133,12 @@ function connectWS(): void {
|
||||
state.ws = null;
|
||||
micBtn.disabled = true;
|
||||
if (state.recording) stopRecording();
|
||||
// Clean up pending async start on disconnect
|
||||
if (state.pendingStart) {
|
||||
state.pendingStart = false;
|
||||
state.startCancelled = true;
|
||||
micBtn.classList.remove("recording");
|
||||
}
|
||||
setStatus("disconnected", "已断开");
|
||||
scheduleReconnect();
|
||||
};
|
||||
@@ -357,40 +363,24 @@ function escapeHtml(s: string): string {
|
||||
}
|
||||
// ── Event bindings ──
|
||||
function bindMicButton(): void {
|
||||
// Touch events (mobile primary)
|
||||
micBtn.addEventListener(
|
||||
"touchstart",
|
||||
(e: TouchEvent) => {
|
||||
e.preventDefault();
|
||||
startRecording();
|
||||
},
|
||||
{ passive: false },
|
||||
);
|
||||
micBtn.addEventListener(
|
||||
"touchend",
|
||||
(e: TouchEvent) => {
|
||||
e.preventDefault();
|
||||
stopRecording();
|
||||
},
|
||||
{ passive: false },
|
||||
);
|
||||
micBtn.addEventListener(
|
||||
"touchcancel",
|
||||
(e: TouchEvent) => {
|
||||
e.preventDefault();
|
||||
stopRecording();
|
||||
},
|
||||
{ passive: false },
|
||||
);
|
||||
// Mouse fallback (desktop testing)
|
||||
micBtn.addEventListener("mousedown", (e: MouseEvent) => {
|
||||
// Pointer Events: unified touch + mouse, no double-trigger
|
||||
micBtn.addEventListener("pointerdown", (e: PointerEvent) => {
|
||||
if (e.button !== 0) return;
|
||||
e.preventDefault();
|
||||
startRecording();
|
||||
});
|
||||
micBtn.addEventListener("mouseup", () => stopRecording());
|
||||
micBtn.addEventListener("mouseleave", () => {
|
||||
if (state.recording) stopRecording();
|
||||
micBtn.addEventListener("pointerup", (e: PointerEvent) => {
|
||||
e.preventDefault();
|
||||
stopRecording();
|
||||
});
|
||||
micBtn.addEventListener("pointerleave", () => {
|
||||
if (state.recording || state.pendingStart) stopRecording();
|
||||
});
|
||||
micBtn.addEventListener("pointercancel", () => {
|
||||
if (state.recording || state.pendingStart) stopRecording();
|
||||
});
|
||||
// Prevent context menu on long press
|
||||
micBtn.addEventListener("contextmenu", (e) => e.preventDefault());
|
||||
}
|
||||
// ── Init ──
|
||||
function init(): void {
|
||||
|
||||
Reference in New Issue
Block a user