OpenDiablo2/d2core/d2input/input_manager.go

295 lines
6.8 KiB
Go

package d2input
import (
"sort"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
ebiten_input "github.com/OpenDiablo2/OpenDiablo2/d2core/d2input/ebiten"
)
type inputManager struct {
inputService d2interface.InputService
cursorX int
cursorY int
buttonMod d2enum.MouseButtonMod
keyMod d2enum.KeyMod
entries handlerEntryList
}
// NewInputManager returns a new input manager instance
func NewInputManager() d2interface.InputManager {
return &inputManager{
inputService: ebiten_input.InputService{},
}
}
// Advance advances the inputManager
func (im *inputManager) Advance(_, _ float64) error {
im.updateKeyMod()
im.updateButtonMod()
cursorX, cursorY := im.inputService.CursorPosition()
eventBase := HandlerEvent{
im.keyMod,
im.buttonMod,
cursorX,
cursorY,
}
for key := d2enum.KeyMin; key <= d2enum.KeyMax; key++ {
im.updateJustPressedKey(key, eventBase)
im.updateJustReleasedKey(key, eventBase)
im.updatePressedKey(key, eventBase)
}
im.updateInputChars(eventBase)
for button := d2enum.MouseButtonMin; button <= d2enum.MouseButtonMax; button++ {
im.updateJustPressedButton(button, eventBase)
im.updateJustReleasedButton(button, eventBase)
im.updatePressedButton(button, eventBase)
}
im.updateCursor(cursorX, cursorY, eventBase)
return nil
}
func (im *inputManager) updateKeyMod() {
im.keyMod = 0
if im.inputService.IsKeyPressed(d2enum.KeyAlt) {
im.keyMod |= d2enum.KeyModAlt
}
if im.inputService.IsKeyPressed(d2enum.KeyControl) {
im.keyMod |= d2enum.KeyModControl
}
if im.inputService.IsKeyPressed(d2enum.KeyShift) {
im.keyMod |= d2enum.KeyModShift
}
}
func (im *inputManager) updateButtonMod() {
im.buttonMod = 0
if im.inputService.IsMouseButtonPressed(d2enum.MouseButtonLeft) {
im.buttonMod |= d2enum.MouseButtonModLeft
}
if im.inputService.IsMouseButtonPressed(d2enum.MouseButtonMiddle) {
im.buttonMod |= d2enum.MouseButtonModMiddle
}
if im.inputService.IsMouseButtonPressed(d2enum.MouseButtonRight) {
im.buttonMod |= d2enum.MouseButtonModRight
}
}
func (im *inputManager) updateJustPressedKey(k d2enum.Key, e HandlerEvent) {
if im.inputService.IsKeyJustPressed(k) {
event := KeyEvent{HandlerEvent: e, key: k}
fn := func(handler d2interface.InputEventHandler) bool {
if l, ok := handler.(d2interface.KeyDownHandler); ok {
return l.OnKeyDown(&event)
}
return false
}
im.propagate(fn)
}
}
func (im *inputManager) updateJustReleasedKey(k d2enum.Key, e HandlerEvent) {
if im.inputService.IsKeyJustReleased(k) {
event := KeyEvent{HandlerEvent: e, key: k}
fn := func(handler d2interface.InputEventHandler) bool {
if l, ok := handler.(d2interface.KeyUpHandler); ok {
return l.OnKeyUp(&event)
}
return false
}
im.propagate(fn)
}
}
func (im *inputManager) updatePressedKey(k d2enum.Key, e HandlerEvent) {
if im.inputService.IsKeyPressed(k) {
event := KeyEvent{
HandlerEvent: e,
key: k,
duration: im.inputService.KeyPressDuration(k),
}
fn := func(handler d2interface.InputEventHandler) bool {
if l, ok := handler.(d2interface.KeyRepeatHandler); ok {
return l.OnKeyRepeat(&event)
}
return false
}
im.propagate(fn)
}
}
func (im *inputManager) updateInputChars(eventBase HandlerEvent) {
if chars := im.inputService.InputChars(); len(chars) > 0 {
event := KeyCharsEvent{eventBase, chars}
fn := func(handler d2interface.InputEventHandler) bool {
if l, ok := handler.(d2interface.KeyCharsHandler); ok {
l.OnKeyChars(&event)
}
return false
}
im.propagate(fn)
}
}
func (im *inputManager) updateJustPressedButton(b d2enum.MouseButton, e HandlerEvent) {
if im.inputService.IsMouseButtonJustPressed(b) {
event := MouseEvent{e, b}
fn := func(handler d2interface.InputEventHandler) bool {
if l, ok := handler.(d2interface.MouseButtonDownHandler); ok {
return l.OnMouseButtonDown(&event)
}
return false
}
im.propagate(fn)
}
}
func (im *inputManager) updateJustReleasedButton(b d2enum.MouseButton, e HandlerEvent) {
if im.inputService.IsMouseButtonJustReleased(b) {
event := MouseEvent{e, b}
fn := func(handler d2interface.InputEventHandler) bool {
if l, ok := handler.(d2interface.MouseButtonUpHandler); ok {
return l.OnMouseButtonUp(&event)
}
return false
}
im.propagate(fn)
}
}
func (im *inputManager) updatePressedButton(b d2enum.MouseButton, e HandlerEvent) {
if im.inputService.IsMouseButtonPressed(b) {
event := MouseEvent{e, b}
fn := func(handler d2interface.InputEventHandler) bool {
if l, ok := handler.(d2interface.MouseButtonRepeatHandler); ok {
return l.OnMouseButtonRepeat(&event)
}
return false
}
im.propagate(fn)
}
}
func (im *inputManager) updateCursor(cursorX, cursorY int, e HandlerEvent) {
if im.cursorX != cursorX || im.cursorY != cursorY {
event := MouseMoveEvent{e}
fn := func(handler d2interface.InputEventHandler) bool {
if l, ok := handler.(d2interface.MouseMoveHandler); ok {
return l.OnMouseMove(&event)
}
return false
}
im.propagate(fn)
im.cursorX, im.cursorY = cursorX, cursorY
}
}
// BindHandlerWithPriority adds an event handler with a specific call priority
func (im *inputManager) BindHandlerWithPriority(
h d2interface.InputEventHandler,
p d2enum.Priority) error {
return im.bindHandler(h, p)
}
// BindHandler adds an event handler
func (im *inputManager) BindHandler(h d2interface.InputEventHandler) error {
return im.bindHandler(h, d2enum.PriorityDefault)
}
// BindHandler adds an event handler
func (im *inputManager) bindHandler(h d2interface.InputEventHandler, p d2enum.Priority) error {
for _, entry := range im.entries {
if entry.handler == h {
return ErrHasReg
}
}
entry := handlerEntry{h, p}
im.entries = append(im.entries, entry)
sort.Sort(im.entries)
return nil
}
// UnbindHandler removes a previously bound event handler
func (im *inputManager) UnbindHandler(handler d2interface.InputEventHandler) error {
for i, entry := range im.entries {
if entry.handler == handler {
copy(im.entries[i:], im.entries[i+1:])
im.entries = im.entries[:len(im.entries)-1]
return nil
}
}
return ErrNotReg
}
func (im *inputManager) propagate(callback func(d2interface.InputEventHandler) bool) {
var priority d2enum.Priority
var handled bool
for _, entry := range im.entries {
if priority > entry.priority && handled {
break
}
if callback(entry.handler) {
handled = true
}
priority = entry.priority
}
}
type handlerEntry struct {
handler d2interface.InputEventHandler
priority d2enum.Priority
}
type handlerEntryList []handlerEntry
func (lel handlerEntryList) Len() int {
return len(lel)
}
func (lel handlerEntryList) Swap(i, j int) {
lel[i], lel[j] = lel[j], lel[i]
}
func (lel handlerEntryList) Less(i, j int) bool {
return lel[i].priority > lel[j].priority
}