2019-06-27 01:36:54 +00:00
|
|
|
package canvas
|
|
|
|
|
|
|
|
import (
|
|
|
|
"syscall/js"
|
|
|
|
|
|
|
|
"git.kirsle.net/apps/doodle/lib/events"
|
|
|
|
"git.kirsle.net/apps/doodle/pkg/log"
|
|
|
|
)
|
|
|
|
|
2019-06-27 03:33:24 +00:00
|
|
|
// EventClass to categorize JavaScript events.
|
|
|
|
type EventClass int
|
|
|
|
|
|
|
|
// EventClass values.
|
|
|
|
const (
|
|
|
|
MouseEvent EventClass = iota
|
|
|
|
KeyEvent
|
|
|
|
ResizeEvent
|
|
|
|
)
|
|
|
|
|
|
|
|
// Event object queues up asynchronous JavaScript events to be processed linearly.
|
|
|
|
type Event struct {
|
|
|
|
Name string // mouseup, keydown, etc.
|
|
|
|
Class EventClass
|
|
|
|
|
|
|
|
// Mouse events.
|
|
|
|
X int
|
|
|
|
Y int
|
|
|
|
LeftClick bool
|
|
|
|
RightClick bool
|
|
|
|
|
|
|
|
// Key events.
|
|
|
|
KeyName string
|
|
|
|
State bool
|
|
|
|
Repeat bool
|
|
|
|
}
|
|
|
|
|
2019-06-27 01:36:54 +00:00
|
|
|
// AddEventListeners sets up bindings to collect events from the browser.
|
|
|
|
func (e *Engine) AddEventListeners() {
|
|
|
|
// Mouse movement.
|
|
|
|
e.canvas.Value.Call(
|
|
|
|
"addEventListener",
|
|
|
|
"mousemove",
|
|
|
|
js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
|
|
|
var (
|
|
|
|
x = args[0].Get("pageX").Int()
|
|
|
|
y = args[0].Get("pageY").Int()
|
|
|
|
)
|
|
|
|
|
2019-06-27 03:33:24 +00:00
|
|
|
e.queue <- Event{
|
|
|
|
Name: "mousemove",
|
|
|
|
Class: MouseEvent,
|
|
|
|
X: x,
|
|
|
|
Y: y,
|
|
|
|
}
|
2019-06-27 01:36:54 +00:00
|
|
|
return nil
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
|
|
|
|
// Mouse clicks.
|
|
|
|
for _, ev := range []string{"mouseup", "mousedown"} {
|
|
|
|
ev := ev
|
|
|
|
e.canvas.Value.Call(
|
|
|
|
"addEventListener",
|
|
|
|
ev,
|
|
|
|
js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
|
|
|
var (
|
|
|
|
x = args[0].Get("pageX").Int()
|
|
|
|
y = args[0].Get("pageY").Int()
|
|
|
|
which = args[0].Get("which").Int()
|
|
|
|
)
|
|
|
|
|
|
|
|
log.Info("Clicked at %d,%d", x, y)
|
|
|
|
|
|
|
|
// Is a mouse button pressed down?
|
|
|
|
checkDown := func(number int) bool {
|
|
|
|
if which == number {
|
|
|
|
return ev == "mousedown"
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-06-27 03:33:24 +00:00
|
|
|
e.queue <- Event{
|
|
|
|
Name: ev,
|
|
|
|
Class: MouseEvent,
|
|
|
|
X: x,
|
|
|
|
Y: y,
|
|
|
|
LeftClick: checkDown(1),
|
|
|
|
RightClick: checkDown(3),
|
|
|
|
}
|
2019-06-27 01:36:54 +00:00
|
|
|
return false
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Supress context menu.
|
|
|
|
e.canvas.Value.Call(
|
|
|
|
"addEventListener",
|
|
|
|
"contextmenu",
|
|
|
|
js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
|
|
|
args[0].Call("preventDefault")
|
|
|
|
return false
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
|
|
|
|
// Keyboard keys
|
2019-06-27 03:33:24 +00:00
|
|
|
for _, ev := range []string{"keydown", "keyup"} {
|
|
|
|
ev := ev
|
|
|
|
js.Global().Get("document").Call(
|
|
|
|
"addEventListener",
|
|
|
|
ev,
|
|
|
|
js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
|
|
|
var (
|
|
|
|
event = args[0]
|
|
|
|
key = event.Get("key").String()
|
|
|
|
repeat = event.Get("repeat").Bool()
|
|
|
|
|
|
|
|
pressed = ev == "keydown"
|
|
|
|
)
|
|
|
|
|
|
|
|
if key == "F3" {
|
|
|
|
args[0].Call("preventDefault")
|
|
|
|
}
|
|
|
|
|
|
|
|
e.queue <- Event{
|
|
|
|
Name: ev,
|
|
|
|
Class: KeyEvent,
|
|
|
|
KeyName: key,
|
|
|
|
Repeat: repeat,
|
|
|
|
State: pressed,
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// PollEvent returns the next event in the queue, or null.
|
|
|
|
func (e *Engine) PollEvent() *Event {
|
|
|
|
select {
|
|
|
|
case event := <-e.queue:
|
|
|
|
return &event
|
|
|
|
default:
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return nil
|
2019-06-27 01:36:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Poll for events.
|
|
|
|
func (e *Engine) Poll() (*events.State, error) {
|
2019-06-27 03:33:24 +00:00
|
|
|
s := e.events
|
|
|
|
|
|
|
|
if e.events.EnterKey.Now {
|
|
|
|
log.Info("saw enter key here, good")
|
|
|
|
}
|
|
|
|
if e.events.KeyName.Now == "h" {
|
|
|
|
log.Info("saw letter h here, good")
|
|
|
|
}
|
|
|
|
|
|
|
|
for event := e.PollEvent(); event != nil; event = e.PollEvent() {
|
|
|
|
switch event.Class {
|
|
|
|
case MouseEvent:
|
|
|
|
s.CursorX.Push(int32(event.X))
|
|
|
|
s.CursorY.Push(int32(event.Y))
|
|
|
|
s.Button1.Push(event.LeftClick)
|
|
|
|
s.Button2.Push(event.RightClick)
|
|
|
|
case KeyEvent:
|
|
|
|
switch event.KeyName {
|
|
|
|
case "Enter":
|
|
|
|
if event.Repeat {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if event.State {
|
|
|
|
s.EnterKey.Push(true)
|
|
|
|
}
|
|
|
|
case "F3":
|
|
|
|
if event.State {
|
|
|
|
s.KeyName.Push("F3")
|
|
|
|
}
|
|
|
|
case "ArrowUp":
|
|
|
|
s.Up.Push(event.State)
|
|
|
|
case "ArrowLeft":
|
|
|
|
s.Left.Push(event.State)
|
|
|
|
case "ArrowRight":
|
|
|
|
s.Right.Push(event.State)
|
|
|
|
case "ArrowDown":
|
|
|
|
s.Down.Push(event.State)
|
|
|
|
case "Shift":
|
|
|
|
s.ShiftActive.Push(event.State)
|
|
|
|
continue
|
|
|
|
case "Alt":
|
|
|
|
case "Control":
|
|
|
|
continue
|
|
|
|
case "Backspace":
|
|
|
|
if event.State {
|
|
|
|
s.KeyName.Push(`\b`)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
log.Info("default handler, push key %s", event.KeyName)
|
|
|
|
if event.State {
|
|
|
|
s.KeyName.Push(event.KeyName)
|
|
|
|
} else {
|
|
|
|
s.KeyName.Push("")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Info("event end, stored key=%s", s.KeyName.Now)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-27 01:36:54 +00:00
|
|
|
return e.events, nil
|
|
|
|
}
|