Skip to content

Commit

Permalink
Merge pull request #86 from bhperry/bhpery/input-handler-internal
Browse files Browse the repository at this point in the history
Input handler internal
  • Loading branch information
bhperry authored Jun 15, 2024
2 parents 38b1455 + 03e89b6 commit c3b45d9
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 182 deletions.
78 changes: 78 additions & 0 deletions backends/internal/input_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package internal

import "github.com/gopxl/pixel/v2"

type InputState struct {
Mouse pixel.Vec
Buttons [pixel.NumButtons]bool
Repeat [pixel.NumButtons]bool
Scroll pixel.Vec
Typed string
}

type InputHandler struct {
Prev, Curr, temp InputState

PressEvents, tempPressEvents [pixel.NumButtons]bool
ReleaseEvents, tempReleaseEvents [pixel.NumButtons]bool

MouseInsideWindow bool
}

// SetMousePosition overrides the mouse position
// Called when the mouse is set to a point in the backend Window
func (ih *InputHandler) SetMousePosition(pos pixel.Vec) {
ih.Prev.Mouse = pos
ih.Curr.Mouse = pos
ih.temp.Mouse = pos
}

// ButtonEvent sets the action state of a button for the next update
func (ih *InputHandler) ButtonEvent(button pixel.Button, action pixel.Action) {
switch action {
case pixel.Press:
ih.tempPressEvents[button] = true
ih.temp.Buttons[button] = true
case pixel.Release:
ih.tempReleaseEvents[button] = true
ih.temp.Buttons[button] = false
case pixel.Repeat:
ih.temp.Repeat[button] = true
}
}

// MouseMoveEvent sets the mouse position for the next update
func (ih *InputHandler) MouseMoveEvent(pos pixel.Vec) {
ih.temp.Mouse = pos
}

// MouseScrollEvent adds to the scroll offset for the next update
func (ih *InputHandler) MouseScrollEvent(x, y float64) {
ih.temp.Scroll.X += x
ih.temp.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.temp.Typed += string(r)
}

func (ih *InputHandler) Update() {
ih.Prev = ih.Curr
ih.Curr = ih.temp

ih.PressEvents = ih.tempPressEvents
ih.ReleaseEvents = ih.tempReleaseEvents

// Clear last frame's temporary status
ih.tempPressEvents = [pixel.NumButtons]bool{}
ih.tempReleaseEvents = [pixel.NumButtons]bool{}
ih.temp.Repeat = [pixel.NumButtons]bool{}
ih.temp.Scroll = pixel.ZV
ih.temp.Typed = ""
}
28 changes: 28 additions & 0 deletions backends/internal/joystick_state.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package internal

import "github.com/gopxl/pixel/v2"

type JoystickState struct {
Connected [pixel.NumJoysticks]bool
Name [pixel.NumJoysticks]string
Buttons [pixel.NumJoysticks][]pixel.Action
Axis [pixel.NumJoysticks][]float32
}

// Returns if a button on a joystick is down, returning false if the button or joystick is invalid.
func (js *JoystickState) GetButton(joystick pixel.Joystick, button pixel.GamepadButton) bool {
// Check that the joystick and button is valid, return false by default
if js.Buttons[joystick] == nil || int(button) >= len(js.Buttons[joystick]) || button < 0 {
return false
}
return js.Buttons[joystick][button] == pixel.Press
}

