diff --git a/window/canvas.go b/window/canvas.go index 34ca663a..14cd9389 100644 --- a/window/canvas.go +++ b/window/canvas.go @@ -328,6 +328,7 @@ type WebGlCanvas struct { cursorEv CursorEvent scrollEv ScrollEvent focusEv FocusEvent + lockEv LockEvent // Callbacks onCtxMenu js.Func @@ -340,6 +341,7 @@ type WebGlCanvas struct { winResize js.Func winFocus js.Func winBlur js.Func + mouseLock js.Func } // Init initializes the WebGlCanvas singleton. @@ -386,6 +388,13 @@ func Init(canvasId string) error { // TODO scaling/hidpi (device pixel ratio) + w.mouseLock = js.FuncOf(func(this js.Value, args []js.Value) interface{} { + w.lockEv.Locked = doc.Get("pointerLockElement").Equal(w.canvas) + w.Dispatch(OnLockChange, &w.lockEv) + return nil + }) + doc.Call("addEventListener", "pointerlockchange", w.mouseLock) + // Set up key down callback to dispatch event w.keyDown = js.FuncOf(func(this js.Value, args []js.Value) interface{} { event := args[0] @@ -435,8 +444,14 @@ func Init(canvasId string) error { // Set up mouse move callback to dispatch event w.mouseMove = js.FuncOf(func(this js.Value, args []js.Value) interface{} { event := args[0] - w.cursorEv.Xpos = float32(event.Get("offsetX").Float()) //* float32(w.scaleX) TODO - w.cursorEv.Ypos = float32(event.Get("offsetY").Float()) //* float32(w.scaleY) + if w.lockEv.Locked { + w.cursorEv.Xpos += float32(event.Get("movementX").Float()) + w.cursorEv.Ypos += float32(event.Get("movementY").Float()) + } else { + w.cursorEv.Xpos = float32(event.Get("offsetX").Float()) //* float32(w.scaleX) TODO + w.cursorEv.Ypos = float32(event.Get("offsetY").Float()) //* float32(w.scaleY) + } + w.cursorEv.Mods = getModifiers(event) w.Dispatch(OnCursor, &w.cursorEv) return nil @@ -556,6 +571,7 @@ func (w *WebGlCanvas) Destroy() { js.Global().Get("window").Call("removeEventListener", "resize", w.winResize) js.Global().Get("window").Call("removeEventListener", "onfocus", w.winFocus) js.Global().Get("window").Call("removeEventListener", "onfocus", w.winBlur) + js.Global().Get("document").Call("removeEventListener", "pointerlockchange", w.mouseLock) // Release callbacks w.onCtxMenu.Release() @@ -568,6 +584,7 @@ func (w *WebGlCanvas) Destroy() { w.winResize.Release() w.winFocus.Release() w.winBlur.Release() + w.mouseLock.Release() } // GetFramebufferSize returns the framebuffer size. @@ -610,6 +627,28 @@ func (w *WebGlCanvas) SetCursor(cursor Cursor) { // TODO } +// SetCursorMode sets the window's cursor mode. +// More info: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API +func (w *WebGlCanvas) SetCursorMode(mode CursorMode) { + switch mode { + case CursorNormal: + js.Global().Get("document").Call("exitPointerLock") + case CursorHidden: + case CursorDisabled: + promise := w.Canvas().Call("requestPointerLock", map[string]interface{}{"unadjustedMovement": true}) + if promise.IsUndefined() { + w.Canvas().Call("requestPointerLock") + } else { + promise.Call("catch", js.FuncOf(func(this js.Value, args []js.Value) interface{} { + if len(args) > 0 && args[0].Get("name").Equal(js.ValueOf("NotSupportedError")) { + w.Canvas().Call("requestPointerLock") + } + return nil + })) + } + } +} + // DisposeAllCursors deletes all existing custom cursors. func (w *WebGlCanvas) DisposeAllCustomCursors() { diff --git a/window/glfw.go b/window/glfw.go index 9910b6d4..c97ccf7c 100644 --- a/window/glfw.go +++ b/window/glfw.go @@ -207,6 +207,7 @@ type GlfwWindow struct { cursorEv CursorEvent scrollEv ScrollEvent focusEv FocusEvent + lockEv LockEvent mods ModifierKey // Current modifier keys @@ -458,6 +459,13 @@ func (w *GlfwWindow) SetCursor(cursor Cursor) { w.Window.SetCursor(cur) } +// SetCursorMode sets the window's cursor mode. +func (w *GlfwWindow) SetCursorMode(mode CursorMode) { + w.Window.SetInputMode(glfw.CursorMode, int(mode)) + w.lockEv.Locked = mode == CursorDisabled + w.Dispatch(OnLockChange, &w.lockEv) +} + // CreateCursor creates a new custom cursor and returns an int handle. func (w *GlfwWindow) CreateCursor(imgFile string, xhot, yhot int) (Cursor, error) { diff --git a/window/window.go b/window/window.go index 14849d7c..55e349f3 100644 --- a/window/window.go +++ b/window/window.go @@ -38,6 +38,7 @@ type IWindow interface { GetScale() (x float64, y float64) CreateCursor(imgFile string, xhot, yhot int) (Cursor, error) SetCursor(cursor Cursor) + SetCursorMode(mode CursorMode) DisposeAllCustomCursors() Destroy() FullScreen() bool @@ -88,6 +89,7 @@ const ( // Desktop | Browser | OnMouseUp = "w.OnMouseUp" // x | x | OnMouseDown = "w.OnMouseDown" // x | x | OnScroll = "w.OnScroll" // x | x | + OnLockChange = "w.OnLockChange" // x | x | ) // PosEvent describes a windows position changed event @@ -136,6 +138,11 @@ type ScrollEvent struct { Mods ModifierKey } +// LockEvent describes if cursor is locked or not +type LockEvent struct { + Locked bool +} + // FocusEvent describes a focus event type FocusEvent struct { Focused bool