From 9b8a341a26a4cbd482c82ddd8ac1f37cb6099f67 Mon Sep 17 00:00:00 2001 From: Long Date: Sat, 11 Apr 2026 02:05:35 +0700 Subject: [PATCH] fix HUD bar drag uses document events instead of pointer capture. --- src/components/launch/LaunchWindow.tsx | 268 ++++++++++++------------- 1 file changed, 130 insertions(+), 138 deletions(-) diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx index 12c9115f..3cf4d291 100644 --- a/src/components/launch/LaunchWindow.tsx +++ b/src/components/launch/LaunchWindow.tsx @@ -244,6 +244,25 @@ export function LaunchWindow() { previewHeight: number; dragging: boolean; } | null>(null); + const hudDragStartRef = useRef< + | { + pointerId: number; + mode: "webcam-preview"; + startX: number; + startY: number; + originX: number; + originY: number; + initialLeft: number; + initialTop: number; + hudWidth: number; + hudHeight: number; + } + | { + pointerId: number; + mode: "overlay"; + } + | null + >(null); const isHudDraggingRef = useRef(false); const isWebcamPreviewDraggingRef = useRef(false); @@ -394,6 +413,113 @@ export function LaunchWindow() { } }; + const handleHudBarPointerDown = ( + event: React.PointerEvent, + ) => { + if (event.button !== 0) { + return; + } + + event.preventDefault(); + event.currentTarget.setPointerCapture(event.pointerId); + isHudDraggingRef.current = true; + window.electronAPI?.hudOverlaySetIgnoreMouse?.(false); + + if (showRecordingWebcamPreview && hudBarRef.current) { + const hudRect = hudBarRef.current.getBoundingClientRect(); + hudDragStartRef.current = { + pointerId: event.pointerId, + mode: "webcam-preview", + startX: event.clientX, + startY: event.clientY, + originX: recordingHudOffset.x, + originY: recordingHudOffset.y, + initialLeft: hudRect.left, + initialTop: hudRect.top, + hudWidth: hudRect.width, + hudHeight: hudRect.height, + }; + return; + } + + hudDragStartRef.current = { + pointerId: event.pointerId, + mode: "overlay", + }; + window.electronAPI?.hudOverlayDrag?.( + "start", + event.screenX, + event.screenY, + ); + }; + + const handleHudBarPointerMove = ( + event: React.PointerEvent, + ) => { + const dragState = hudDragStartRef.current; + if (!dragState || dragState.pointerId !== event.pointerId) { + return; + } + + if (dragState.mode === "webcam-preview") { + const deltaX = event.clientX - dragState.startX; + const deltaY = event.clientY - dragState.startY; + const viewportWidth = Math.max( + window.innerWidth, + window.screen?.width ?? 0, + ); + const viewportHeight = Math.max( + window.innerHeight, + window.screen?.height ?? 0, + ); + const unclampedLeft = dragState.initialLeft + deltaX; + const unclampedTop = dragState.initialTop + deltaY; + const clampedLeft = Math.min( + Math.max(0, unclampedLeft), + Math.max(0, viewportWidth - dragState.hudWidth), + ); + const clampedTop = Math.min( + Math.max(0, unclampedTop), + Math.max(0, viewportHeight - dragState.hudHeight), + ); + + setRecordingHudOffset({ + x: dragState.originX + (clampedLeft - dragState.initialLeft), + y: dragState.originY + (clampedTop - dragState.initialTop), + }); + return; + } + + window.electronAPI?.hudOverlayDrag?.( + "move", + event.screenX, + event.screenY, + ); + }; + + const handleHudBarPointerUp = ( + event: React.PointerEvent, + ) => { + const dragState = hudDragStartRef.current; + if (!dragState || dragState.pointerId !== event.pointerId) { + return; + } + + if (dragState.mode === "overlay") { + window.electronAPI?.hudOverlayDrag?.("end", 0, 0); + } + + hudDragStartRef.current = null; + const wasDragging = isHudDraggingRef.current; + isHudDraggingRef.current = false; + if (event.currentTarget.hasPointerCapture(event.pointerId)) { + event.currentTarget.releasePointerCapture(event.pointerId); + } + if (wasDragging) { + window.electronAPI?.hudOverlaySetIgnoreMouse?.(true); + } + }; + const attachPreviewStreamToNode = useCallback( (videoElement: HTMLVideoElement | null) => { const previewStream = previewStreamRef.current; @@ -1627,144 +1753,10 @@ export function LaunchWindow() { >
{ - e.preventDefault(); - isHudDraggingRef.current = true; - window.electronAPI?.hudOverlaySetIgnoreMouse?.( - false, - ); - - if ( - showRecordingWebcamPreview && - hudBarRef.current - ) { - const hudRect = - hudBarRef.current.getBoundingClientRect(); - const dragStartX = e.clientX; - const dragStartY = e.clientY; - const originX = recordingHudOffset.x; - const originY = recordingHudOffset.y; - const initialLeft = hudRect.left; - const initialTop = hudRect.top; - const hudWidth = hudRect.width; - const hudHeight = hudRect.height; - - const handleMove = (ev: MouseEvent) => { - const deltaX = - ev.clientX - dragStartX; - const deltaY = - ev.clientY - dragStartY; - const viewportWidth = Math.max( - window.innerWidth, - window.screen?.width ?? 0, - ); - const viewportHeight = Math.max( - window.innerHeight, - window.screen?.height ?? 0, - ); - const unclampedLeft = - initialLeft + deltaX; - const unclampedTop = - initialTop + deltaY; - const clampedLeft = Math.min( - Math.max(0, unclampedLeft), - Math.max( - 0, - viewportWidth - hudWidth, - ), - ); - const clampedTop = Math.min( - Math.max(0, unclampedTop), - Math.max( - 0, - viewportHeight - hudHeight, - ), - ); - - setRecordingHudOffset({ - x: - originX + - (clampedLeft - initialLeft), - y: - originY + - (clampedTop - initialTop), - }); - }; - - const handleUp = () => { - const wasDragging = - isHudDraggingRef.current; - isHudDraggingRef.current = false; - if (wasDragging) { - window.electronAPI?.hudOverlaySetIgnoreMouse?.( - true, - ); - } - document.removeEventListener( - "mousemove", - handleMove, - ); - document.removeEventListener( - "mouseup", - handleUp, - ); - }; - - document.addEventListener( - "mousemove", - handleMove, - ); - document.addEventListener( - "mouseup", - handleUp, - ); - return; - } - - window.electronAPI?.hudOverlayDrag?.( - "start", - e.screenX, - e.screenY, - ); - const handleMove = (ev: MouseEvent) => { - window.electronAPI?.hudOverlayDrag?.( - "move", - ev.screenX, - ev.screenY, - ); - }; - const handleUp = () => { - const wasDragging = - isHudDraggingRef.current; - isHudDraggingRef.current = false; - window.electronAPI?.hudOverlayDrag?.( - "end", - 0, - 0, - ); - if (wasDragging) { - window.electronAPI?.hudOverlaySetIgnoreMouse?.( - true, - ); - } - document.removeEventListener( - "mousemove", - handleMove, - ); - document.removeEventListener( - "mouseup", - handleUp, - ); - }; - document.addEventListener( - "mousemove", - handleMove, - ); - document.addEventListener( - "mouseup", - handleUp, - ); - }} + onPointerDown={handleHudBarPointerDown} + onPointerMove={handleHudBarPointerMove} + onPointerUp={handleHudBarPointerUp} + onPointerCancel={handleHudBarPointerUp} >