package ui import ( "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/inpututil" "muhq.space/muhqs-game/go/log" ) // InputType distinguishes the different supported kinds of input. type InputType int const ( // Click represents a mouse click. Click InputType = iota + 1 // Scroll represents a mouse wheel event. Scroll // Text represents any keyboard input. Text // Tap represents a short touch input. Tap // Pan represents a longer moving touch input. Pan // Pinch represents a moving multi touch input. Pinch // HoverStart represents the start of a hover input. HoverStart // HoverEnd represents the end of a hover input. HoverEnd // Longtap represents a longer touch input. Longtap ) func (it InputType) String() string { switch it { case Click: return "Click" case Scroll: return "Scroll" case Text: return "Text" case Tap: return "Tap" case Pan: return "Pan" case Pinch: return "Pinch" case HoverStart: return "HoverStart" case HoverEnd: return "HoverEnd" case Longtap: return "Longtap" } log.Panic("unexausted InputType switch") return "" } // InputEvent contains all information associated with an occurred user input. type InputEvent struct { Kind InputType // X and Y coordinates the event occured. X, Y int // Ctx contains additional information for the event. Ctx any } // ClickCtx contains the pressed mouse button. type ClickCtx struct { Btn ebiten.MouseButton } // DistanceCtx contains the input's distance. // Scroll and Pan events contain a DistanceCtx. type DistanceCtx struct { scrollX, scrollY int } // TextCtx contains the inputted runes. type TextCtx struct { in []rune } // Input contains all occurred input events since the last call to ui.Update. // The input events should be handled in reverse order to prevent modify during iteration errors. var Input []InputEvent // ConsumeInput removes the i-ths input from the quehe. func ConsumeInput(i int) { if len(Input) == 1 { Input = []InputEvent{} } else { Input[i] = Input[len(Input)-1] } } // AppendInput appends an input event to the input queue. func AppendInput(ev InputEvent) { log.Debug("append input event", "event", ev) Input = append(Input, ev) } // Update all ui singletons and collect all occurred input. func Update() error { Input = []InputEvent{} if err := TouchManager.Update(); err != nil { return err } var hoverEv InputEvent var hoverChange bool if len(TouchManager.taps) > 0 || TouchManager.pan != nil || TouchManager.pinch != nil { hoverEv, hoverChange = longtapHoverDetector.reset() if hoverChange { AppendInput(hoverEv) } } for _, tap := range TouchManager.taps { AppendInput(InputEvent{Tap, tap.x, tap.y, nil}) } if TouchManager.pan != nil { pan := TouchManager.pan iX, iY := pan.Incremental() AppendInput(InputEvent{Pan, pan.originX, pan.originY, DistanceCtx{int(iX) / 10, int(iY) / 10}}) } hoverEv, hoverChange = longtapHoverDetector.update(TouchManager.longtap) if hoverChange { AppendInput(hoverEv) } // TODO: handle pinching if TouchManager.pinch != nil { } x, y := ebiten.CursorPosition() hoverEv, hoverChange = hoverDetector.update(x, y) if hoverChange { AppendInput(hoverEv) } scrollX, scrollY := ebiten.Wheel() if scrollX != 0 || scrollY != 0 { AppendInput(InputEvent{Scroll, x, y, DistanceCtx{int(scrollX), int(scrollY)}}) } var in []rune in = ebiten.AppendInputChars(in) if len(in) > 0 { AppendInput(InputEvent{Text, x, y, TextCtx{in}}) } if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) { AppendInput(InputEvent{Click, x, y, ClickCtx{ebiten.MouseButtonLeft}}) } return nil }