File size: 4,289 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

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)
    }
}