From db28ac75379c1e40ec6359633d6cae535e4e80ee Mon Sep 17 00:00:00 2001 From: inkeliz Date: Sun, 9 Jun 2024 00:34:47 +0100 Subject: [PATCH] app,io,widget: [android/macos] fix focus issues This patch is intended to fix two issues related to focus and software-keyboard. The focus is now reseted if it's lost due to external event, such as clicking on non-Gio window/activity/fragment. The software-keyboard will now re-open when clicked, except if it's ReadOnly. On macOS it will request focus again if the focus is lose due to another View in the same Window. However, currently, it's done by using ShowTextInput. Fixes: https://todo.sr.ht/~eliasnaur/gio/591 Signed-off-by: inkeliz --- app/os_macos.go | 11 ++++++++++- app/os_macos.m | 20 ++++++++++++++++---- io/input/router.go | 8 ++++++++ widget/editor.go | 5 ++++- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/app/os_macos.go b/app/os_macos.go index 1da5083fd..73a063e6c 100644 --- a/app/os_macos.go +++ b/app/os_macos.go @@ -297,6 +297,11 @@ static void invalidateCharacterCoordinates(CFTypeRef viewRef) { } } } + +static void setFocus(CFTypeRef viewRef) { + NSView *view = (__bridge NSView *)viewRef; + [view.window makeFirstResponder:view]; +} */ import "C" @@ -514,7 +519,11 @@ func (w *window) EditorStateChanged(old, new editorState) { } } -func (w *window) ShowTextInput(show bool) {} +func (w *window) ShowTextInput(show bool) { + if show && !w.config.Focused { + C.setFocus(w.view) + } +} func (w *window) SetInputHint(_ key.InputHint) {} diff --git a/app/os_macos.m b/app/os_macos.m index 0a3f62629..0527fb134 100644 --- a/app/os_macos.m +++ b/app/os_macos.m @@ -47,13 +47,17 @@ - (void)windowDidChangeScreen:(NSNotification *)notification { } - (void)windowDidBecomeKey:(NSNotification *)notification { NSWindow *window = (NSWindow *)[notification object]; - GioView *view = (GioView *)window.contentView; - gio_onFocus(view.handle, 1); + GioView *view = (GioView *)window.contentView; + if ([window firstResponder] == view) { + gio_onFocus(view.handle, 1); + } } - (void)windowDidResignKey:(NSNotification *)notification { NSWindow *window = (NSWindow *)[notification object]; - GioView *view = (GioView *)window.contentView; - gio_onFocus(view.handle, 0); + GioView *view = (GioView *)window.contentView; + if ([window firstResponder] == view) { + gio_onFocus(view.handle, 0); + } } @end @@ -205,6 +209,14 @@ - (void)applicationDidHide:(NSNotification *)notification { - (void)dealloc { gio_onDestroy(self.handle); } +- (BOOL) becomeFirstResponder { + gio_onFocus(self.handle, 1); + return [super becomeFirstResponder]; + } +- (BOOL) resignFirstResponder { + gio_onFocus(self.handle, 0); + return [super resignFirstResponder]; +} @end // Delegates are weakly referenced from their peers. Nothing diff --git a/io/input/router.go b/io/input/router.go index 99962a1a2..4645eda8d 100644 --- a/io/input/router.go +++ b/io/input/router.go @@ -567,6 +567,14 @@ func (q *Router) changeState(e event.Event, state inputState, evts []taggedEvent e.event = de } } + for i := range evts { + e := &evts[i] + if fe, ok := e.event.(key.FocusEvent); ok { + if !fe.Focus { + state.keyState.focus = nil + } + } + } // Initialize the first change to contain the current state // and events that are bound for the current frame. if len(q.changes) == 0 { diff --git a/widget/editor.go b/widget/editor.go index 015c15de5..38783f037 100644 --- a/widget/editor.go +++ b/widget/editor.go @@ -289,6 +289,9 @@ func (e *Editor) processPointerEvent(gtx layout.Context, ev event.Event) (Editor Y: int(math.Round(float64(evt.Position.Y))), }) gtx.Execute(key.FocusCmd{Tag: e}) + if !e.ReadOnly { + gtx.Execute(key.SoftKeyboardCmd{Show: true}) + } if e.scroller.State() != gesture.StateFlinging { e.scrollCaret = true } @@ -395,7 +398,7 @@ func (e *Editor) processKey(gtx layout.Context) (EditorEvent, bool) { case key.FocusEvent: // Reset IME state. e.ime.imeState = imeState{} - if ke.Focus { + if ke.Focus && !e.ReadOnly { gtx.Execute(key.SoftKeyboardCmd{Show: true}) } case key.Event: