File size: 5,468 Bytes
aeb61fc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

export function initializeEraserPen(canvasElement, onEraserStateChange = null) {
    let isErasing = false

    // Stylus eraser button - most styluses use button 5 (Samsung S-Pen, Wacom, etc.)
    // Some may use button 32, so we check for both
    const ERASER_BUTTON_IDS = [5, 32]

    // Marker to identify synthetic events and prevent infinite loops
    const SYNTHETIC_MARKER = '__eraser_synthetic__'

    console.log('[EraserEngine] Initialized. Listening for buttons:', ERASER_BUTTON_IDS)
    console.log('[EraserEngine] Canvas element:', canvasElement)
    console.log('[EraserEngine] Callback provided:', !!onEraserStateChange)

    const handlePointerDown = (e) => {
        // Skip synthetic events we created
        if (e[SYNTHETIC_MARKER]) {
            return
        }

        // Check if target is canvas
        const isCanvasTarget = e.target === canvasElement || canvasElement.contains(e.target)

        if (!isCanvasTarget) {
            return
        }

        // Check if this is an eraser button
        if (ERASER_BUTTON_IDS.includes(e.button)) {
            console.log('[EraserEngine] ✓ ERASER BUTTON', e.button, 'DETECTED! Activating eraser mode')

            // STOP the original event from reaching canvas handlers
            e.stopPropagation()
            e.preventDefault()

            isErasing = true

            // Notify callback of eraser state change BEFORE dispatching synthetic event
            if (onEraserStateChange) {
                console.log('[EraserEngine] Calling onEraserStateChange(true)')
                onEraserStateChange(true)
            }

            // 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,
                buttons: 1,
                isPrimary: true,
                bubbles: true,
                cancelable: true
            })
            newEvent[SYNTHETIC_MARKER] = true
            console.log('[EraserEngine] Dispatching synthetic pointerdown to canvas')
            canvasElement.dispatchEvent(newEvent)
        }
    }

    const handlePointerMove = (e) => {
        // Skip synthetic events we created
        if (e[SYNTHETIC_MARKER]) return

        if (!isErasing) 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 (isErasing) {
            console.log('[EraserEngine] Ending eraser mode')
            e.stopPropagation()
            e.preventDefault()

            isErasing = false

            // Notify callback of eraser state change
            if (onEraserStateChange) {
                console.log('[EraserEngine] Calling onEraserStateChange(false)')
                onEraserStateChange(false)
            }

            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
            console.log('[EraserEngine] Dispatching synthetic pointerup')
            canvasElement.dispatchEvent(newEvent)
        }
    }

    // Use CAPTURE phase to intercept events BEFORE they reach the canvas
    console.log('[EraserEngine] Adding event listeners with capture phase')
    window.addEventListener('pointerdown', handlePointerDown, true)
    window.addEventListener('pointermove', handlePointerMove, true)
    window.addEventListener('pointerup', handlePointerUp, true)

    return () => {
        console.log('[EraserEngine] Cleanup: removing event listeners')
        window.removeEventListener('pointerdown', handlePointerDown, true)
        window.removeEventListener('pointermove', handlePointerMove, true)
        window.removeEventListener('pointerup', handlePointerUp, true)
    }
}