Spaces:
Sleeping
Sleeping
| export function initializeSPen(canvasElement) { | |
| let isPen = false | |
| // S-Pen uses button ID 5 | |
| const SPEN_BUTTON_ID = 5 | |
| // Marker to identify synthetic events and prevent infinite loops | |
| const SYNTHETIC_MARKER = '__spen_synthetic__' | |
| const handlePointerDown = (e) => { | |
| // Skip synthetic events we created | |
| if (e[SYNTHETIC_MARKER]) return | |
| // CRITICAL: Only process if the event target is the canvas or inside it | |
| if (e.target !== canvasElement && !canvasElement.contains(e.target)) { | |
| return | |
| } | |
| if (e.button === SPEN_BUTTON_ID) { | |
| // STOP the original event from reaching canvas handlers | |
| e.stopPropagation() | |
| e.preventDefault() | |
| isPen = true | |
| // Dispatch S-Pen button event for tool switching | |
| window.dispatchEvent(new CustomEvent('spen-button-down')) | |
| // Dispatch a synthetic 'pointerdown' event with button 0 | |
| const newEvent = new PointerEvent('pointerdown', { | |
| clientX: e.clientX, | |
| clientY: e.clientY, | |
| screenX: e.screenX, | |
| screenY: e.screenY, | |
| pointerId: e.pointerId, | |
| pointerType: e.pointerType, | |
| pressure: e.pressure, | |
| width: e.width, | |
| height: e.height, | |
| tiltX: e.tiltX, | |
| tiltY: e.tiltY, | |
| button: 0, // Pretend it's a left-click/touch | |
| buttons: 1, | |
| isPrimary: true, | |
| bubbles: true, | |
| cancelable: true | |
| }) | |
| newEvent[SYNTHETIC_MARKER] = true | |
| canvasElement.dispatchEvent(newEvent) | |
| } | |
| } | |
| const handlePointerMove = (e) => { | |
| // Skip synthetic events we created | |
| if (e[SYNTHETIC_MARKER]) return | |
| if (!isPen) return | |
| // Stop original event and dispatch synthetic one | |
| e.stopPropagation() | |
| e.preventDefault() | |
| const newEvent = new PointerEvent('pointermove', { | |
| clientX: e.clientX, | |
| clientY: e.clientY, | |
| screenX: e.screenX, | |
| screenY: e.screenY, | |
| pointerId: e.pointerId, | |
| pointerType: e.pointerType, | |
| pressure: e.pressure, | |
| width: e.width, | |
| height: e.height, | |
| tiltX: e.tiltX, | |
| tiltY: e.tiltY, | |
| button: 0, | |
| buttons: 1, | |
| isPrimary: true, | |
| bubbles: true, | |
| cancelable: true | |
| }) | |
| newEvent[SYNTHETIC_MARKER] = true | |
| canvasElement.dispatchEvent(newEvent) | |
| } | |
| const handlePointerUp = (e) => { | |
| // Skip synthetic events we created | |
| if (e[SYNTHETIC_MARKER]) return | |
| if (isPen) { | |
| e.stopPropagation() | |
| e.preventDefault() | |
| isPen = false | |
| // Dispatch S-Pen button up event for tool switching | |
| window.dispatchEvent(new CustomEvent('spen-button-up')) | |
| const newEvent = new PointerEvent('pointerup', { | |
| clientX: e.clientX, | |
| clientY: e.clientY, | |
| screenX: e.screenX, | |
| screenY: e.screenY, | |
| pointerId: e.pointerId, | |
| pointerType: e.pointerType, | |
| pressure: e.pressure, | |
| width: e.width, | |
| height: e.height, | |
| tiltX: e.tiltX, | |
| tiltY: e.tiltY, | |
| button: 0, | |
| buttons: 0, | |
| isPrimary: true, | |
| bubbles: true, | |
| cancelable: true | |
| }) | |
| newEvent[SYNTHETIC_MARKER] = true | |
| canvasElement.dispatchEvent(newEvent) | |
| } | |
| } | |
| // Use CAPTURE phase to intercept events BEFORE they reach the canvas | |
| window.addEventListener('pointerdown', handlePointerDown, true) | |
| window.addEventListener('pointermove', handlePointerMove, true) | |
| window.addEventListener('pointerup', handlePointerUp, true) | |
| return () => { | |
| window.removeEventListener('pointerdown', handlePointerDown, true) | |
| window.removeEventListener('pointermove', handlePointerMove, true) | |
| window.removeEventListener('pointerup', handlePointerUp, true) | |
| } | |
| } | |