diff --git a/backends/opengl/input.go b/backends/opengl/input.go index 474e5fe..fb13acf 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,28 @@ 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() +} + +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.currInp.typed + return w.input.Typed() } var actionMapping = map[glfw.Action]pixel.Action{ @@ -215,18 +217,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.ButtonEvent(b, a) + } } }) @@ -234,20 +228,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.ButtonEvent(b, a) + } } }) @@ -256,19 +240,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 +282,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..e2e4951 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] +} + +// 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 +} + +// 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 +} + +// 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.