Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IME support #4614

Draft
wants to merge 13 commits into
base: develop
Choose a base branch
from
Draft

Add IME support #4614

wants to merge 13 commits into from

Conversation

kanryu
Copy link

@kanryu kanryu commented Feb 6, 2024

Description:

As everyone knows, fyne does not currently support IME. This is fundamentally caused by the fact that glfw does not support IME, and cannot be resolved by fyne's efforts alone. So I solved this problem by adding a hack to both go-gl/glfw and fyne. Please check it on your PC.

Fixes #618

Supported environments

  • supported
    • Windows
    • Mac
    • Linux(X11, Wayland)
  • not supported
    • Android
    • iOS

How to try this

git clone https://github.com/kanryu/fyne
git clone https://github.com/kanryu/glfw
cd fyne
go mod edit -replace github.com/go-gl/glfw/v3.3/glfw=../glfw/v3.4/glfw
go run cmd/fyne_demo/main.go
Fyne.Demo.2024-02-06.19-48-28.mp4

Checklist:

  • Tests included.
  • Lint and formatter run with no errors.
  • Tests all pass.

Where applicable:

  • Public APIs match existing style and have Since: line.
  • Any breaking changes have a deprecation path or have been discussed.
  • Check for binary size increases when importing new modules.

Copy link
Member

@andydotxyz andydotxyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this really complex task.
I have some suggestions inline.

@@ -75,6 +75,14 @@ type Focusable interface {
TypedKey(*KeyEvent)
}

// Preeditable describes any CanvasObject that can respond to IME inputs.
// Originally, it should be a method of Focusable, but only a few widgets need PreeditChanged,
// and adding a method to Focusable will have a big impact on others, so defined as a new interface.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this sentiment - adding it to Focusable would be a breaking change.
However can it be worded less like a workaround.
i.e. "Widgets that implement Focusable may also want to implement PreeditChanged to handle IME input?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That comment certainly makes the relationship with Focusable clearer. People who see this code for the first time may not understand the deep relationship between Focusable and Preeditable.

@@ -191,6 +191,15 @@ func (c *Canvas) Focused() fyne.Focusable {
return mgr.Focused()
}

// Preeditable return the current preeditable object only when focused
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will crash if the input is not Preeditable. It should not be needed as it will always be the same object returned by Focused()

Copy link
Author

@kanryu kanryu Feb 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will crash if the input is not Preeditable.

I didn't notice it when running fyne_demo. Thank you for pointing that out. I had a chance to learn the correct casting method.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would only happen if you started to interact with an input that had not implemented that interface.
Something like the checkbox I would think for example.

@@ -677,6 +678,32 @@ func (w *window) charInput(viewport *glfw.Window, char rune) {
w.processCharInput(char)
}

var counterIme int

// IME
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment should not be needed here. Where comments are added it usually implies naming is insufficient.

