From 3b900ad4c2f89c14c90a9634a3d20562a1f48d12 Mon Sep 17 00:00:00 2001 From: Ben Perry Date: Fri, 27 Oct 2023 17:15:16 -0500 Subject: [PATCH 1/3] Move input state out of backend into pixel core --- backends/opengl/input.go | 83 ++++++++----------------- backends/opengl/window.go | 14 +---- input.go | 125 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 69 deletions(-) diff --git a/backends/opengl/input.go b/backends/opengl/input.go index 474e5fe..c7b21cf 100644 --- a/backends/opengl/input.go +++ b/backends/opengl/input.go @@ -10,34 +10,34 @@ import ( // Pressed returns whether the Button is currently pressed down. func (w *Window) Pressed(button pixel.Button) bool { - return w.currInp.buttons[button] + return w.input.Pressed(button) } // JustPressed returns whether the Button has been pressed in the last frame. func (w *Window) JustPressed(button pixel.Button) bool { - return w.pressEvents[button] + return w.input.JustPressed(button) } // JustReleased returns whether the Button has been released in the last frame. func (w *Window) JustReleased(button pixel.Button) bool { - return w.releaseEvents[button] + return w.input.JustReleased(button) } // Repeated returns whether a repeat event has been triggered on button. // // Repeat event occurs repeatedly when a button is held down for some time. func (w *Window) Repeated(button pixel.Button) bool { - return w.currInp.repeat[button] + return w.input.Repeated(button) } // MousePosition returns the current mouse position in the Window's Bounds. func (w *Window) MousePosition() pixel.Vec { - return w.currInp.mouse + return w.input.MousePosition() } // MousePreviousPosition returns the previous mouse position in the Window's Bounds. func (w *Window) MousePreviousPosition() pixel.Vec { - return w.prevInp.mouse + return w.input.MousePreviousPosition() } // SetMousePosition positions the mouse cursor anywhere within the Window's Bounds. @@ -49,26 +49,24 @@ func (w *Window) SetMousePosition(v pixel.Vec) { v.X+w.bounds.Min.X, (w.bounds.H()-v.Y)+w.bounds.Min.Y, ) - w.prevInp.mouse = v - w.currInp.mouse = v - w.tempInp.mouse = v + w.input.SetMousePosition(v) } }) } // MouseInsideWindow returns true if the mouse position is within the Window's Bounds. func (w *Window) MouseInsideWindow() bool { - return w.cursorInsideWindow + return w.input.MouseInsideWindow() } // MouseScroll returns the mouse scroll amount (in both axes) since the last call to Window.Update. func (w *Window) MouseScroll() pixel.Vec { - return w.currInp.scroll + return w.input.MouseScroll() } // Typed returns the text typed on the keyboard since the last call to Window.Update. func (w *Window) Typed() string { - return w.currInp.typed + return w.input.Typed() } var actionMapping = map[glfw.Action]pixel.Action{ @@ -215,18 +213,10 @@ var keyButtonMapping = map[glfw.Key]pixel.Button{ func (w *Window) initInput() { mainthread.Call(func() { w.window.SetMouseButtonCallback(func(_ *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) { - mb, ok := mouseButtonMapping[button] - if !ok { - return - } - - switch action { - case glfw.Press: - w.tempPressEvents[mb] = true - w.tempInp.buttons[mb] = true - case glfw.Release: - w.tempReleaseEvents[mb] = true - w.tempInp.buttons[mb] = false + if b, buttonOk := mouseButtonMapping[button]; buttonOk { + if a, actionOk := actionMapping[action]; actionOk { + w.input.SetButton(b, a) + } } }) @@ -234,20 +224,10 @@ func (w *Window) initInput() { if key == glfw.KeyUnknown { return } - kb, ok := keyButtonMapping[key] - if !ok { - return - } - - switch action { - case glfw.Press: - w.tempPressEvents[kb] = true - w.tempInp.buttons[kb] = true - case glfw.Release: - w.tempReleaseEvents[kb] = true - w.tempInp.buttons[kb] = false - case glfw.Repeat: - w.tempInp.repeat[kb] = true + if b, buttonOk := keyButtonMapping[key]; buttonOk { + if a, actionOk := actionMapping[action]; actionOk { + w.input.SetButton(b, a) + } } }) @@ -256,19 +236,20 @@ func (w *Window) initInput() { }) w.window.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) { - w.tempInp.mouse = pixel.V( - x+w.bounds.Min.X, - (w.bounds.H()-y)+w.bounds.Min.Y, + w.input.MouseMoveEvent( + pixel.V( + x+w.bounds.Min.X, + (w.bounds.H()-y)+w.bounds.Min.Y, + ), ) }) w.window.SetScrollCallback(func(_ *glfw.Window, xoff, yoff float64) { - w.tempInp.scroll.X += xoff - w.tempInp.scroll.Y += yoff + w.input.MouseScrollEvent(xoff, yoff) }) w.window.SetCharCallback(func(_ *glfw.Window, r rune) { - w.tempInp.typed += string(r) + w.input.CharEvent(r) }) }) } @@ -297,18 +278,6 @@ func (w *Window) UpdateInputWait(timeout time.Duration) { // internal input bookkeeping func (w *Window) doUpdateInput() { - w.prevInp = w.currInp - w.currInp = w.tempInp - - w.pressEvents = w.tempPressEvents - w.releaseEvents = w.tempReleaseEvents - - // Clear last frame's temporary status - w.tempPressEvents = [pixel.NumButtons]bool{} - w.tempReleaseEvents = [pixel.NumButtons]bool{} - w.tempInp.repeat = [pixel.NumButtons]bool{} - w.tempInp.scroll = pixel.ZV - w.tempInp.typed = "" - + w.input.Update() w.updateJoystickInput() } diff --git a/backends/opengl/window.go b/backends/opengl/window.go index 4739e8b..00deaa2 100644 --- a/backends/opengl/window.go +++ b/backends/opengl/window.go @@ -97,17 +97,7 @@ type Window struct { xpos, ypos, width, height int } - prevInp, currInp, tempInp struct { - mouse pixel.Vec - buttons [pixel.NumButtons]bool - repeat [pixel.NumButtons]bool - scroll pixel.Vec - typed string - } - - pressEvents, tempPressEvents [pixel.NumButtons]bool - releaseEvents, tempReleaseEvents [pixel.NumButtons]bool - + input *pixel.InputHandler prevJoy, currJoy, tempJoy joystickState } @@ -122,7 +112,7 @@ func NewWindow(cfg WindowConfig) (*Window, error) { false: glfw.False, } - w := &Window{bounds: cfg.Bounds, cursorVisible: true} + w := &Window{bounds: cfg.Bounds, cursorVisible: true, input: &pixel.InputHandler{}} flag := false for _, v := range []int{0, 2, 4, 8, 16} { diff --git a/input.go b/input.go index 1f0cff6..ba4a6f4 100644 --- a/input.go +++ b/input.go @@ -1,5 +1,130 @@ package pixel +type InputHandler struct { + prevInp, currInp, tempInp struct { + mouse Vec + buttons [NumButtons]bool + repeat [NumButtons]bool + scroll Vec + typed string + } + + pressEvents, tempPressEvents [NumButtons]bool + releaseEvents, tempReleaseEvents [NumButtons]bool + + mouseInsideWindow bool +} + +// Pressed returns whether the Button is currently pressed down. +func (ih *InputHandler) Pressed(button Button) bool { + return ih.currInp.buttons[button] +} + +// JustPressed returns whether the Button has been pressed in the last frame. +func (ih *InputHandler) JustPressed(button Button) bool { + return ih.pressEvents[button] +} + +// JustReleased returns whether the Button has been released in the last frame. +func (ih *InputHandler) JustReleased(button Button) bool { + return ih.releaseEvents[button] +} + +// Repeated returns whether a repeat event has been triggered on button. +// +// Repeat event occurs repeatedly when a button is held down for some time. +func (ih *InputHandler) Repeated(button Button) bool { + return ih.currInp.repeat[button] +} + +// SetButton sets the action state of a button for the next update +func (ih *InputHandler) SetButton(button Button, action Action) { + switch action { + case Press: + ih.tempPressEvents[button] = true + ih.tempInp.buttons[button] = true + case Release: + ih.tempReleaseEvents[button] = true + ih.tempInp.buttons[button] = false + case Repeat: + ih.tempInp.repeat[button] = true + } +} + +// MousePosition returns the current mouse position in the Window's Bounds +func (ih *InputHandler) MousePosition() Vec { + return ih.currInp.mouse +} + +// MousePreviousPosition returns the previous mouse position in the Window's Bounds +func (ih *InputHandler) MousePreviousPosition() Vec { + return ih.prevInp.mouse +} + +// MouseScroll returns the mouse scroll amount (in both axes) since the last update +func (ih *InputHandler) MouseScroll() Vec { + return ih.currInp.scroll +} + +// MousePreviousScroll returns the previous mouse scroll amount (in both axes) +func (ih *InputHandler) MousePreviousScroll() Vec { + return ih.prevInp.scroll +} + +// MouseInsideWindow returns true if the mouse position is within the Window's Bounds +func (ih *InputHandler) MouseInsideWindow() bool { + return ih.mouseInsideWindow +} + +// Typed returns the text typed on the keyboard since the last update +func (ih *InputHandler) Typed() string { + return ih.currInp.typed +} + +// SetMousePosition overrides the mouse position +// Called when the mouse is set to a point in the backend Window +func (ih *InputHandler) SetMousePosition(pos Vec) { + ih.prevInp.mouse = pos + ih.currInp.mouse = pos + ih.tempInp.mouse = pos +} + +// MouseMoveEvent sets the mouse position for the next update +func (ih *InputHandler) MouseMoveEvent(pos Vec) { + ih.tempInp.mouse = pos +} + +// MouseScrollEvent adds to the scroll offset for the next update +func (ih *InputHandler) MouseScrollEvent(x, y float64) { + ih.tempInp.scroll.X += x + ih.tempInp.scroll.Y += y +} + +// MouseEnteredEvent is called when the mouse enters or leaves the window +func (ih *InputHandler) MouseEnteredEvent(entered bool) { + ih.mouseInsideWindow = entered +} + +// CharEvent adds to the typed string for the next update +func (ih *InputHandler) CharEvent(r rune) { + ih.tempInp.typed += string(r) +} + +func (ih *InputHandler) Update() { + ih.prevInp = ih.currInp + ih.currInp = ih.tempInp + + ih.pressEvents = ih.tempPressEvents + ih.releaseEvents = ih.tempReleaseEvents + + // Clear last frame's temporary status + ih.tempPressEvents = [NumButtons]bool{} + ih.tempReleaseEvents = [NumButtons]bool{} + ih.tempInp.repeat = [NumButtons]bool{} + ih.tempInp.scroll = ZV + ih.tempInp.typed = "" +} + type Action int // String returns a human-readable string describing the Button. From 5cbefff46fce27ec5b7f58f33b27af7ab5286aa8 Mon Sep 17 00:00:00 2001 From: Ben Perry Date: Fri, 27 Oct 2023 17:59:40 -0500 Subject: [PATCH 2/3] expose mouse previous position --- backends/opengl/input.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backends/opengl/input.go b/backends/opengl/input.go index c7b21cf..9f1d324 100644 --- a/backends/opengl/input.go +++ b/backends/opengl/input.go @@ -64,6 +64,10 @@ func (w *Window) MouseScroll() pixel.Vec { return w.input.MouseScroll() } +func (w *Window) MousePreviousScroll() pixel.Vec { + return w.input.MousePreviousScroll() +} + // Typed returns the text typed on the keyboard since the last call to Window.Update. func (w *Window) Typed() string { return w.input.Typed() From 2305ab0511f9dc64fff6d2045cf4bbc821cbaa6a Mon Sep 17 00:00:00 2001 From: Ben Perry Date: Fri, 27 Oct 2023 21:40:40 -0500 Subject: [PATCH 3/3] naming consistency --- backends/opengl/input.go | 4 ++-- input.go | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/backends/opengl/input.go b/backends/opengl/input.go index 9f1d324..fb13acf 100644 --- a/backends/opengl/input.go +++ b/backends/opengl/input.go @@ -219,7 +219,7 @@ func (w *Window) initInput() { w.window.SetMouseButtonCallback(func(_ *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) { if b, buttonOk := mouseButtonMapping[button]; buttonOk { if a, actionOk := actionMapping[action]; actionOk { - w.input.SetButton(b, a) + w.input.ButtonEvent(b, a) } } }) @@ -230,7 +230,7 @@ func (w *Window) initInput() { } if b, buttonOk := keyButtonMapping[key]; buttonOk { if a, actionOk := actionMapping[action]; actionOk { - w.input.SetButton(b, a) + w.input.ButtonEvent(b, a) } } }) diff --git a/input.go b/input.go index ba4a6f4..e2e4951 100644 --- a/input.go +++ b/input.go @@ -37,20 +37,6 @@ func (ih *InputHandler) Repeated(button Button) bool { return ih.currInp.repeat[button] } -// SetButton sets the action state of a button for the next update -func (ih *InputHandler) SetButton(button Button, action Action) { - switch action { - case Press: - ih.tempPressEvents[button] = true - ih.tempInp.buttons[button] = true - case Release: - ih.tempReleaseEvents[button] = true - ih.tempInp.buttons[button] = false - case Repeat: - ih.tempInp.repeat[button] = true - } -} - // MousePosition returns the current mouse position in the Window's Bounds func (ih *InputHandler) MousePosition() Vec { return ih.currInp.mouse @@ -89,6 +75,20 @@ func (ih *InputHandler) SetMousePosition(pos Vec) { ih.tempInp.mouse = pos } +// ButtonEvent sets the action state of a button for the next update +func (ih *InputHandler) ButtonEvent(button Button, action Action) { + switch action { + case Press: + ih.tempPressEvents[button] = true + ih.tempInp.buttons[button] = true + case Release: + ih.tempReleaseEvents[button] = true + ih.tempInp.buttons[button] = false + case Repeat: + ih.tempInp.repeat[button] = true + } +} + // MouseMoveEvent sets the mouse position for the next update func (ih *InputHandler) MouseMoveEvent(pos Vec) { ih.tempInp.mouse = pos