// Returns the value of a joystick axis, returning 0 if the button or joystick is invalid.
func (js *JoystickState) GetAxis(joystick pixel.Joystick, axis pixel.GamepadAxis) float64 {
// Check that the joystick and axis is valid, return 0 by default.
if js.Axis[joystick] == nil || int(axis) >= len(js.Axis[joystick]) || axis < 0 {
return 0
}
return float64(js.Axis[joystick][axis])
}
20 changes: 10 additions & 10 deletions backends/opengl/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,34 @@ import (

// Pressed returns whether the Button is currently pressed down.
func (w *Window) Pressed(button pixel.Button) bool {
return w.input.Pressed(button)
return w.input.Curr.Buttons[button]
}

// JustPressed returns whether the Button has been pressed in the last frame.
func (w *Window) JustPressed(button pixel.Button) bool {
return w.input.JustPressed(button)
return w.input.PressEvents[button]
}

// JustReleased returns whether the Button has been released in the last frame.
func (w *Window) JustReleased(button pixel.Button) bool {
return w.input.JustReleased(button)
return w.input.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 (w *Window) Repeated(button pixel.Button) bool {
return w.input.Repeated(button)
return w.input.Curr.Repeat[button]
}

// MousePosition returns the current mouse position in the Window's Bounds.
func (w *Window) MousePosition() pixel.Vec {
return w.input.MousePosition()
return w.input.Curr.Mouse
}

// MousePreviousPosition returns the previous mouse position in the Window's Bounds.
func (w *Window) MousePreviousPosition() pixel.Vec {
return w.input.MousePreviousPosition()
return w.input.Prev.Mouse
}

// SetMousePosition positions the mouse cursor anywhere within the Window's Bounds.
Expand All @@ -56,21 +56,21 @@ func (w *Window) SetMousePosition(v pixel.Vec) {

// MouseInsideWindow returns true if the mouse position is within the Window's Bounds.
func (w *Window) MouseInsideWindow() bool {
return w.input.MouseInsideWindow()
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.input.MouseScroll()
return w.input.Curr.Mouse
}

func (w *Window) MousePreviousScroll() pixel.Vec {
return w.input.MousePreviousScroll()
return w.input.Prev.Mouse
}

// Typed returns the text typed on the keyboard since the last call to Window.Update.
func (w *Window) Typed() string {
return w.input.Typed()
return w.input.Curr.Typed
}

var actionMapping = map[glfw.Action]pixel.Action{
Expand Down
63 changes: 19 additions & 44 deletions backends/opengl/joystick.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,61 +56,61 @@ var gamepadButtonMapping = map[glfw.GamepadButton]pixel.GamepadButton{
//
// This API is experimental.
func (w *Window) JoystickPresent(js pixel.Joystick) bool {
return w.currJoy.connected[js]
return w.currJoy.Connected[js]
}

// JoystickName returns the name of the joystick. A disconnected joystick will return an
// empty string.
//
// This API is experimental.
func (w *Window) JoystickName(js pixel.Joystick) string {
return w.currJoy.name[js]
return w.currJoy.Name[js]
}

// JoystickButtonCount returns the number of buttons a connected joystick has.
//
// This API is experimental.
func (w *Window) JoystickButtonCount(js pixel.Joystick) int {
return len(w.currJoy.buttons[js])
return len(w.currJoy.Buttons[js])
}

// JoystickAxisCount returns the number of axes a connected joystick has.
//
// This API is experimental.
func (w *Window) JoystickAxisCount(js pixel.Joystick) int {
return len(w.currJoy.axis[js])
return len(w.currJoy.Axis[js])
}

// JoystickPressed returns whether the joystick Button is currently pressed down.
// If the button index is out of range, this will return false.
//
// This API is experimental.
func (w *Window) JoystickPressed(js pixel.Joystick, button pixel.GamepadButton) bool {
return w.currJoy.getButton(js, int(button))
return w.currJoy.GetButton(js, button)
}

// JoystickJustPressed returns whether the joystick Button has just been pressed down.
// If the button index is out of range, this will return false.
//
// This API is experimental.
func (w *Window) JoystickJustPressed(js pixel.Joystick, button pixel.GamepadButton) bool {
return w.currJoy.getButton(js, int(button)) && !w.prevJoy.getButton(js, int(button))
return w.currJoy.GetButton(js, button) && !w.prevJoy.GetButton(js, button)
}

// JoystickJustReleased returns whether the joystick Button has just been released up.
// If the button index is out of range, this will return false.
//
// This API is experimental.
func (w *Window) JoystickJustReleased(js pixel.Joystick, button pixel.GamepadButton) bool {
return !w.currJoy.getButton(js, int(button)) && w.prevJoy.getButton(js, int(button))
return !w.currJoy.GetButton(js, button) && w.prevJoy.GetButton(js, button)
}

// JoystickAxis returns the value of a joystick axis at the last call to Window.Update.
// If the axis index is out of range, this will return 0.
//
// This API is experimental.
func (w *Window) JoystickAxis(js pixel.Joystick, axis pixel.GamepadAxis) float64 {
return w.currJoy.getAxis(js, int(axis))
return w.currJoy.GetAxis(js, axis)
}

// Used internally during Window.UpdateInput to update the state of the joysticks.
Expand All @@ -122,62 +122,37 @@ func (w *Window) updateJoystickInput() {
}
// Determine and store if the joystick was connected
joystickPresent := joystick.Present()
w.tempJoy.connected[js] = joystickPresent
w.tempJoy.Connected[js] = joystickPresent

if joystickPresent {
if joystick.IsGamepad() {
gamepadInputs := joystick.GetGamepadState()

w.tempJoy.buttons[js] = convertGamepadButtons(gamepadInputs.Buttons)
w.tempJoy.axis[js] = gamepadInputs.Axes[:]
w.tempJoy.Buttons[js] = convertGamepadButtons(gamepadInputs.Buttons)
w.tempJoy.Axis[js] = gamepadInputs.Axes[:]
} else {
w.tempJoy.buttons[js] = convertJoystickButtons(joystick.GetButtons())
w.tempJoy.axis[js] = joystick.GetAxes()
w.tempJoy.Buttons[js] = convertJoystickButtons(joystick.GetButtons())
w.tempJoy.Axis[js] = joystick.GetAxes()
}

if !w.currJoy.connected[js] {
if !w.currJoy.Connected[js] {
// The joystick was recently connected, we get the name
w.tempJoy.name[js] = joystick.GetName()
w.tempJoy.Name[js] = joystick.GetName()
} else {
// Use the name from the previous one
w.tempJoy.name[js] = w.currJoy.name[js]
w.tempJoy.Name[js] = w.currJoy.Name[js]
}
} else {
w.tempJoy.buttons[js] = []pixel.Action{}
w.tempJoy.axis[js] = []float32{}
w.tempJoy.name[js] = ""
w.tempJoy.Buttons[js] = []pixel.Action{}
w.tempJoy.Axis[js] = []float32{}
w.tempJoy.Name[js] = ""
}
}

w.prevJoy = w.currJoy
w.currJoy = w.tempJoy
}

type joystickState struct {
connected [pixel.NumJoysticks]bool
name [pixel.NumJoysticks]string
buttons [pixel.NumJoysticks][]pixel.Action
axis [pixel.NumJoysticks][]float32
}

// Returns if a button on a joystick is down, returning false if the button or joystick is invalid.
func (js *joystickState) getButton(joystick pixel.Joystick, button int) bool {
// Check that the joystick and button is valid, return false by default
if js.buttons[joystick] == nil || button >= len(js.buttons[joystick]) || button < 0 {
return false
}
return js.buttons[joystick][byte(button)] == pixel.Press
}

// Returns the value of a joystick axis, returning 0 if the button or joystick is invalid.
func (js *joystickState) getAxis(joystick pixel.Joystick, axis int) float64 {
// Check that the joystick and axis is valid, return 0 by default.
if js.axis[joystick] == nil || axis >= len(js.axis[joystick]) || axis < 0 {
return 0
}
return float64(js.axis[joystick][axis])
}

// Convert buttons from a GLFW gamepad mapping to pixel format
func convertGamepadButtons(buttons [glfw.ButtonLast + 1]glfw.Action) []pixel.Action {
pixelButtons := make([]pixel.Action, pixel.NumGamepadButtons)
Expand Down
7 changes: 4 additions & 3 deletions backends/opengl/window.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/gopxl/glhf/v2"
"github.com/gopxl/mainthread/v2"
"github.com/gopxl/pixel/v2"
"github.com/gopxl/pixel/v2/backends/internal"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -96,8 +97,8 @@ type Window struct {
xpos, ypos, width, height int
}

input *pixel.InputHandler
prevJoy, currJoy, tempJoy joystickState
input internal.InputHandler
prevJoy, currJoy, tempJoy internal.JoystickState

buttonCallback func(win *Window, button pixel.Button, action pixel.Action)
charCallback func(win *Window, r rune)
Expand All @@ -117,7 +118,7 @@ func NewWindow(cfg WindowConfig) (*Window, error) {
false: glfw.False,
}

w := &Window{bounds: cfg.Bounds, cursorVisible: true, input: &pixel.InputHandler{}}
w := &Window{bounds: cfg.Bounds, cursorVisible: true}

flag := false
for _, v := range []int{0, 2, 4, 8, 16} {
Expand Down
Loading

0 comments on commit c3b45d9

Please sign in to comment.