focusedBlock int,
caret int,
) {
fmt.Println(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't leave in debug

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andydotxyz ok, removed.

"focusedBlock", focusedBlock,
"caret", caret,
)
w.processPreedit(preeditString)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like it would be easier to just inline processPreedit here as it is barely a single line and only called from this location

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andydotxyz Unfortunately processPreedit and Preeditable.PreeditChanged are temporary interfaces. This is because the original Preedit response requires a more complex response. It is necessary to additionally display the conversion candidates for input content provided by the IME and the IME's own caret.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Should we mark this as a draft PR then instead of one ready for review?

widget/entry.go Outdated
@@ -102,6 +105,7 @@ type Entry struct {

// NewEntry creates a new single line entry widget.
func NewEntry() *Entry {
// e := &Entry{Wrapping: fyne.TextTruncate, PreeditText: "(日本語)"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't leave dead code in comments

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andydotxyz OK, removed

widget/entry.go Outdated
Text string
shortcut fyne.ShortcutHandler
Text string
PreeditText string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a public field? it feels like it should be an internal implementation if required at all?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andydotxyz OK, privated

// Convert column, row into x,y
getCoordinates := func(column int, row int) (float32, float32) {
sz := provider.lineSizeToColumn(column, row)
return sz.Width, sz.Height*float32(row) - theme.InputBorderSize() + theme.InnerPadding()
szpe := preedit.lineSizeToColumn(column, row)
return float32(math.Max(float64(sz.Width), float64(r.cursor.Position().X+szpe.Width))), sz.Height*float32(row) - theme.InputBorderSize() + theme.InnerPadding()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this is correct? Isn't the pre-edit only on the current cursor line? This seems to add the "szpe" irrespective of the row being measured...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andydotxyz OK, Removed.

@kanryu
Copy link
Author

kanryu commented Feb 14, 2024

スクリーンショット 2024-02-14 11 36 16
Full input is now available on Mac.

@Jacalz Jacalz changed the title IME support for 1.5 billion users Add IME support Feb 14, 2024
@qizhanchan
Copy link

qizhanchan commented Apr 6, 2024

image

I cloned the latest branch and run the demo, the entry's 'select all' focus effect is confusing.

@Jacalz
Copy link
Member

Jacalz commented Apr 6, 2024

@kanryu If you are experiencing a bug on develop, report it as an issue instead of as a comment on a PR please. Thanks.

@kanryu
Copy link
Author

kanryu commented Apr 6, 2024

I cloned the latest branch and run the demo, the entry's 'select all' focus effect is confusing.

@qizhanchan This issue is not caused by this PR's fix, but also occurs with the original Fyne Entry. So it's a Fyne problem.

@kanryu
Copy link
Author

kanryu commented Apr 6, 2024

If you are experiencing a bug on develop, report it as an issue instead of as a comment on a PR please. Thanks.

@Jacalz Which problem in this PR are you pointing out? This PR involves a very large source code modification.

@Jacalz
Copy link
Member

Jacalz commented Apr 6, 2024

Ah, sorry @kanryu. I meant to be tagging @qizhanchan in my message. I assumed that he was referring to a bug on the develop branch.

Copy link
Member

@andydotxyz andydotxyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry it has taken so long to get back on this.

I can't figure out how to test this - is there info about the versions of GLFW etc missing form go.mod?

@@ -765,11 +807,15 @@ func (w *window) create() {
win.SetRefreshCallback(w.refresh)
win.SetContentScaleCallback(w.scaled)
win.SetCursorPosCallback(w.mouseMoved)
win.SetPreeditCallback(w.preedit)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't compile for me. I guess the go.mod is missing some alterations?

@@ -11,8 +11,11 @@ import (
"github.com/go-gl/glfw/v3.3/glfw"
)

const GLFW_X11_ONTHESPOT glfw.Hint = 0x00052002
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this be declared in the GLFW project?
I guess it relates to my other comment about not being sure of how to compile or which GLFW version is needed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andydotxyz Thanks for trying. As I wrote at the beginning of this PR, in order to check the operation of this PR, you need to clone both the modified fyne and glfw and change go.mod.

Copy link
Member

@Jacalz Jacalz Apr 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kanryu If this is under active development but not completed, please mark the PR as draft.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Jacalz It's difficult to explain in a few words because the work spanned multiple projects, but achieving this PR required major modifications to go-gl/glfw, and they effectively refused to merge. Because of this, we are currently unable to proceed with this PR any further.
Other than that, I think this PR is of a quality worthy of being tested by many people.

It's up to the people at the Fyne project to decide whether or not this PR should be marked as draft. Not that I would complain.

Copy link
Member

@Jacalz Jacalz Apr 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kanryu I am entirely aware of the situation. My personal opinion is that if a PR can't be tested as it is, i.e. isn't ready to be merged, it should be a draft. Those that are interested in testing it can do so but we maintainers don't have to remember that it isn't ready. It makes it easier to grasp which pull requests are waiting for reviews.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andydotxyz Thanks for trying. As I wrote at the beginning of this PR, in order to check the operation of this PR, you need to clone both the modified fyne and glfw and change go.mod.

This can be done with a replace directive in the go.mod so that this PR can simply be checked out and tested without pre-requisites. That also makes it clear of the requirements to compile.

@andydotxyz
Copy link
Member

Converting to draft as this is not in a state where we would be reviewing for merge.

@andydotxyz andydotxyz marked this pull request as draft April 23, 2024 14:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants