Skip to content

Commit

Permalink
Merge pull request #82 from bhperry/input-handler
Browse files Browse the repository at this point in the history
Move input state out of backend into pixel core
  • Loading branch information
duysqubix committed Nov 2, 2023
2 parents d734fae + 2305ab0 commit 2298e16
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 69 deletions.
87 changes: 30 additions & 57 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.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.
Expand All @@ -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{
Expand Down Expand Up @@ -215,39 +217,21 @@ 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)
}
}
})

w.window.SetKeyCallback(func(_ *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
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)
}
}
})

Expand All @@ -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)
})
})
}
Expand Down Expand Up @@ -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()
}
14 changes: 2 additions & 12 deletions backends/opengl/window.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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} {
Expand Down
125 changes: 125 additions & 0 deletions input.go
Original file line number Diff line number Diff line change
@@ -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.
Expand Down

0 comments on commit 2298e16

Please sign in to comment.