app,widget: implement Editor IME support, add Android implementation

Fixes: https://todo.sr.ht/~eliasnaur/gio/116
References: https://todo.sr.ht/~eliasnaur/gio/246
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2022-01-13 13:04:31 +01:00
parent c22138f5f8
commit 58cdb3e1da
16 changed files with 880 additions and 55 deletions
+109 -7
View File
@@ -188,6 +188,8 @@ var gioView struct {
sendA11yEvent C.jmethodID
sendA11yChange C.jmethodID
isA11yActive C.jmethodID
restartInput C.jmethodID
updateSelection C.jmethodID
}
// ViewEvent is sent whenever the Window's underlying Android view
@@ -471,6 +473,8 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j
m.sendA11yEvent = getMethodID(env, class, "sendA11yEvent", "(II)V")
m.sendA11yChange = getMethodID(env, class, "sendA11yChange", "(I)V")
m.isA11yActive = getMethodID(env, class, "isA11yActive", "()Z")
m.restartInput = getMethodID(env, class, "restartInput", "()V")
m.updateSelection = getMethodID(env, class, "updateSelection", "()V")
})
view = C.jni_NewGlobalRef(env, view)
wopts := <-mainWindow.out
@@ -490,6 +494,7 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j
views[handle] = w
w.loadConfig(env, class)
w.Configure(wopts.options)
w.SetInputHint(key.HintAny)
w.setStage(system.StagePaused)
w.callbacks.Event(ViewEvent{View: uintptr(view)})
return handle
@@ -930,7 +935,7 @@ func Java_org_gioui_GioView_onKeyEvent(env *C.JNIEnv, class C.jclass, handle C.j
w.callbacks.Event(key.Event{Name: n, State: state})
}
if pressed == C.JNI_TRUE && r != 0 && r != '\n' { // Checking for "\n" to prevent duplication with key.NameEnter (gio#224).
w.callbacks.Event(key.EditEvent{Text: string(rune(r))})
w.callbacks.EditorInsert(string(rune(r)))
}
}
@@ -988,6 +993,107 @@ func Java_org_gioui_GioView_onTouchEvent(env *C.JNIEnv, class C.jclass, handle C
})
}
//export Java_org_gioui_GioView_imeSelectionStart
func Java_org_gioui_GioView_imeSelectionStart(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jint {
w := views[handle]
sel := w.callbacks.EditorState().Selection
start := sel.Start
if sel.End < sel.Start {
start = sel.End
}
return C.jint(start)
}
//export Java_org_gioui_GioView_imeSelectionEnd
func Java_org_gioui_GioView_imeSelectionEnd(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jint {
w := views[handle]
sel := w.callbacks.EditorState().Selection
end := sel.End
if sel.End < sel.Start {
end = sel.Start
}
return C.jint(end)
}
//export Java_org_gioui_GioView_imeComposingStart
func Java_org_gioui_GioView_imeComposingStart(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jint {
w := views[handle]
comp := w.callbacks.EditorState().compose
start := comp.Start
if e := comp.End; e < start {
start = e
}
return C.jint(start)
}
//export Java_org_gioui_GioView_imeComposingEnd
func Java_org_gioui_GioView_imeComposingEnd(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jint {
w := views[handle]
comp := w.callbacks.EditorState().compose
end := comp.End
if s := comp.Start; s > end {
end = s
}
return C.jint(end)
}
//export Java_org_gioui_GioView_imeSnippet
func Java_org_gioui_GioView_imeSnippet(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jstring {
w := views[handle]
snip := w.callbacks.EditorState().Snippet.Text
return javaString(env, snip)
}
//export Java_org_gioui_GioView_imeSnippetStart
func Java_org_gioui_GioView_imeSnippetStart(env *C.JNIEnv, class C.jclass, handle C.jlong) C.jint {
w := views[handle]
return C.jint(w.callbacks.EditorState().Snippet.Start)
}
//export Java_org_gioui_GioView_imeSetSnippet
func Java_org_gioui_GioView_imeSetSnippet(env *C.JNIEnv, class C.jclass, handle C.jlong, start, end C.jint) {
w := views[handle]
r := key.Range{Start: int(start), End: int(end)}
w.callbacks.SetEditorSnippet(r)
}
//export Java_org_gioui_GioView_imeSetSelection
func Java_org_gioui_GioView_imeSetSelection(env *C.JNIEnv, class C.jclass, handle C.jlong, start, end C.jint) {
w := views[handle]
r := key.Range{Start: int(start), End: int(end)}
w.callbacks.SetEditorSelection(r)
}
//export Java_org_gioui_GioView_imeSetComposingRegion
func Java_org_gioui_GioView_imeSetComposingRegion(env *C.JNIEnv, class C.jclass, handle C.jlong, start, end C.jint) {
w := views[handle]
w.callbacks.SetComposingRegion(key.Range{
Start: int(start),
End: int(end),
})
}
//export Java_org_gioui_GioView_imeReplace
func Java_org_gioui_GioView_imeReplace(env *C.JNIEnv, class C.jclass, handle C.jlong, start, end C.jint, jtext C.jstring) {
w := views[handle]
r := key.Range{Start: int(start), End: int(end)}
text := goString(env, jtext)
w.callbacks.EditorReplace(r, text)
}
func (w *window) EditorStateChanged(old, new editorState) {
runInJVM(javaVM(), func(env *C.JNIEnv) {
if old.Snippet != new.Snippet {
callVoidMethod(env, w.view, gioView.restartInput)
return
}
if old.Selection != new.Selection {
w.callbacks.SetComposingRegion(key.Range{Start: -1, End: -1})
}
callVoidMethod(env, w.view, gioView.updateSelection)
})
}
func (w *window) ShowTextInput(show bool) {
runInJVM(javaVM(), func(env *C.JNIEnv) {
if show {
@@ -1002,6 +1108,7 @@ func (w *window) SetInputHint(mode key.InputHint) {
// Constants defined at https://developer.android.com/reference/android/text/InputType.
const (
TYPE_NULL = 0
TYPE_CLASS_TEXT = 1
TYPE_CLASS_NUMBER = 2
TYPE_NUMBER_FLAG_DECIMAL = 8192
TYPE_NUMBER_FLAG_SIGNED = 4096
@@ -1015,14 +1122,9 @@ func (w *window) SetInputHint(mode key.InputHint) {
case key.HintNumeric:
m = TYPE_CLASS_NUMBER | TYPE_NUMBER_FLAG_DECIMAL | TYPE_NUMBER_FLAG_SIGNED
default:
// TYPE_NULL, since TYPE_CLASS_TEXT isn't currently supported.
m = TYPE_NULL
m = TYPE_CLASS_TEXT
}
// The TYPE_TEXT_FLAG_NO_SUGGESTIONS and TYPE_TEXT_VARIATION_VISIBLE_PASSWORD are used to fix the
// Samsung keyboard compatibility, forcing to disable the suggests/auto-complete. gio#116.
m = m | TYPE_TEXT_FLAG_NO_SUGGESTIONS | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
callVoidMethod(env, w.view, gioView.setInputHint, m)
})
}