From dd63eef65e58aca8c949f2169b289b1bf07473b9 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 24 Aug 2024 01:04:11 +0900 Subject: [PATCH] textinput: support every environment even without IME Closes #3072 --- exp/textinput/textinput_noime.go | 58 ++++++++++++++++++++++++++++++++ exp/textinput/textinput_null.go | 25 -------------- internal/ui/context.go | 2 ++ internal/ui/ui.go | 5 +++ 4 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 exp/textinput/textinput_noime.go delete mode 100644 exp/textinput/textinput_null.go diff --git a/exp/textinput/textinput_noime.go b/exp/textinput/textinput_noime.go new file mode 100644 index 000000000..58b4d05fc --- /dev/null +++ b/exp/textinput/textinput_noime.go @@ -0,0 +1,58 @@ +// Copyright 2023 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. + +//go:build (!darwin && !js && !windows) || ios + +package textinput + +import ( + "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/internal/ui" +) + +type textInput struct { + rs []rune + lastTick uint64 +} + +var theTextInput textInput + +func (t *textInput) Start(x, y int) (chan State, func()) { + // AppendInputChars is updated only when the tick is updated. + // If the tick is not updated, return nil immediately. + tick := ui.Get().Tick() + if t.lastTick == tick { + return nil, nil + } + defer func() { + t.lastTick = tick + }() + + s := newSession() + + // This is a pseudo implementation with AppendInputChars without IME. + // This is tentative and should be replaced with IME in the future. + t.rs = ebiten.AppendInputChars(t.rs[:0]) + if len(t.rs) == 0 { + return nil, nil + } + s.ch <- State{ + Text: string(t.rs), + Committed: true, + } + // Keep the channel as end() resets s.ch. + ch := s.ch + s.end() + return ch, nil +} diff --git a/exp/textinput/textinput_null.go b/exp/textinput/textinput_null.go deleted file mode 100644 index 22867befc..000000000 --- a/exp/textinput/textinput_null.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2023 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. - -//go:build (!darwin && !js && !windows) || ios - -package textinput - -type textInput struct{} - -var theTextInput textInput - -func (t *textInput) Start(x, y int) (chan State, func()) { - return nil, nil -} diff --git a/internal/ui/context.go b/internal/ui/context.go index bf9ccce50..7f94b2d5d 100644 --- a/internal/ui/context.go +++ b/internal/ui/context.go @@ -153,6 +153,8 @@ func (c *context) updateFrameImpl(graphicsDriver graphicsdriver.Graphics, update if err := ui.error(); err != nil { return err } + + ui.tick.Add(1) } // Update window icons during a frame, since an icon might be *ebiten.Image and diff --git a/internal/ui/ui.go b/internal/ui/ui.go index b8f3991d8..ed7efbee9 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -79,6 +79,7 @@ type UserInterface struct { graphicsLibrary atomic.Int32 running atomic.Bool terminated atomic.Bool + tick atomic.Uint64 whiteImage *Image @@ -230,3 +231,7 @@ func (u *UserInterface) isTerminated() bool { func (u *UserInterface) setTerminated() { u.terminated.Store(true) } + +func (u *UserInterface) Tick() uint64 { + return u.tick.Load() +}