@@ -11,6 +11,7 @@ import (
1111 "unicode/utf8"
1212
1313 "github.com/hajimehoshi/ebiten/v2"
14+ "github.com/hajimehoshi/ebiten/v2/exp/textinput"
1415 "github.com/hajimehoshi/ebiten/v2/inpututil"
1516)
1617
@@ -41,8 +42,12 @@ func (c *Context) textFieldRaw(buf *string, id widgetID, opt option) (EventHandl
4142
4243 f := c .currentContainer ().textInputTextField (id , true )
4344 if c .focus == id {
45+ // A freshly focused text input field still has its own cursor/selection state.
46+ // Seed that state from the bound string before reading input so typing starts
47+ // after any existing text instead of inserting at the beginning.
48+ focusTextInputField (f , * buf )
49+
4450 // handle text input
45- f .Focus ()
4651 x := bounds .Min .X + c .style ().padding + textWidth (* buf )
4752 y := bounds .Min .Y + lineHeight ()
4853 handled , err := f .HandleInput (x , y )
@@ -58,15 +63,17 @@ func (c *Context) textFieldRaw(buf *string, id widgetID, opt option) (EventHandl
5863 if inpututil .IsKeyJustPressed (ebiten .KeyBackspace ) && len (* buf ) > 0 {
5964 _ , size := utf8 .DecodeLastRuneInString (* buf )
6065 * buf = (* buf )[:len (* buf )- size ]
61- f . SetTextAndSelection ( * buf , len ( * buf ), len ( * buf ) )
66+ setTextInputFieldValue ( f , * buf )
6267 }
6368 if inpututil .IsKeyJustPressed (ebiten .KeyEnter ) {
6469 e = & eventHandler {}
6570 }
6671 }
6772 } else {
6873 if * buf != f .Text () {
69- f .SetTextAndSelection (* buf , len (* buf ), len (* buf ))
74+ // Keep the cached text-input object in sync while it is unfocused so the
75+ // next focus starts from the latest value and with the caret at the end.
76+ setTextInputFieldValue (f , * buf )
7077 }
7178 if wasFocused {
7279 e = & eventHandler {}
@@ -100,13 +107,35 @@ func (c *Context) textFieldRaw(buf *string, id widgetID, opt option) (EventHandl
100107 })
101108}
102109
110+ func focusTextInputField (f * textinput.Field , value string ) {
111+ // Focus() does not rewrite the field's text or selection. If this field is being
112+ // focused for the first time, its selection is still 0,0, so copy in the current
113+ // value first and move the caret to the end.
114+ //
115+ // Reset the selection on every unfocused->focused transition, even when the
116+ // text already matches. The cached textinput.Field can survive across window
117+ // reopenings, and in that case it can keep an old caret position from an
118+ // earlier edit session.
119+ if ! f .IsFocused () {
120+ setTextInputFieldValue (f , value )
121+ }
122+ f .Focus ()
123+ }
124+
125+ func setTextInputFieldValue (f * textinput.Field , value string ) {
126+ // Treat programmatic value changes the same way a user expects to keep typing:
127+ // after loading text, place the caret at the end ready for appending.
128+ f .SetTextAndSelection (value , len (value ), len (value ))
129+ }
130+
103131// SetTextFieldValue sets the value of the current text field.
132+ // The caret is moved to the end of the new text.
104133//
105134// If the last widget is not a text field, this function does nothing.
106135func (c * Context ) SetTextFieldValue (value string ) {
107136 _ = c .wrapEventHandlerAndError (func () (EventHandler , error ) {
108137 if f := c .currentContainer ().textInputTextField (c .currentID , false ); f != nil {
109- f . SetTextAndSelection ( value , 0 , 0 )
138+ setTextInputFieldValue ( f , value )
110139 }
111140 return nil , nil
112141 })
@@ -201,7 +230,7 @@ func (c *Context) numberField(value *int, step int, idPart string, opt option) (
201230 if updated {
202231 buf := fmt .Sprintf ("%d" , * value )
203232 if f := c .currentContainer ().textInputTextField (id , false ); f != nil {
204- f . SetTextAndSelection ( buf , len ( buf ), len ( buf ) )
233+ setTextInputFieldValue ( f , buf )
205234 }
206235 e = & eventHandler {}
207236 }
@@ -277,7 +306,7 @@ func (c *Context) numberFieldF(value *float64, step float64, digits int, idPart
277306 if updated {
278307 buf := formatNumber (* value , digits )
279308 if f := c .currentContainer ().textInputTextField (id , false ); f != nil {
280- f . SetTextAndSelection ( buf , len ( buf ), len ( buf ) )
309+ setTextInputFieldValue ( f , buf )
281310 }
282311 e = & eventHandler {}
283312 }
0 commit comments