From b1c67c7661bfda0fb1d18d48e7fe21edb74f3e48 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 10 Oct 2020 03:36:14 +0900 Subject: [PATCH] ebiten: Introduce type TouchID Fixes #604 --- examples/2048/2048/input.go | 2 +- examples/drag/main.go | 2 +- input.go | 7 +++++-- inpututil/inpututil.go | 26 +++++++++++++----------- internal/driver/input.go | 6 ++++-- internal/uidriver/glfw/input.go | 8 ++++---- internal/uidriver/js/input_js.go | 12 +++++------ internal/uidriver/mobile/input.go | 10 ++++----- internal/uidriver/mobile/ui.go | 4 ++-- mobile/ebitenmobileview/input.go | 2 +- mobile/ebitenmobileview/input_android.go | 4 ++-- mobile/ebitenmobileview/input_ios.go | 6 ++++-- 12 files changed, 49 insertions(+), 40 deletions(-) diff --git a/examples/2048/2048/input.go b/examples/2048/2048/input.go index 9a605d1ee..5e23ab523 100644 --- a/examples/2048/2048/input.go +++ b/examples/2048/2048/input.go @@ -84,7 +84,7 @@ type Input struct { mouseDir Dir touchState touchState - touchID int + touchID ebiten.TouchID touchInitPosX int touchInitPosY int touchLastPosX int diff --git a/examples/drag/main.go b/examples/drag/main.go index 422224258..5a001e254 100644 --- a/examples/drag/main.go +++ b/examples/drag/main.go @@ -106,7 +106,7 @@ func (m *MouseStrokeSource) IsJustReleased() bool { // TouchStrokeSource is a StrokeSource implementation of touch. type TouchStrokeSource struct { - ID int + ID ebiten.TouchID } func (t *TouchStrokeSource) Position() (int, int) { diff --git a/input.go b/input.go index b66b0c314..a3ddc1c2f 100644 --- a/input.go +++ b/input.go @@ -182,6 +182,9 @@ func IsGamepadButtonPressed(id GamepadID, button GamepadButton) bool { return uiDriver().Input().IsGamepadButtonPressed(id, driver.GamepadButton(button)) } +// TouchID represents a touch's identifier. +type TouchID = driver.TouchID + // TouchIDs returns the current touch states. // // If you want to know whether a touch started being pressed in the current frame, @@ -191,7 +194,7 @@ func IsGamepadButtonPressed(id GamepadID, button GamepadButton) bool { // TouchIDs always returns nil on desktops. // // TouchIDs is concurrent-safe. -func TouchIDs() []int { +func TouchIDs() []TouchID { return uiDriver().Input().TouchIDs() } @@ -200,7 +203,7 @@ func TouchIDs() []int { // If the touch of the specified ID is not present, TouchPosition returns (0, 0). // // TouchPosition is cuncurrent-safe. -func TouchPosition(id int) (int, int) { +func TouchPosition(id TouchID) (int, int) { found := false for _, i := range uiDriver().Input().TouchIDs() { if id == i { diff --git a/inpututil/inpututil.go b/inpututil/inpututil.go index 68fa6f537..3296cbd3d 100644 --- a/inpututil/inpututil.go +++ b/inpututil/inpututil.go @@ -36,8 +36,8 @@ type inputState struct { gamepadButtonDurations map[ebiten.GamepadID][]int prevGamepadButtonDurations map[ebiten.GamepadID][]int - touchDurations map[int]int - prevTouchDurations map[int]int + touchDurations map[ebiten.TouchID]int + prevTouchDurations map[ebiten.TouchID]int m sync.RWMutex } @@ -55,8 +55,8 @@ var theInputState = &inputState{ gamepadButtonDurations: map[ebiten.GamepadID][]int{}, prevGamepadButtonDurations: map[ebiten.GamepadID][]int{}, - touchDurations: map[int]int{}, - prevTouchDurations: map[int]int{}, + touchDurations: map[ebiten.TouchID]int{}, + prevTouchDurations: map[ebiten.TouchID]int{}, } func init() { @@ -134,10 +134,10 @@ func (i *inputState) update() { } // Touches - ids := map[int]struct{}{} + ids := map[ebiten.TouchID]struct{}{} // Copy the touch durations. - i.prevTouchDurations = map[int]int{} + i.prevTouchDurations = map[ebiten.TouchID]int{} for id := range i.touchDurations { i.prevTouchDurations[id] = i.touchDurations[id] } @@ -146,7 +146,7 @@ func (i *inputState) update() { ids[id] = struct{}{} i.touchDurations[id]++ } - touchIDsToDelete := []int{} + touchIDsToDelete := []ebiten.TouchID{} for id := range i.touchDurations { if _, ok := ids[id]; !ok { touchIDsToDelete = append(touchIDsToDelete, id) @@ -292,8 +292,8 @@ func GamepadButtonPressDuration(id ebiten.GamepadID, button ebiten.GamepadButton // JustPressedTouchIDs might return nil when there is not touch. // // JustPressedTouchIDs is concurrent safe. -func JustPressedTouchIDs() []int { - var ids []int +func JustPressedTouchIDs() []ebiten.TouchID { + var ids []ebiten.TouchID theInputState.m.RLock() for id, s := range theInputState.touchDurations { if s == 1 { @@ -301,7 +301,9 @@ func JustPressedTouchIDs() []int { } } theInputState.m.RUnlock() - sort.Ints(ids) + sort.Slice(ids, func(a, b int) bool { + return ids[a] < ids[b] + }) return ids } @@ -309,7 +311,7 @@ func JustPressedTouchIDs() []int { // whether the given touch is released just in the current frame. // // IsTouchJustReleased is concurrent safe. -func IsTouchJustReleased(id int) bool { +func IsTouchJustReleased(id ebiten.TouchID) bool { theInputState.m.RLock() r := theInputState.touchDurations[id] == 0 && theInputState.prevTouchDurations[id] > 0 theInputState.m.RUnlock() @@ -319,7 +321,7 @@ func IsTouchJustReleased(id int) bool { // TouchPressDuration returns how long the touch remains in frames. // // TouchPressDuration is concurrent safe. -func TouchPressDuration(id int) int { +func TouchPressDuration(id ebiten.TouchID) int { theInputState.m.RLock() s := theInputState.touchDurations[id] theInputState.m.RUnlock() diff --git a/internal/driver/input.go b/internal/driver/input.go index a5945010c..d73c3e1eb 100644 --- a/internal/driver/input.go +++ b/internal/driver/input.go @@ -16,6 +16,8 @@ package driver type GamepadID int +type TouchID int + type Input interface { CursorPosition() (x, y int) GamepadSDLID(id GamepadID) string @@ -28,7 +30,7 @@ type Input interface { IsKeyPressed(key Key) bool IsMouseButtonPressed(button MouseButton) bool RuneBuffer() []rune - TouchIDs() []int - TouchPosition(id int) (x, y int) + TouchIDs() []TouchID + TouchPosition(id TouchID) (x, y int) Wheel() (xoff, yoff float64) } diff --git a/internal/uidriver/glfw/input.go b/internal/uidriver/glfw/input.go index ae57ed80f..3207bc2dd 100644 --- a/internal/uidriver/glfw/input.go +++ b/internal/uidriver/glfw/input.go @@ -45,7 +45,7 @@ type Input struct { cursorX int cursorY int gamepads [16]gamePad - touches map[int]pos // TODO: Implement this (#417) + touches map[driver.TouchID]pos // TODO: Implement this (#417) runeBuffer []rune ui *UserInterface } @@ -173,11 +173,11 @@ func (i *Input) IsGamepadButtonPressed(id driver.GamepadID, button driver.Gamepa return r } -func (i *Input) TouchIDs() []int { +func (i *Input) TouchIDs() []driver.TouchID { if !i.ui.isRunning() { return nil } - var ids []int + var ids []driver.TouchID _ = i.ui.t.Call(func() error { if len(i.touches) == 0 { return nil @@ -190,7 +190,7 @@ func (i *Input) TouchIDs() []int { return ids } -func (i *Input) TouchPosition(id int) (x, y int) { +func (i *Input) TouchPosition(id driver.TouchID) (x, y int) { if !i.ui.isRunning() { return 0, 0 } diff --git a/internal/uidriver/js/input_js.go b/internal/uidriver/js/input_js.go index fc041c876..23815593f 100644 --- a/internal/uidriver/js/input_js.go +++ b/internal/uidriver/js/input_js.go @@ -46,7 +46,7 @@ type Input struct { wheelX float64 wheelY float64 gamepads [16]gamePad - touches map[int]pos + touches map[driver.TouchID]pos runeBuffer []rune ui *UserInterface } @@ -118,19 +118,19 @@ func (i *Input) IsGamepadButtonPressed(id driver.GamepadID, button driver.Gamepa return i.gamepads[id].buttonPressed[button] } -func (i *Input) TouchIDs() []int { +func (i *Input) TouchIDs() []driver.TouchID { if len(i.touches) == 0 { return nil } - var ids []int + var ids []driver.TouchID for id := range i.touches { ids = append(ids, id) } return ids } -func (i *Input) TouchPosition(id int) (x, y int) { +func (i *Input) TouchPosition(id driver.TouchID) (x, y int) { for tid, pos := range i.touches { if id == tid { x, y := i.ui.context.AdjustPosition(float64(pos.X), float64(pos.Y)) @@ -346,10 +346,10 @@ func (i *Input) setMouseCursorFromEvent(e js.Value) { func (i *Input) updateTouches(e js.Value) { j := e.Get("targetTouches") - ts := map[int]pos{} + ts := map[driver.TouchID]pos{} for i := 0; i < j.Length(); i++ { jj := j.Call("item", i) - id := jj.Get("identifier").Int() + id := driver.TouchID(jj.Get("identifier").Int()) ts[id] = pos{ X: jj.Get("clientX").Int(), Y: jj.Get("clientY").Int(), diff --git a/internal/uidriver/mobile/input.go b/internal/uidriver/mobile/input.go index b2c024b6c..b6d69d84b 100644 --- a/internal/uidriver/mobile/input.go +++ b/internal/uidriver/mobile/input.go @@ -30,7 +30,7 @@ type Input struct { cursorY int keys map[driver.Key]struct{} runes []rune - touches map[int]pos + touches map[driver.TouchID]pos gamepads []Gamepad ui *UserInterface } @@ -136,7 +136,7 @@ func (i *Input) IsGamepadButtonPressed(id driver.GamepadID, button driver.Gamepa return false } -func (i *Input) TouchIDs() []int { +func (i *Input) TouchIDs() []driver.TouchID { i.ui.m.RLock() defer i.ui.m.RUnlock() @@ -144,14 +144,14 @@ func (i *Input) TouchIDs() []int { return nil } - var ids []int + var ids []driver.TouchID for id := range i.touches { ids = append(ids, id) } return ids } -func (i *Input) TouchPosition(id int) (x, y int) { +func (i *Input) TouchPosition(id driver.TouchID) (x, y int) { i.ui.m.RLock() defer i.ui.m.RUnlock() @@ -198,7 +198,7 @@ func (i *Input) update(keys map[driver.Key]struct{}, runes []rune, touches []*To i.runes = make([]rune, len(runes)) copy(i.runes, runes) - i.touches = map[int]pos{} + i.touches = map[driver.TouchID]pos{} for _, t := range touches { i.touches[t.ID] = pos{ X: t.X, diff --git a/internal/uidriver/mobile/ui.go b/internal/uidriver/mobile/ui.go index f075d1b72..4928b5bb9 100644 --- a/internal/uidriver/mobile/ui.go +++ b/internal/uidriver/mobile/ui.go @@ -215,7 +215,7 @@ func (u *UserInterface) appMain(a app.App) { x, y := float64(e.X)/s, float64(e.Y)/s // TODO: Is it ok to cast from int64 to int here? touches[e.Sequence] = &Touch{ - ID: int(e.Sequence), + ID: driver.TouchID(e.Sequence), X: int(x), Y: int(y), } @@ -474,7 +474,7 @@ func (u *UserInterface) Window() driver.Window { } type Touch struct { - ID int + ID driver.TouchID X int Y int } diff --git a/mobile/ebitenmobileview/input.go b/mobile/ebitenmobileview/input.go index 0fc5baca0..b3ef45342 100644 --- a/mobile/ebitenmobileview/input.go +++ b/mobile/ebitenmobileview/input.go @@ -29,7 +29,7 @@ type position struct { var ( keys = map[driver.Key]struct{}{} runes []rune - touches = map[int]position{} + touches = map[driver.TouchID]position{} gamepads = map[driver.GamepadID]*mobile.Gamepad{} ) diff --git a/mobile/ebitenmobileview/input_android.go b/mobile/ebitenmobileview/input_android.go index af29d6318..dfa1c42e6 100644 --- a/mobile/ebitenmobileview/input_android.go +++ b/mobile/ebitenmobileview/input_android.go @@ -201,10 +201,10 @@ func gamepadIDFromDeviceID(deviceID int) driver.GamepadID { func UpdateTouchesOnAndroid(action int, id int, x, y int) { switch action { case 0x00, 0x05, 0x02: // ACTION_DOWN, ACTION_POINTER_DOWN, ACTION_MOVE - touches[id] = position{x, y} + touches[driver.TouchID(id)] = position{x, y} updateInput() case 0x01, 0x06: // ACTION_UP, ACTION_POINTER_UP - delete(touches, id) + delete(touches, driver.TouchID(id)) updateInput() } } diff --git a/mobile/ebitenmobileview/input_ios.go b/mobile/ebitenmobileview/input_ios.go index 6a1f9688a..6b434f466 100644 --- a/mobile/ebitenmobileview/input_ios.go +++ b/mobile/ebitenmobileview/input_ios.go @@ -18,6 +18,8 @@ package ebitenmobileview import ( "fmt" + + "github.com/hajimehoshi/ebiten/v2/internal/driver" ) // #cgo CFLAGS: -x objective-c @@ -47,12 +49,12 @@ func UpdateTouchesOnIOS(phase int, ptr int64, x, y int) { switch phase { case C.UITouchPhaseBegan, C.UITouchPhaseMoved, C.UITouchPhaseStationary: id := getIDFromPtr(ptr) - touches[id] = position{x, y} + touches[driver.TouchID(id)] = position{x, y} updateInput() case C.UITouchPhaseEnded, C.UITouchPhaseCancelled: id := getIDFromPtr(ptr) delete(ptrToID, ptr) - delete(touches, id) + delete(touches, driver.TouchID(id)) updateInput() default: panic(fmt.Sprintf("ebitenmobileview: invalid phase: %d", phase))