ebiten: refactoring: add internal/inputstate

internal/inputstate will be accessed from inpututil in the future.

Updates #3249
This commit is contained in:
Hajime Hoshi
2025-09-21 16:57:33 +09:00
parent 97e145a493
commit 6aa208e15e
8 changed files with 157 additions and 388 deletions

View File

@@ -20,6 +20,7 @@ import (
"sync/atomic" "sync/atomic"
"github.com/hajimehoshi/ebiten/v2/internal/atlas" "github.com/hajimehoshi/ebiten/v2/internal/atlas"
"github.com/hajimehoshi/ebiten/v2/internal/inputstate"
"github.com/hajimehoshi/ebiten/v2/internal/ui" "github.com/hajimehoshi/ebiten/v2/internal/ui"
) )
@@ -94,7 +95,7 @@ func (g *gameForUI) Layout(outsideWidth, outsideHeight float64) (float64, float6
} }
func (g *gameForUI) UpdateInputState(fn func(*ui.InputState)) { func (g *gameForUI) UpdateInputState(fn func(*ui.InputState)) {
theInputState.update(fn) inputstate.Get().Update(fn)
} }
func (g *gameForUI) Update() error { func (g *gameForUI) Update() error {

View File

@@ -468,10 +468,10 @@ type Key int
// Keys. // Keys.
const ( const (
{{range $index, $name := .EbitengineKeyNamesWithoutMods}}Key{{$name}} Key = Key(ui.Key{{$name}}) {{range $index, $name := .EbitengineKeyNamesWithoutMods}}Key{{$name}} Key = Key(ui.Key{{$name}})
{{end}} KeyAlt Key = Key(ui.KeyReserved0) {{end}} KeyAlt Key = Key(ui.KeyAlt)
KeyControl Key = Key(ui.KeyReserved1) KeyControl Key = Key(ui.KeyControl)
KeyShift Key = Key(ui.KeyReserved2) KeyShift Key = Key(ui.KeyShift)
KeyMeta Key = Key(ui.KeyReserved3) KeyMeta Key = Key(ui.KeyMeta)
KeyMax Key = KeyMeta KeyMax Key = KeyMeta
// Keys for backward compatibility. // Keys for backward compatibility.
@@ -480,16 +480,6 @@ const (
{{end}} {{end}}
) )
func (k Key) isValid() bool {
switch k {
{{range $name := .EbitengineKeyNamesWithoutOld}}case Key{{$name}}:
return true
{{end}}
default:
return false
}
}
// String returns a string representing the key. // String returns a string representing the key.
// //
// If k is an undefined key, String returns an empty string. // If k is an undefined key, String returns an empty string.
@@ -539,11 +529,11 @@ type Key int
const ( const (
{{range $index, $name := .UIKeyNames}}Key{{$name}}{{if eq $index 0}} Key = iota{{end}} {{range $index, $name := .UIKeyNames}}Key{{$name}}{{if eq $index 0}} Key = iota{{end}}
{{end}} KeyReserved0 {{end}} KeyAlt
KeyReserved1 KeyControl
KeyReserved2 KeyShift
KeyReserved3 KeyMeta
KeyMax = KeyReserved3 KeyMax = KeyMeta
) )
func (k Key) String() string { func (k Key) String() string {

114
input.go
View File

@@ -15,11 +15,9 @@
package ebiten package ebiten
import ( import (
"io/fs"
"sync"
"github.com/hajimehoshi/ebiten/v2/internal/gamepad" "github.com/hajimehoshi/ebiten/v2/internal/gamepad"
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb" "github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
"github.com/hajimehoshi/ebiten/v2/internal/inputstate"
"github.com/hajimehoshi/ebiten/v2/internal/ui" "github.com/hajimehoshi/ebiten/v2/internal/ui"
) )
@@ -36,7 +34,7 @@ import (
// //
// On Android (ebitenmobile), EbitenView must be focusable to enable to handle keyboard keys. // On Android (ebitenmobile), EbitenView must be focusable to enable to handle keyboard keys.
func AppendInputChars(runes []rune) []rune { func AppendInputChars(runes []rune) []rune {
return theInputState.appendInputChars(runes) return inputstate.Get().AppendInputChars(runes)
} }
// InputChars return "printable" runes read from the keyboard at the time Update is called. // InputChars return "printable" runes read from the keyboard at the time Update is called.
@@ -58,7 +56,7 @@ func InputChars() []rune {
// //
// On Android (ebitenmobile), EbitenView must be focusable to enable to handle keyboard keys. // On Android (ebitenmobile), EbitenView must be focusable to enable to handle keyboard keys.
func IsKeyPressed(key Key) bool { func IsKeyPressed(key Key) bool {
return theInputState.isKeyPressed(key) return inputstate.Get().IsKeyPressed(ui.Key(key))
} }
// KeyName returns a key name for the current keyboard layout. // KeyName returns a key name for the current keyboard layout.
@@ -83,7 +81,7 @@ func KeyName(key Key) string {
// //
// CursorPosition is concurrent-safe. // CursorPosition is concurrent-safe.
func CursorPosition() (x, y int) { func CursorPosition() (x, y int) {
cx, cy := theInputState.cursorPosition() cx, cy := inputstate.Get().CursorPosition()
return int(cx), int(cy) return int(cx), int(cy)
} }
@@ -92,7 +90,7 @@ func CursorPosition() (x, y int) {
// //
// Wheel is concurrent-safe. // Wheel is concurrent-safe.
func Wheel() (xoff, yoff float64) { func Wheel() (xoff, yoff float64) {
return theInputState.wheel() return inputstate.Get().Wheel()
} }
// IsMouseButtonPressed returns a boolean indicating whether mouseButton is pressed. // IsMouseButtonPressed returns a boolean indicating whether mouseButton is pressed.
@@ -102,7 +100,7 @@ func Wheel() (xoff, yoff float64) {
// //
// IsMouseButtonPressed is concurrent-safe. // IsMouseButtonPressed is concurrent-safe.
func IsMouseButtonPressed(mouseButton MouseButton) bool { func IsMouseButtonPressed(mouseButton MouseButton) bool {
return theInputState.isMouseButtonPressed(mouseButton) return inputstate.Get().IsMouseButtonPressed(ui.MouseButton(mouseButton))
} }
// GamepadID represents a gamepad identifier. // GamepadID represents a gamepad identifier.
@@ -350,7 +348,7 @@ func UpdateStandardGamepadLayoutMappings(mappings string) (bool, error) {
} }
// TouchID represents a touch's identifier. // TouchID represents a touch's identifier.
type TouchID int type TouchID = ui.TouchID
// AppendTouchIDs appends the current touch states to touches, and returns the extended buffer. // AppendTouchIDs appends the current touch states to touches, and returns the extended buffer.
// Giving a slice that already has enough capacity works efficiently. // Giving a slice that already has enough capacity works efficiently.
@@ -363,7 +361,7 @@ type TouchID int
// //
// AppendTouchIDs is concurrent-safe. // AppendTouchIDs is concurrent-safe.
func AppendTouchIDs(touches []TouchID) []TouchID { func AppendTouchIDs(touches []TouchID) []TouchID {
return theInputState.appendTouchIDs(touches) return inputstate.Get().AppendTouchIDs(touches)
} }
// TouchIDs returns the current touch states. // TouchIDs returns the current touch states.
@@ -379,99 +377,5 @@ func TouchIDs() []TouchID {
// //
// TouchPosition is concurrent-safe. // TouchPosition is concurrent-safe.
func TouchPosition(id TouchID) (int, int) { func TouchPosition(id TouchID) (int, int) {
return theInputState.touchPosition(id) return inputstate.Get().TouchPosition(ui.TouchID(id))
}
var theInputState inputState
type inputState struct {
state ui.InputState
m sync.Mutex
}
func (i *inputState) update(fn func(*ui.InputState)) {
i.m.Lock()
defer i.m.Unlock()
fn(&i.state)
}
func (i *inputState) appendInputChars(runes []rune) []rune {
i.m.Lock()
defer i.m.Unlock()
return append(runes, i.state.Runes...)
}
func (i *inputState) isKeyPressed(key Key) bool {
if !key.isValid() {
return false
}
i.m.Lock()
defer i.m.Unlock()
switch key {
case KeyAlt:
return i.state.KeyPressed[ui.KeyAltLeft] || i.state.KeyPressed[ui.KeyAltRight]
case KeyControl:
return i.state.KeyPressed[ui.KeyControlLeft] || i.state.KeyPressed[ui.KeyControlRight]
case KeyShift:
return i.state.KeyPressed[ui.KeyShiftLeft] || i.state.KeyPressed[ui.KeyShiftRight]
case KeyMeta:
return i.state.KeyPressed[ui.KeyMetaLeft] || i.state.KeyPressed[ui.KeyMetaRight]
default:
return i.state.KeyPressed[key]
}
}
func (i *inputState) cursorPosition() (float64, float64) {
i.m.Lock()
defer i.m.Unlock()
return i.state.CursorX, i.state.CursorY
}
func (i *inputState) wheel() (float64, float64) {
i.m.Lock()
defer i.m.Unlock()
return i.state.WheelX, i.state.WheelY
}
func (i *inputState) isMouseButtonPressed(mouseButton MouseButton) bool {
i.m.Lock()
defer i.m.Unlock()
return i.state.MouseButtonPressed[mouseButton]
}
func (i *inputState) appendTouchIDs(touches []TouchID) []TouchID {
i.m.Lock()
defer i.m.Unlock()
for _, t := range i.state.Touches {
touches = append(touches, TouchID(t.ID))
}
return touches
}
func (i *inputState) touchPosition(id TouchID) (int, int) {
i.m.Lock()
defer i.m.Unlock()
for _, t := range i.state.Touches {
if id != TouchID(t.ID) {
continue
}
return t.X, t.Y
}
return 0, 0
}
func (i *inputState) windowBeingClosed() bool {
i.m.Lock()
defer i.m.Unlock()
return i.state.WindowBeingClosed
}
func (i *inputState) droppedFiles() fs.FS {
i.m.Lock()
defer i.m.Unlock()
return i.state.DroppedFiles
} }

View File

@@ -0,0 +1,124 @@
// Copyright 2025 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package inputstate provides APIs to access the input state for the current tick.
// This package is for the ebiten package and the inpututil package.
package inputstate
import (
"io/fs"
"sync"
"github.com/hajimehoshi/ebiten/v2/internal/ui"
)
var (
theInputState inputState
)
type inputState struct {
state ui.InputState
m sync.Mutex
}
func Get() *inputState {
return &theInputState
}
func (i *inputState) Update(fn func(*ui.InputState)) {
i.m.Lock()
defer i.m.Unlock()
fn(&i.state)
}
func (i *inputState) AppendInputChars(runes []rune) []rune {
i.m.Lock()
defer i.m.Unlock()
return append(runes, i.state.Runes...)
}
func (i *inputState) IsKeyPressed(key ui.Key) bool {
if key < 0 || key > ui.KeyMax {
return false
}
i.m.Lock()
defer i.m.Unlock()
switch key {
case ui.KeyAlt:
return i.state.KeyPressed[ui.KeyAltLeft] || i.state.KeyPressed[ui.KeyAltRight]
case ui.KeyControl:
return i.state.KeyPressed[ui.KeyControlLeft] || i.state.KeyPressed[ui.KeyControlRight]
case ui.KeyShift:
return i.state.KeyPressed[ui.KeyShiftLeft] || i.state.KeyPressed[ui.KeyShiftRight]
case ui.KeyMeta:
return i.state.KeyPressed[ui.KeyMetaLeft] || i.state.KeyPressed[ui.KeyMetaRight]
default:
return i.state.KeyPressed[key]
}
}
func (i *inputState) CursorPosition() (float64, float64) {
i.m.Lock()
defer i.m.Unlock()
return i.state.CursorX, i.state.CursorY
}
func (i *inputState) Wheel() (float64, float64) {
i.m.Lock()
defer i.m.Unlock()
return i.state.WheelX, i.state.WheelY
}
func (i *inputState) IsMouseButtonPressed(mouseButton ui.MouseButton) bool {
i.m.Lock()
defer i.m.Unlock()
return i.state.MouseButtonPressed[mouseButton]
}
func (i *inputState) AppendTouchIDs(touches []ui.TouchID) []ui.TouchID {
i.m.Lock()
defer i.m.Unlock()
for _, t := range i.state.Touches {
touches = append(touches, ui.TouchID(t.ID))
}
return touches
}
func (i *inputState) TouchPosition(id ui.TouchID) (int, int) {
i.m.Lock()
defer i.m.Unlock()
for _, t := range i.state.Touches {
if id != ui.TouchID(t.ID) {
continue
}
return t.X, t.Y
}
return 0, 0
}
func (i *inputState) WindowBeingClosed() bool {
i.m.Lock()
defer i.m.Unlock()
return i.state.WindowBeingClosed
}
func (i *inputState) DroppedFiles() fs.FS {
i.m.Lock()
defer i.m.Unlock()
return i.state.DroppedFiles
}

View File

@@ -141,11 +141,11 @@ const (
KeySlash KeySlash
KeySpace KeySpace
KeyTab KeyTab
KeyReserved0 KeyAlt
KeyReserved1 KeyControl
KeyReserved2 KeyShift
KeyReserved3 KeyMeta
KeyMax = KeyReserved3 KeyMax = KeyMeta
) )
func (k Key) String() string { func (k Key) String() string {

260
keys.go
View File

@@ -148,10 +148,10 @@ const (
KeySlash Key = Key(ui.KeySlash) KeySlash Key = Key(ui.KeySlash)
KeySpace Key = Key(ui.KeySpace) KeySpace Key = Key(ui.KeySpace)
KeyTab Key = Key(ui.KeyTab) KeyTab Key = Key(ui.KeyTab)
KeyAlt Key = Key(ui.KeyReserved0) KeyAlt Key = Key(ui.KeyAlt)
KeyControl Key = Key(ui.KeyReserved1) KeyControl Key = Key(ui.KeyControl)
KeyShift Key = Key(ui.KeyReserved2) KeyShift Key = Key(ui.KeyShift)
KeyMeta Key = Key(ui.KeyReserved3) KeyMeta Key = Key(ui.KeyMeta)
KeyMax Key = KeyMeta KeyMax Key = KeyMeta
// Keys for backward compatibility. // Keys for backward compatibility.
@@ -194,258 +194,6 @@ const (
KeyUp Key = Key(ui.KeyArrowUp) KeyUp Key = Key(ui.KeyArrowUp)
) )
func (k Key) isValid() bool {
switch k {
case KeyA:
return true
case KeyB:
return true
case KeyC:
return true
case KeyD:
return true
case KeyE:
return true
case KeyF:
return true
case KeyG:
return true
case KeyH:
return true
case KeyI:
return true
case KeyJ:
return true
case KeyK:
return true
case KeyL:
return true
case KeyM:
return true
case KeyN:
return true
case KeyO:
return true
case KeyP:
return true
case KeyQ:
return true
case KeyR:
return true
case KeyS:
return true
case KeyT:
return true
case KeyU:
return true
case KeyV:
return true
case KeyW:
return true
case KeyX:
return true
case KeyY:
return true
case KeyZ:
return true
case KeyAlt:
return true
case KeyAltLeft:
return true
case KeyAltRight:
return true
case KeyArrowDown:
return true
case KeyArrowLeft:
return true
case KeyArrowRight:
return true
case KeyArrowUp:
return true
case KeyBackquote:
return true
case KeyBackslash:
return true
case KeyBackspace:
return true
case KeyBracketLeft:
return true
case KeyBracketRight:
return true
case KeyCapsLock:
return true
case KeyComma:
return true
case KeyContextMenu:
return true
case KeyControl:
return true
case KeyControlLeft:
return true
case KeyControlRight:
return true
case KeyDelete:
return true
case KeyDigit0:
return true
case KeyDigit1:
return true
case KeyDigit2:
return true
case KeyDigit3:
return true
case KeyDigit4:
return true
case KeyDigit5:
return true
case KeyDigit6:
return true
case KeyDigit7:
return true
case KeyDigit8:
return true
case KeyDigit9:
return true
case KeyEnd:
return true
case KeyEnter:
return true
case KeyEqual:
return true
case KeyEscape:
return true
case KeyF1:
return true
case KeyF2:
return true
case KeyF3:
return true
case KeyF4:
return true
case KeyF5:
return true
case KeyF6:
return true
case KeyF7:
return true
case KeyF8:
return true
case KeyF9:
return true
case KeyF10:
return true
case KeyF11:
return true
case KeyF12:
return true
case KeyF13:
return true
case KeyF14:
return true
case KeyF15:
return true
case KeyF16:
return true
case KeyF17:
return true
case KeyF18:
return true
case KeyF19:
return true
case KeyF20:
return true
case KeyF21:
return true
case KeyF22:
return true
case KeyF23:
return true
case KeyF24:
return true
case KeyHome:
return true
case KeyInsert:
return true
case KeyIntlBackslash:
return true
case KeyMeta:
return true
case KeyMetaLeft:
return true
case KeyMetaRight:
return true
case KeyMinus:
return true
case KeyNumLock:
return true
case KeyNumpad0:
return true
case KeyNumpad1:
return true
case KeyNumpad2:
return true
case KeyNumpad3:
return true
case KeyNumpad4:
return true
case KeyNumpad5:
return true
case KeyNumpad6:
return true
case KeyNumpad7:
return true
case KeyNumpad8:
return true
case KeyNumpad9:
return true
case KeyNumpadAdd:
return true
case KeyNumpadDecimal:
return true
case KeyNumpadDivide:
return true
case KeyNumpadEnter:
return true
case KeyNumpadEqual:
return true
case KeyNumpadMultiply:
return true
case KeyNumpadSubtract:
return true
case KeyPageDown:
return true
case KeyPageUp:
return true
case KeyPause:
return true
case KeyPeriod:
return true
case KeyPrintScreen:
return true
case KeyQuote:
return true
case KeyScrollLock:
return true
case KeySemicolon:
return true
case KeyShift:
return true
case KeyShiftLeft:
return true
case KeyShiftRight:
return true
case KeySlash:
return true
case KeySpace:
return true
case KeyTab:
return true
default:
return false
}
}
// String returns a string representing the key. // String returns a string representing the key.
// //
// If k is an undefined key, String returns an empty string. // If k is an undefined key, String returns an empty string.

3
run.go
View File

@@ -23,6 +23,7 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/clock" "github.com/hajimehoshi/ebiten/v2/internal/clock"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/inputstate"
"github.com/hajimehoshi/ebiten/v2/internal/ui" "github.com/hajimehoshi/ebiten/v2/internal/ui"
) )
@@ -754,7 +755,7 @@ func toUIRunOptions(options *RunGameOptions) *ui.RunOptions {
// //
// DroppedFiles is concurrent-safe. // DroppedFiles is concurrent-safe.
func DroppedFiles() fs.FS { func DroppedFiles() fs.FS {
return theInputState.droppedFiles() return inputstate.Get().DroppedFiles()
} }
// Tick returns the current tick count. // Tick returns the current tick count.

View File

@@ -18,6 +18,7 @@ import (
"image" "image"
"sync/atomic" "sync/atomic"
"github.com/hajimehoshi/ebiten/v2/internal/inputstate"
"github.com/hajimehoshi/ebiten/v2/internal/ui" "github.com/hajimehoshi/ebiten/v2/internal/ui"
) )
@@ -293,7 +294,7 @@ func RestoreWindow() {
// //
// IsWindowBeingClosed is concurrent-safe. // IsWindowBeingClosed is concurrent-safe.
func IsWindowBeingClosed() bool { func IsWindowBeingClosed() bool {
return theInputState.windowBeingClosed() return inputstate.Get().WindowBeingClosed()
} }
// SetWindowClosingHandled sets whether the window closing is handled or not on desktops. The default state is false. // SetWindowClosingHandled sets whether the window closing is handled or not on desktops. The default state is false.