Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input handler internal #86

Merged
merged 3 commits into from
Jun 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading