| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036 |
- //go:build js && !wasm
- // +build js,!wasm
- package glfw
- import (
- "errors"
- "fmt"
- "io"
- "log"
- "net/http"
- "runtime"
- "github.com/gopherjs/gopherjs/js"
- "honnef.co/go/js/dom"
- )
- const (
- True int = 1
- False int = 0
- DontCare int = -1
- )
- var document = dom.GetWindow().Document().(dom.HTMLDocument)
- var contextWatcher ContextWatcher
- func Init(cw ContextWatcher) error {
- contextWatcher = cw
- return nil
- }
- func Terminate() error {
- return nil
- }
- func CreateWindow(_, _ int, title string, monitor *Monitor, share *Window) (*Window, error) {
- // THINK: Consider https://developer.mozilla.org/en-US/docs/Web/API/Window.open?
- // HACK: Go fullscreen?
- width := dom.GetWindow().InnerWidth()
- height := dom.GetWindow().InnerHeight()
- canvas := document.CreateElement("canvas").(*dom.HTMLCanvasElement)
- devicePixelRatio := js.Global.Get("devicePixelRatio").Float()
- canvas.Width = int(float64(width)*devicePixelRatio + 0.5) // Nearest non-negative int.
- canvas.Height = int(float64(height)*devicePixelRatio + 0.5) // Nearest non-negative int.
- canvas.Style().SetProperty("width", fmt.Sprintf("%vpx", width), "")
- canvas.Style().SetProperty("height", fmt.Sprintf("%vpx", height), "")
- if js.Global.Get("document").Get("body") == nil {
- body := js.Global.Get("document").Call("createElement", "body")
- js.Global.Get("document").Set("body", body)
- }
- document.Body().Style().SetProperty("margin", "0", "")
- document.Body().AppendChild(canvas)
- document.SetTitle(title)
- // DEBUG: Add framebuffer information div.
- if false {
- //canvas.Height -= 30
- text := document.CreateElement("div")
- textContent := fmt.Sprintf("%v %v (%v) @%v", dom.GetWindow().InnerWidth(), canvas.Width, float64(width)*devicePixelRatio, devicePixelRatio)
- text.SetTextContent(textContent)
- document.Body().AppendChild(text)
- }
- // Use glfw hints.
- attrs := defaultAttributes()
- attrs.Alpha = (hints[AlphaBits] > 0)
- if _, ok := hints[DepthBits]; ok {
- attrs.Depth = (hints[DepthBits] > 0)
- }
- attrs.Stencil = (hints[StencilBits] > 0)
- attrs.Antialias = (hints[Samples] > 0)
- attrs.PremultipliedAlpha = (hints[PremultipliedAlpha] > 0)
- attrs.PreserveDrawingBuffer = (hints[PreserveDrawingBuffer] > 0)
- attrs.PreferLowPowerToHighPerformance = (hints[PreferLowPowerToHighPerformance] > 0)
- attrs.FailIfMajorPerformanceCaveat = (hints[FailIfMajorPerformanceCaveat] > 0)
- // Create GL context.
- context, err := newContext(canvas.Underlying(), attrs)
- if err != nil {
- return nil, err
- }
- w := &Window{
- canvas: canvas,
- context: context,
- devicePixelRatio: devicePixelRatio,
- }
- if w.canvas.Underlying().Get("requestPointerLock") == js.Undefined ||
- document.Underlying().Get("exitPointerLock") == js.Undefined {
- w.missing.pointerLock = true
- }
- if w.canvas.Underlying().Get("webkitRequestFullscreen") == js.Undefined ||
- document.Underlying().Get("webkitExitFullscreen") == js.Undefined {
- w.missing.fullscreen = true
- }
- if monitor != nil {
- if w.missing.fullscreen {
- log.Println("warning: Fullscreen API unsupported")
- } else {
- w.requestFullscreen = true
- }
- }
- dom.GetWindow().AddEventListener("resize", false, func(event dom.Event) {
- // HACK: Go fullscreen?
- width := dom.GetWindow().InnerWidth()
- height := dom.GetWindow().InnerHeight()
- devicePixelRatio := js.Global.Get("devicePixelRatio").Float()
- w.canvas.Width = int(float64(width)*devicePixelRatio + 0.5) // Nearest non-negative int.
- w.canvas.Height = int(float64(height)*devicePixelRatio + 0.5) // Nearest non-negative int.
- if w.framebufferSizeCallback != nil {
- // TODO: Callbacks may be blocking so they need to happen asyncronously. However,
- // GLFW API promises the callbacks will occur from one thread (i.e., sequentially), so may want to do that.
- go w.framebufferSizeCallback(w, w.canvas.Width, w.canvas.Height)
- }
- if w.sizeCallback != nil {
- boundingW, boundingH := width, height
- go w.sizeCallback(w, boundingW, boundingH)
- }
- })
- document.AddEventListener("keydown", false, func(event dom.Event) {
- w.goFullscreenIfRequested()
- ke := event.(*dom.KeyboardEvent)
- action := Press
- if ke.Repeat {
- action = Repeat
- }
- key := toKey(ke)
- // Extend slice if needed.
- neededSize := int(key) + 1
- if neededSize > len(w.keys) {
- w.keys = append(w.keys, make([]Action, neededSize-len(w.keys))...)
- }
- w.keys[key] = action
- if w.keyCallback != nil {
- mods := toModifierKey(ke)
- go w.keyCallback(w, key, -1, action, mods)
- }
- if w.charCallback != nil {
- if len(ke.Key) == 1 {
- keyRune := []rune(ke.Key)
- go w.charCallback(w, keyRune[0])
- }
- }
- ke.PreventDefault()
- })
- document.AddEventListener("keyup", false, func(event dom.Event) {
- w.goFullscreenIfRequested()
- ke := event.(*dom.KeyboardEvent)
- key := toKey(ke)
- // Extend slice if needed.
- neededSize := int(key) + 1
- if neededSize > len(w.keys) {
- w.keys = append(w.keys, make([]Action, neededSize-len(w.keys))...)
- }
- w.keys[key] = Release
- if w.keyCallback != nil {
- mods := toModifierKey(ke)
- go w.keyCallback(w, key, -1, Release, mods)
- }
- ke.PreventDefault()
- })
- document.AddEventListener("mousedown", false, func(event dom.Event) {
- w.goFullscreenIfRequested()
- me := event.(*dom.MouseEvent)
- if !(me.Button >= 0 && me.Button <= 2) {
- return
- }
- w.mouseButton[me.Button] = Press
- if w.mouseButtonCallback != nil {
- go w.mouseButtonCallback(w, MouseButton(me.Button), Press, 0)
- }
- me.PreventDefault()
- })
- document.AddEventListener("mouseup", false, func(event dom.Event) {
- w.goFullscreenIfRequested()
- me := event.(*dom.MouseEvent)
- if !(me.Button >= 0 && me.Button <= 2) {
- return
- }
- w.mouseButton[me.Button] = Release
- if w.mouseButtonCallback != nil {
- go w.mouseButtonCallback(w, MouseButton(me.Button), Release, 0)
- }
- me.PreventDefault()
- })
- document.AddEventListener("contextmenu", false, func(event dom.Event) {
- event.PreventDefault()
- })
- document.AddEventListener("mousemove", false, func(event dom.Event) {
- me := event.(*dom.MouseEvent)
- var movementX, movementY float64
- if !w.missing.pointerLock {
- movementX = float64(me.MovementX)
- movementY = float64(me.MovementY)
- } else {
- movementX = float64(me.ClientX) - w.cursorPos[0]
- movementY = float64(me.ClientY) - w.cursorPos[1]
- }
- w.cursorPos[0], w.cursorPos[1] = float64(me.ClientX), float64(me.ClientY)
- if w.cursorPosCallback != nil {
- go w.cursorPosCallback(w, w.cursorPos[0], w.cursorPos[1])
- }
- if w.mouseMovementCallback != nil {
- go w.mouseMovementCallback(w, w.cursorPos[0], w.cursorPos[1], movementX, movementY)
- }
- me.PreventDefault()
- })
- document.AddEventListener("wheel", false, func(event dom.Event) {
- we := event.(*dom.WheelEvent)
- var multiplier float64
- switch we.DeltaMode {
- case dom.DeltaPixel:
- multiplier = 0.1
- case dom.DeltaLine:
- multiplier = 1
- default:
- log.Println("unsupported WheelEvent.DeltaMode:", we.DeltaMode)
- multiplier = 1
- }
- if w.scrollCallback != nil {
- go w.scrollCallback(w, -we.DeltaX*multiplier, -we.DeltaY*multiplier)
- }
- we.PreventDefault()
- })
- // Hacky mouse-emulation-via-touch.
- touchHandler := func(event dom.Event) {
- w.goFullscreenIfRequested()
- te := event.(*dom.TouchEvent)
- touches := te.Get("touches")
- if touches.Length() > 0 {
- t := touches.Index(0)
- if w.touches != nil && w.touches.Length() > 0 { // This event is a movement only if we previously had > 0 touch points.
- if w.mouseMovementCallback != nil {
- go w.mouseMovementCallback(w, t.Get("clientX").Float(), t.Get("clientY").Float(), t.Get("clientX").Float()-w.cursorPos[0], t.Get("clientY").Float()-w.cursorPos[1])
- }
- }
- w.cursorPos[0], w.cursorPos[1] = t.Get("clientX").Float(), t.Get("clientY").Float()
- if w.cursorPosCallback != nil {
- go w.cursorPosCallback(w, w.cursorPos[0], w.cursorPos[1])
- }
- }
- w.touches = touches
- te.PreventDefault()
- }
- document.AddEventListener("touchstart", false, touchHandler)
- document.AddEventListener("touchmove", false, touchHandler)
- document.AddEventListener("touchend", false, touchHandler)
- // Request first animation frame.
- js.Global.Call("requestAnimationFrame", animationFrame)
- return w, nil
- }
- func (w *Window) SetAttrib(attrib Hint, value int) {
- // TODO: Implement.
- }
- func SwapInterval(interval int) error {
- // TODO: Implement.
- return nil
- }
- type Window struct {
- canvas *dom.HTMLCanvasElement
- context *js.Object
- requestFullscreen bool // requestFullscreen is set to true when fullscreen should be entered as soon as possible (in a user input handler).
- fullscreen bool // fullscreen is true if we're currently in fullscreen mode.
- // Unavailable browser APIs.
- missing struct {
- pointerLock bool // Pointer Lock API.
- fullscreen bool // Fullscreen API.
- }
- devicePixelRatio float64
- cursorMode int
- cursorPos [2]float64
- mouseButton [3]Action
- keys []Action
- cursorPosCallback CursorPosCallback
- mouseMovementCallback MouseMovementCallback
- mouseButtonCallback MouseButtonCallback
- keyCallback KeyCallback
- charCallback CharCallback
- scrollCallback ScrollCallback
- framebufferSizeCallback FramebufferSizeCallback
- sizeCallback SizeCallback
- touches *js.Object // Hacky mouse-emulation-via-touch.
- }
- func (w *Window) SetPos(xpos, ypos int) {
- fmt.Println("not implemented: SetPos:", xpos, ypos)
- }
- func (w *Window) SetSize(width, height int) {
- fmt.Println("not implemented: SetSize:", width, height)
- }
- func (w *Window) SetIcon(images interface{}) {
- // images is actually of type []image.Image, but no need to import image until we actually do something with it
- fmt.Println("not implemented: SetIcon")
- }
- // goFullscreenIfRequested performs webkitRequestFullscreen if it was scheduled. It is called only from
- // user events, because that API will fail if called at any other time.
- func (w *Window) goFullscreenIfRequested() {
- if !w.requestFullscreen {
- return
- }
- w.requestFullscreen = false
- w.canvas.Underlying().Call("webkitRequestFullscreen")
- w.fullscreen = true
- }
- type Monitor struct{}
- func (m *Monitor) GetVideoMode() *VidMode {
- return &VidMode{
- // HACK: Hardcoded sample values.
- // TODO: Try to get real values from browser via some API, if possible.
- Width: 1680,
- Height: 1050,
- RedBits: 8,
- GreenBits: 8,
- BlueBits: 8,
- RefreshRate: 60,
- }
- }
- func GetPrimaryMonitor() *Monitor {
- // TODO: Implement real functionality.
- return &Monitor{}
- }
- func (w *Window) SetMonitor(monitor *Monitor, xpos, ypos, width, height, refreshRate int) {
- // TODO: Implement real functionality.
- }
- func PollEvents() error {
- return nil
- }
- func (w *Window) MakeContextCurrent() {
- contextWatcher.OnMakeCurrent(w.context)
- }
- func DetachCurrentContext() {
- contextWatcher.OnDetach()
- }
- func GetCurrentContext() *Window {
- panic("not implemented")
- }
- type CursorPosCallback func(w *Window, xpos float64, ypos float64)
- func (w *Window) SetCursorPosCallback(cbfun CursorPosCallback) (previous CursorPosCallback) {
- w.cursorPosCallback = cbfun
- // TODO: Handle previous.
- return nil
- }
- type MouseMovementCallback func(w *Window, xpos float64, ypos float64, xdelta float64, ydelta float64)
- func (w *Window) SetMouseMovementCallback(cbfun MouseMovementCallback) (previous MouseMovementCallback) {
- w.mouseMovementCallback = cbfun
- // TODO: Handle previous.
- return nil
- }
- type KeyCallback func(w *Window, key Key, scancode int, action Action, mods ModifierKey)
- func (w *Window) SetKeyCallback(cbfun KeyCallback) (previous KeyCallback) {
- w.keyCallback = cbfun
- // TODO: Handle previous.
- return nil
- }
- type CharCallback func(w *Window, char rune)
- func (w *Window) SetCharCallback(cbfun CharCallback) (previous CharCallback) {
- w.charCallback = cbfun
- // TODO: Handle previous.
- return nil
- }
- type ScrollCallback func(w *Window, xoff float64, yoff float64)
- func (w *Window) SetScrollCallback(cbfun ScrollCallback) (previous ScrollCallback) {
- w.scrollCallback = cbfun
- // TODO: Handle previous.
- return nil
- }
- type MouseButtonCallback func(w *Window, button MouseButton, action Action, mods ModifierKey)
- func (w *Window) SetMouseButtonCallback(cbfun MouseButtonCallback) (previous MouseButtonCallback) {
- w.mouseButtonCallback = cbfun
- // TODO: Handle previous.
- return nil
- }
- type FramebufferSizeCallback func(w *Window, width int, height int)
- func (w *Window) SetFramebufferSizeCallback(cbfun FramebufferSizeCallback) (previous FramebufferSizeCallback) {
- w.framebufferSizeCallback = cbfun
- // TODO: Handle previous.
- return nil
- }
- func (w *Window) GetSize() (width, height int) {
- width = int(w.canvas.GetBoundingClientRect().Width*w.devicePixelRatio + 0.5)
- height = int(w.canvas.GetBoundingClientRect().Height*w.devicePixelRatio + 0.5)
- return width, height
- }
- func (w *Window) GetFramebufferSize() (width, height int) {
- return w.canvas.Width, w.canvas.Height
- }
- func (w *Window) GetPos() (x, y int) {
- // Not implemented.
- return
- }
- func (w *Window) ShouldClose() bool {
- return false
- }
- func (w *Window) SetShouldClose(value bool) {
- // TODO: Implement.
- // THINK: What should happen in the browser if we're told to "close" the window. Do we destroy/remove the canvas? Or nothing?
- // Perhaps https://developer.mozilla.org/en-US/docs/Web/API/Window.close is relevant.
- }
- func (w *Window) SwapBuffers() error {
- <-animationFrameChan
- js.Global.Call("requestAnimationFrame", animationFrame)
- return nil
- }
- var animationFrameChan = make(chan struct{}, 1)
- func animationFrame() {
- animationFrameChan <- struct{}{}
- }
- func (w *Window) GetCursorPos() (x, y float64) {
- return w.cursorPos[0], w.cursorPos[1]
- }
- var keyWarnings = 10
- func (w *Window) GetKey(key Key) Action {
- if key == -1 && keyWarnings > 0 {
- // TODO: Implement all keys, get rid of this.
- keyWarnings--
- log.Println("GetKey: key not implemented.")
- return Release
- }
- if int(key) >= len(w.keys) {
- return Release
- }
- return w.keys[key]
- }
- func (w *Window) GetMouseButton(button MouseButton) Action {
- if !(button >= 0 && button <= 2) {
- panic(fmt.Errorf("button is out of range: %v", button))
- }
- // Hacky mouse-emulation-via-touch.
- if w.touches != nil {
- switch button {
- case MouseButton1:
- if w.touches.Length() == 1 || w.touches.Length() == 3 {
- return Press
- }
- case MouseButton2:
- if w.touches.Length() == 2 || w.touches.Length() == 3 {
- return Press
- }
- }
- return Release
- }
- return w.mouseButton[button]
- }
- func (w *Window) GetInputMode(mode InputMode) int {
- switch mode {
- case CursorMode:
- return w.cursorMode
- default:
- panic(errors.New("not implemented"))
- }
- }
- var ErrInvalidParameter = errors.New("invalid parameter")
- var ErrInvalidValue = errors.New("invalid value")
- func (w *Window) SetInputMode(mode InputMode, value int) {
- switch mode {
- case CursorMode:
- // TODO; Make cursor API compatible with GLFW and Fyne use/expectation.
- /*
- if w.missing.pointerLock {
- log.Println("warning: Pointer Lock API unsupported")
- return
- }
- switch value {
- case CursorNormal:
- w.cursorMode = value
- document.Underlying().Call("exitPointerLock")
- w.canvas.Style().SetProperty("cursor", "initial", "")
- return
- case CursorHidden:
- w.cursorMode = value
- document.Underlying().Call("exitPointerLock")
- w.canvas.Style().SetProperty("cursor", "none", "")
- return
- case CursorDisabled:
- w.cursorMode = value
- w.canvas.Underlying().Call("requestPointerLock")
- return
- default:
- panic(ErrInvalidValue)
- }
- */
- return
- case StickyKeysMode:
- panic(errors.New("not implemented"))
- case StickyMouseButtonsMode:
- panic(errors.New("not implemented"))
- default:
- panic(ErrInvalidParameter)
- }
- }
- type Key int
- // TODO: Keys defined as -iota-2 need to be set to a valid positive value that matches the keyCode
- // generated by browsers. -iota-2 is used as a temporary solution to have unique but invalid values.
- // See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode.
- const (
- KeyUnknown Key = -1
- KeySpace Key = 32
- KeyApostrophe Key = 222
- KeyComma Key = 188
- KeyMinus Key = 189
- KeyPeriod Key = 190
- KeySlash Key = 191
- Key0 Key = 48
- Key1 Key = 49
- Key2 Key = 50
- Key3 Key = 51
- Key4 Key = 52
- Key5 Key = 53
- Key6 Key = 54
- Key7 Key = 55
- Key8 Key = 56
- Key9 Key = 57
- KeySemicolon Key = 186
- KeyEqual Key = 187
- KeyA Key = 65
- KeyB Key = 66
- KeyC Key = 67
- KeyD Key = 68
- KeyE Key = 69
- KeyF Key = 70
- KeyG Key = 71
- KeyH Key = 72
- KeyI Key = 73
- KeyJ Key = 74
- KeyK Key = 75
- KeyL Key = 76
- KeyM Key = 77
- KeyN Key = 78
- KeyO Key = 79
- KeyP Key = 80
- KeyQ Key = 81
- KeyR Key = 82
- KeyS Key = 83
- KeyT Key = 84
- KeyU Key = 85
- KeyV Key = 86
- KeyW Key = 87
- KeyX Key = 88
- KeyY Key = 89
- KeyZ Key = 90
- KeyLeftBracket Key = 219
- KeyBackslash Key = 220
- KeyRightBracket Key = 221
- KeyGraveAccent Key = 192
- KeyWorld1 Key = -iota - 2
- KeyWorld2 Key = -iota - 2
- KeyEscape Key = 27
- KeyEnter Key = 13
- KeyTab Key = 9
- KeyBackspace Key = 8
- KeyInsert Key = -iota - 2
- KeyDelete Key = 46
- KeyRight Key = 39
- KeyLeft Key = 37
- KeyDown Key = 40
- KeyUp Key = 38
- KeyPageUp Key = -iota - 2
- KeyPageDown Key = -iota - 2
- KeyHome Key = -iota - 2
- KeyEnd Key = -iota - 2
- KeyCapsLock Key = 20
- KeyScrollLock Key = -iota - 2
- KeyNumLock Key = -iota - 2
- KeyPrintScreen Key = -iota - 2
- KeyPause Key = -iota - 2
- KeyF1 Key = 112
- KeyF2 Key = 113
- KeyF3 Key = 114
- KeyF4 Key = 115
- KeyF5 Key = 116
- KeyF6 Key = 117
- KeyF7 Key = 118
- KeyF8 Key = 119
- KeyF9 Key = 120
- KeyF10 Key = 121
- KeyF11 Key = 122
- KeyF12 Key = 123
- KeyF13 Key = -iota - 2
- KeyF14 Key = -iota - 2
- KeyF15 Key = -iota - 2
- KeyF16 Key = -iota - 2
- KeyF17 Key = -iota - 2
- KeyF18 Key = -iota - 2
- KeyF19 Key = -iota - 2
- KeyF20 Key = -iota - 2
- KeyF21 Key = -iota - 2
- KeyF22 Key = -iota - 2
- KeyF23 Key = -iota - 2
- KeyF24 Key = -iota - 2
- KeyF25 Key = -iota - 2
- KeyKP0 Key = -iota - 2
- KeyKP1 Key = -iota - 2
- KeyKP2 Key = -iota - 2
- KeyKP3 Key = -iota - 2
- KeyKP4 Key = -iota - 2
- KeyKP5 Key = -iota - 2
- KeyKP6 Key = -iota - 2
- KeyKP7 Key = -iota - 2
- KeyKP8 Key = -iota - 2
- KeyKP9 Key = -iota - 2
- KeyKPDecimal Key = -iota - 2
- KeyKPDivide Key = -iota - 2
- KeyKPMultiply Key = -iota - 2
- KeyKPSubtract Key = -iota - 2
- KeyKPAdd Key = -iota - 2
- KeyKPEnter Key = -iota - 2
- KeyKPEqual Key = -iota - 2
- KeyLeftShift Key = 340
- KeyLeftControl Key = 341
- KeyLeftAlt Key = 342
- KeyLeftSuper Key = 91
- KeyRightShift Key = 344
- KeyRightControl Key = 345
- KeyRightAlt Key = 346
- KeyRightSuper Key = 93
- KeyMenu Key = -iota - 2
- )
- // toKey extracts Key from given KeyboardEvent.
- func toKey(ke *dom.KeyboardEvent) Key {
- key := Key(ke.KeyCode)
- switch {
- case key == 16 && ke.Location == dom.KeyLocationLeft:
- key = KeyLeftShift
- case key == 16 && ke.Location == dom.KeyLocationRight:
- key = KeyRightShift
- case key == 17 && ke.Location == dom.KeyLocationLeft:
- key = KeyLeftControl
- case key == 17 && ke.Location == dom.KeyLocationRight:
- key = KeyRightControl
- case key == 18 && ke.Location == dom.KeyLocationLeft:
- key = KeyLeftAlt
- case key == 18 && ke.Location == dom.KeyLocationRight:
- key = KeyRightAlt
- }
- return key
- }
- // toModifierKey extracts ModifierKey from given KeyboardEvent.
- func toModifierKey(ke *dom.KeyboardEvent) ModifierKey {
- mods := ModifierKey(0)
- if ke.ShiftKey {
- mods += ModShift
- }
- if ke.CtrlKey {
- mods += ModControl
- }
- if ke.AltKey {
- mods += ModAlt
- }
- if ke.MetaKey {
- mods += ModSuper
- }
- return mods
- }
- type MouseButton int
- const (
- MouseButton1 MouseButton = 0
- MouseButton2 MouseButton = 2 // Web MouseEvent has middle and right mouse buttons in reverse order.
- MouseButton3 MouseButton = 1 // Web MouseEvent has middle and right mouse buttons in reverse order.
- MouseButtonLeft = MouseButton1
- MouseButtonRight = MouseButton2
- MouseButtonMiddle = MouseButton3
- )
- type Joystick int
- const (
- Joystick1 Joystick = iota
- Joystick2
- Joystick3
- Joystick4
- Joystick5
- Joystick6
- Joystick7
- Joystick8
- Joystick9
- Joystick10
- Joystick11
- Joystick12
- Joystick13
- Joystick14
- Joystick15
- Joystick16
- JoystickLast = Joystick16
- )
- type GamepadAxis int
- const (
- AxisLeftX GamepadAxis = iota
- AxisLeftY
- AxisRightX
- AxisRightY
- AxisLeftTrigger
- AxisRightTrigger
- AxisLast = AxisRightTrigger
- )
- type GamepadButton int
- const (
- ButtonA GamepadButton = iota
- ButtonB
- ButtonX
- ButtonY
- ButtonLeftBumper
- ButtonRightBumper
- ButtonBack
- ButtonStart
- ButtonGuide
- ButtonLeftThumb
- ButtonRightThumb
- ButtonDpadUp
- ButtonDpadRight
- ButtonDpadDown
- ButtonDpadLeft
- ButtonLast = ButtonDpadLeft
- ButtonCross = ButtonA
- ButtonCircle = ButtonB
- ButtonSquare = ButtonX
- ButtonTriangle = ButtonY
- )
- type Action int
- const (
- Release Action = 0
- Press Action = 1
- Repeat Action = 2
- )
- type InputMode int
- const (
- CursorMode InputMode = iota
- StickyKeysMode
- StickyMouseButtonsMode
- LockKeyMods
- RawMouseMotion
- )
- const (
- CursorNormal = iota
- CursorHidden
- CursorDisabled
- )
- type ModifierKey int
- const (
- ModShift ModifierKey = (1 << iota)
- ModControl
- ModAlt
- ModSuper
- )
- func (joy Joystick) IsPresent() bool {
- // TODO: Implement.
- return false
- }
- func (joy Joystick) GetGamepadName() string {
- // TODO: Implement.
- return "Gamepad"
- }
- func (joy Joystick) GetButtons() []Action {
- // TODO: Implement.
- return make([]Action, 0)
- }
- func (joy Joystick) GetAxes() []float32 {
- // TODO: Implement.
- return make([]float32, 0)
- }
- // Open opens a named asset. It's the caller's responsibility to close it when done.
- func Open(name string) (io.ReadCloser, error) {
- resp, err := http.Get(name)
- if err != nil {
- return nil, err
- }
- if resp.StatusCode != 200 {
- return nil, fmt.Errorf("non-200 status: %s", resp.Status)
- }
- return resp.Body, nil
- }
- // ---
- func WaitEvents() {
- // TODO.
- runtime.Gosched()
- }
- func PostEmptyEvent() {
- // TODO: Implement.
- }
- func DefaultWindowHints() {
- // TODO: Implement.
- }
- func (w *Window) SetClipboardString(str string) {
- // TODO: Implement.
- }
- func (w *Window) GetClipboardString() (string, error) {
- // TODO: Implement.
- return "", errors.New("GetClipboardString not implemented")
- }
- func (w *Window) SetTitle(title string) {
- document.SetTitle(title)
- }
- func (w *Window) Show() {
- // TODO: Implement.
- }
- func (w *Window) Hide() {
- // TODO: Implement.
- }
- func (w *Window) Destroy() {
- document.Body().RemoveChild(w.canvas)
- if w.fullscreen {
- if w.missing.fullscreen {
- log.Println("warning: Fullscreen API unsupported")
- } else {
- document.Underlying().Call("webkitExitFullscreen")
- w.fullscreen = false
- }
- }
- }
- type CloseCallback func(w *Window)
- func (w *Window) SetCloseCallback(cbfun CloseCallback) (previous CloseCallback) {
- // TODO: Implement.
- // TODO: Handle previous.
- return nil
- }
- type RefreshCallback func(w *Window)
- func (w *Window) SetRefreshCallback(cbfun RefreshCallback) (previous RefreshCallback) {
- // TODO: Implement.
- // TODO: Handle previous.
- return nil
- }
- type SizeCallback func(w *Window, width int, height int)
- func (w *Window) SetSizeCallback(cbfun SizeCallback) (previous SizeCallback) {
- w.sizeCallback = cbfun
- // TODO: Handle previous.
- return nil
- }
- type CursorEnterCallback func(w *Window, entered bool)
- func (w *Window) SetCursorEnterCallback(cbfun CursorEnterCallback) (previous CursorEnterCallback) {
- // TODO: Implement.
- // TODO: Handle previous.
- return nil
- }
- type CharModsCallback func(w *Window, char rune, mods ModifierKey)
- func (w *Window) SetCharModsCallback(cbfun CharModsCallback) (previous CharModsCallback) {
- // TODO: Implement.
- // TODO: Handle previous.
- return nil
- }
- type PosCallback func(w *Window, xpos int, ypos int)
- func (w *Window) SetPosCallback(cbfun PosCallback) (previous PosCallback) {
- // TODO: Implement.
- // TODO: Handle previous.
- return nil
- }
- type FocusCallback func(w *Window, focused bool)
- func (w *Window) SetFocusCallback(cbfun FocusCallback) (previous FocusCallback) {
- // TODO: Implement.
- // TODO: Handle previous.
- return nil
- }
- type IconifyCallback func(w *Window, iconified bool)
- func (w *Window) SetIconifyCallback(cbfun IconifyCallback) (previous IconifyCallback) {
- // TODO: Implement.
- // TODO: Handle previous.
- return nil
- }
- type DropCallback func(w *Window, names []string)
- func (w *Window) SetDropCallback(cbfun DropCallback) (previous DropCallback) {
- // TODO: Implement. Can use HTML5 file drag and drop API?
- // TODO: Handle previous.
- return nil
- }
|