mirror of
https://github.com/stablyai/orca.git
synced 2026-10-20 00:03:45 +00:00
fix(mobile): end mouse gestures whose pointerup never reached the surface
Capture the mouse pointer on pointerdown so a drag that leaves the surface keeps delivering pointermove/pointerup; when capture is unavailable and the release is lost anyway, synthesize the release from the next buttons==0 pointermove or the next pointerdown, so a tracking TUI is never left with the left button latched down.
This commit is contained in:
@@ -128,7 +128,13 @@ export const TERMINAL_MOUSE_CLICK_DRAG_JS = `
|
||||
targetSurface.addEventListener('pointermove', function(e) {
|
||||
var gesture = mouseGesture;
|
||||
if (e.pointerType !== 'mouse' || !gesture || gesture.mode === 'cancelled') return;
|
||||
if (!term || (e.buttons & 1) === 0) return;
|
||||
if (!term) return;
|
||||
if ((e.buttons & 1) === 0) {
|
||||
// Why: a pointerup lost outside the WebView (capture unavailable) must
|
||||
// end the gesture here, or a tracked press stays latched at the TUI.
|
||||
abandonMouseGesture();
|
||||
return;
|
||||
}
|
||||
gesture.lastX = e.clientX;
|
||||
gesture.lastY = e.clientY;
|
||||
if (!gesture.moved) {
|
||||
|
||||
@@ -254,7 +254,7 @@ describe('terminal WebView external mouse click and drag', () => {
|
||||
expect(new Set(motionCols).size).toBe(motionCols.length)
|
||||
})
|
||||
|
||||
it('does not report press or motion for an x10 click-only TUI drag', () => {
|
||||
it('does not report motion or release for an x10 click-only TUI drag', () => {
|
||||
boot()
|
||||
activeTerminal().modes.mouseTrackingMode = 'x10'
|
||||
|
||||
@@ -338,6 +338,26 @@ describe('terminal WebView external mouse click and drag', () => {
|
||||
expect(terminalInputBytes(postMessage)).toBe('')
|
||||
})
|
||||
|
||||
it('releases a tracked drag when the button state shows the pointerup was lost', () => {
|
||||
boot()
|
||||
activeTerminal().modes.mouseTrackingMode = 'drag'
|
||||
|
||||
dispatchPointer('pointerdown', { x: 40, y: 60, button: 0, buttons: 1 })
|
||||
dispatchPointer('pointermove', { x: 160, y: 60, button: 0, buttons: 1 })
|
||||
// Pointer re-enters with the button already up — the pointerup never arrived.
|
||||
dispatchPointer('pointermove', { x: 200, y: 60, button: 0, buttons: 0 })
|
||||
|
||||
const reports = terminalInputBytes(postMessage).match(DEFAULT_MOUSE_REPORT_RE) ?? []
|
||||
expect(reports[reports.length - 1]?.charCodeAt(3)).toBe(35)
|
||||
|
||||
postMessage.mockClear()
|
||||
dispatchPointer('pointermove', { x: 240, y: 60, button: 0, buttons: 1 })
|
||||
|
||||
// The lost pointerup ended the gesture; a later unrelated move must not
|
||||
// keep emitting motion for it.
|
||||
expect(terminalInputBytes(postMessage)).toBe('')
|
||||
})
|
||||
|
||||
it('releases a tracked drag when the pointer is cancelled mid-gesture', () => {
|
||||
boot()
|
||||
activeTerminal().modes.mouseTrackingMode = 'drag'
|
||||
|
||||
Reference in New Issue
Block a user