165 lines
4.4 KiB
Go
165 lines
4.4 KiB
Go
//go:build js
|
|
|
|
package web
|
|
|
|
import (
|
|
"syscall/js"
|
|
|
|
"aego/platform"
|
|
"aego/platform/input"
|
|
)
|
|
|
|
func (p *Platform) listen(target js.Value, name string, passive bool, fn func(js.Value)) {
|
|
f := js.FuncOf(func(_ js.Value, args []js.Value) any {
|
|
if len(args) > 0 {
|
|
fn(args[0])
|
|
} else {
|
|
fn(js.Undefined())
|
|
}
|
|
return nil
|
|
})
|
|
target.Call("addEventListener", name, f, map[string]any{"passive": passive})
|
|
p.listeners = append(p.listeners, listener{target: target, name: name, fn: f})
|
|
}
|
|
|
|
func (p *Platform) push(ev platform.Event) {
|
|
if p.win != nil {
|
|
ev.Window = p.win.metrics
|
|
}
|
|
p.queue = append(p.queue, ev)
|
|
}
|
|
|
|
func prevent(e js.Value) {
|
|
e.Call("preventDefault")
|
|
}
|
|
|
|
func (p *Platform) listenWindow(w *Window) {
|
|
c := w.canvas
|
|
p.listen(c, "keydown", false, func(e js.Value) { p.key(e, true) })
|
|
p.listen(c, "keyup", false, func(e js.Value) { p.key(e, false) })
|
|
p.listen(c, "pointerdown", false, func(e js.Value) { p.button(e, true) })
|
|
p.listen(c, "pointerup", false, func(e js.Value) { p.button(e, false) })
|
|
p.listen(c, "pointercancel", true, p.cancel)
|
|
p.listen(c, "pointermove", true, p.move)
|
|
p.listen(c, "wheel", false, p.wheel)
|
|
p.listen(c, "contextmenu", false, prevent)
|
|
p.listen(c, "focus", true, func(js.Value) { p.push(platform.Event{Kind: platform.EvWindowFocusGained}) })
|
|
p.listen(c, "blur", true, func(js.Value) { p.push(platform.Event{Kind: platform.EvWindowFocusLost}) })
|
|
p.listen(p.doc, "paste", true, p.paste)
|
|
p.listen(p.doc, "pointerlockchange", true, p.lockChanged)
|
|
p.listen(p.global, "resize", true, func(js.Value) {
|
|
if p.win != nil {
|
|
p.win.refresh(true)
|
|
}
|
|
})
|
|
if ro := p.global.Get("ResizeObserver"); ro.Type() == js.TypeFunction {
|
|
w.resize = js.FuncOf(func(js.Value, []js.Value) any {
|
|
w.refresh(true)
|
|
return nil
|
|
})
|
|
w.observer = ro.New(w.resize)
|
|
w.observer.Call("observe", c)
|
|
w.observing = true
|
|
}
|
|
}
|
|
|
|
func (p *Platform) key(e js.Value, down bool) {
|
|
w := p.win
|
|
if w == nil {
|
|
return
|
|
}
|
|
code := e.Get("code").String()
|
|
key := e.Get("key").String()
|
|
mods := modsOf(
|
|
e.Get("shiftKey").Truthy(), e.Get("ctrlKey").Truthy(), e.Get("altKey").Truthy(), e.Get("metaKey").Truthy(),
|
|
try(e, "getModifierState", "CapsLock").Truthy(), try(e, "getModifierState", "NumLock").Truthy(),
|
|
)
|
|
scan := scancodeOf(code)
|
|
kind := platform.EvKeyUp
|
|
if down {
|
|
kind = platform.EvKeyDown
|
|
}
|
|
p.push(platform.Event{Kind: kind, Key: input.KeyEvent{Scan: scan, Key: keycodeOf(key, scan), Mods: mods, Repeat: down && e.Get("repeat").Truthy()}})
|
|
if down && w.textInput {
|
|
if s, ok := textOf(key, mods); ok {
|
|
ev := platform.Event{Kind: platform.EvTextInput}
|
|
ev.TextN = uint8(copy(ev.Text[:], s))
|
|
p.push(ev)
|
|
}
|
|
}
|
|
if !browserKey(code, mods) {
|
|
e.Call("preventDefault")
|
|
}
|
|
if down {
|
|
w.gesture()
|
|
}
|
|
}
|
|
|
|
func (p *Platform) button(e js.Value, down bool) {
|
|
w := p.win
|
|
if w == nil || !e.Get("isPrimary").Truthy() {
|
|
return
|
|
}
|
|
b, ok := pointerButton(e.Get("button").Int())
|
|
if !ok {
|
|
return
|
|
}
|
|
if !w.locked {
|
|
w.last = w.pos(e)
|
|
}
|
|
kind := platform.EvMouseUp
|
|
if down {
|
|
kind = platform.EvMouseDown
|
|
try(w.canvas, "focus")
|
|
try(w.canvas, "setPointerCapture", e.Get("pointerId"))
|
|
e.Call("preventDefault")
|
|
w.gesture()
|
|
}
|
|
p.push(platform.Event{Kind: kind, Mouse: input.MouseEvent{Pos: w.last, Button: b}})
|
|
}
|
|
|
|
func (p *Platform) cancel(e js.Value) {
|
|
if w := p.win; w != nil && e.Get("isPrimary").Truthy() {
|
|
p.push(platform.Event{Kind: platform.EvMouseUp, Mouse: input.MouseEvent{Pos: w.last, Button: input.MouseLeft}})
|
|
}
|
|
}
|
|
|
|
func (p *Platform) move(e js.Value) {
|
|
w := p.win
|
|
if w == nil || !e.Get("isPrimary").Truthy() {
|
|
return
|
|
}
|
|
if !w.locked {
|
|
w.last = w.pos(e)
|
|
}
|
|
d := input.MouseEvent{Pos: w.last}
|
|
d.Delta.X = float32(e.Get("movementX").Float())
|
|
d.Delta.Y = float32(e.Get("movementY").Float())
|
|
p.push(platform.Event{Kind: platform.EvMouseMove, Mouse: d})
|
|
}
|
|
|
|
func (p *Platform) wheel(e js.Value) {
|
|
w := p.win
|
|
if w == nil {
|
|
return
|
|
}
|
|
e.Call("preventDefault")
|
|
v, precise := wheelOf(e.Get("deltaX").Float(), e.Get("deltaY").Float(), e.Get("deltaMode").Int())
|
|
p.push(platform.Event{Kind: platform.EvMouseWheel, Mouse: input.MouseEvent{Pos: w.pos(e), Wheel: v, Precise: precise}})
|
|
}
|
|
|
|
func (p *Platform) paste(e js.Value) {
|
|
if p.win == nil {
|
|
return
|
|
}
|
|
if d := e.Get("clipboardData"); d.Truthy() {
|
|
p.win.clip = memory{text: d.Call("getData", MimeText).String()}
|
|
}
|
|
}
|
|
|
|
func (p *Platform) lockChanged(js.Value) {
|
|
if w := p.win; w != nil {
|
|
w.locked = p.doc.Get("pointerLockElement").Equal(w.canvas)
|
|
}
|
|
}
|