dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.26k stars 1.76k forks source link

Editor Problems: (1) Events needed to catch when Android keyboard is manually closed by user are missing from Lifecycle, and (2) Editor starts up with flashing cursor (focused) #18535

Open jonmdev opened 1 year ago

jonmdev commented 1 year ago

Description

Two problems are seen regarding Focus of Editor objects:

1) Android functions necessary to capture the user's close button click of the on screen keyboard are missing from Maui. 2) Editors start up in Android/Windows/iOS already focused (or appearing focused) with a blinking cursor in them.

This is demonstrated by the bug project below with the following code in MauiProgram.cs:

using Microsoft.Extensions.Logging;
using Microsoft.Maui.LifecycleEvents;
using System.Diagnostics;

namespace Android_Editor_Close_Bug {
    public static class MauiProgram {
        public static MauiApp CreateMauiApp() {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                .ConfigureFonts(fonts => {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                    fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                });
#if ANDROID

            builder.ConfigureLifecycleEvents(events => {
                //https://github.com/dotnet/docs-maui/blob/main/docs/fundamentals/app-lifecycle.md
                events.AddAndroid(android => android.OnBackPressed((activity) => backButtonPressed(null) && false));

                //THIS IS MISSING THE onKeyDown, onKeyUp, dispatchKeyEvent, and/or dispatchKeyEventPreIme EVENTS WE WOULD NEED TO CATCH TO MAKE THIS WORK:
                //https://stackoverflow.com/questions/3940127/intercept-back-button-from-soft-keyboard
                //https://stackoverflow.com/questions/3988478/block-back-button-in-android/3988567

                //ONBACK PRESSED IS NOT CAPTURED BY SOFT KEYBOARD CLOSURE, ONLY BACK PRESS ONCE KEYBOARD ALREADY CLOSED

            });

            bool backButtonPressed(string eventName, string type = null) {
                Debug.WriteLine("====== BACK BUTTON PRESSED"); //this only occurs on pure back button, not soft keyboard cancel (when keyboard open not called)
                TestPage.Instance.editor.Unfocus(); //will not work on keyboard close as will not then be invoked
                return true;
            }

#endif
#if DEBUG
            builder.Logging.AddDebug();
#endif

            return builder.Build();
        }
    }
}

And the following code in App.xaml.cs:

using System.Diagnostics;

namespace Android_Editor_Close_Bug {
    public partial class App : Application {
        public App() {
            InitializeComponent();
            MainPage = TestPage.Instance;
        }
    }

    public class TestPage : ContentPage {

        private static readonly Lazy<TestPage> lazy = new Lazy<TestPage>(() => new TestPage());
        public static TestPage Instance { get { return lazy.Value; } }

        public Editor editor;

        private TestPage() {
            VerticalStackLayout vert = new();
            this.Content = vert;

            Border border = new();
            border.StrokeThickness = 4;
            border.BackgroundColor = Colors.DarkBlue;
            border.Stroke = Colors.Red;
            border.Padding = 10;
            vert.Children.Add(border);

            editor = new();
            editor.BackgroundColor = Colors.White;
            editor.AutoSize = EditorAutoSizeOption.TextChanges;
            editor.MaximumHeightRequest = 200;
            border.Content = editor;

            editor.Focused += delegate {
                Debug.WriteLine("======= EDITOR FOCUSED");
            };

            editor.Unfocused += delegate {
                Debug.WriteLine("======= EDITOR UN-FOCUSED"); //no way to trigger this when closing soft keyboard as back buton event not invoked by this in MauiProgram
            };
        }
    }

}

The main Android problem is described by these links:

https://stackoverflow.com/questions/3940127/intercept-back-button-from-soft-keyboard https://stackoverflow.com/questions/3988478/block-back-button-in-android/3988567

To summarize, android.OnBackPressed is not called when the back button is clicked if the keyboard is open. We need some combination of: onKeyDown, onKeyUp, dispatchKeyEvent, and/or dispatchKeyEventPreIme to capture the close command to the soft keyboard in Android.

None of these are accessible via the API: https://github.com/dotnet/docs-maui/blob/main/docs/fundamentals/app-lifecycle.md

Since we cannot inherit from Android Application to override these events in the Maui program build process, we then have no way to access these events.

Any fix would be appreciated. Adding the missing functions/events to the Lifecycle API in Android would fix it.

It is also noted as a secondary issue that when you play the project in Android or Windows and I believe iOS, it will start up with the Editor focused with a blinking cursor even though there is no code requesting it to be focused anywhere. The project should start up with no blinking cursor and no Editor focused.

Steps to Reproduce

  1. Open demo project and press play building to real Android device.
  2. Note that the Editor will start up with a flashing cursor in it, even though nothing has been done to focus it (same in other platforms - general Maui issue likely).
  3. Click the Editor in Android to run the focus event and see the Debug output this has occurred correctly.
  4. Click the back button on the bottom nav bar (ie. close the onscreen keyboard) and see that the Editor has not been unfocused as the keyboard close event has not been captured by android.OnBackPressed, as is known to be the case.
  5. Click the back button while the keyboard is now closed and you will leave the app, but if you return you will find the Editor is now finally defocused and the Debug output for defocusing it will have run on this click (onBackPressed only runs when the keyboard is already closed).
  6. See these links to see the functions missing and needed in the Builder to access the correct events:

https://stackoverflow.com/questions/3940127/intercept-back-button-from-soft-keyboard https://stackoverflow.com/questions/3988478/block-back-button-in-android/3988567

Link to public reproduction project repository

https://github.com/jonmdev/Android-Editor-Close-Bug

Version with bug

8.0.96

Is this a regression from previous behavior?

No, this is something new

Affected platforms

iOS, Android, Windows

Did you find any workaround?

Correct behavior needs the missing functions added here:

https://github.com/dotnet/docs-maui/blob/main/docs/fundamentals/app-lifecycle.md

PureWeen commented 1 year ago

Duplicate of #16357

We can't have unfocusing an entry be a side effect of closing the SoftKeyboard for various a11y reasons, but we do need to supply an API that will let users fill in what they were using the unfocused event for. Which is what the issue linked above should do.

Editor starts up with flashing cursor (focused)

Something has to have focus. The only way to give nothing focus is to give something wrong focus. In XF we would focus the page but this horribly broke accessibility. It doesn't really make sense from an a11y perspective to completely unfocus anything on the screen. iOS does a "better job" of implementing this concept because it can resign most first responders but it will still remember where you left off last when you engage VO or keyboard commands.

ghost commented 1 year ago

Hi @jonmdev. We have added the "s/needs-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

SarthakB26 commented 1 year ago

Most of the developers doesn't care if entry unfocused on closing keyboard or not. They just need events when an entry keyboard is opening and closing that's all for that specific entry only.

SarthakB26 commented 11 months ago

since unfocus event is not possible now. Is there any way I can know when keyboard is closing and opening for a specific entry that would be enough for me to serve as unfocus event.

I am migrating a very big application which depends heavily on entry unfocus event I can't implement user stopped typing behavior at every place it would not get approved

for now android is priority I am fine with writing native code.

If anyone achieved it kindly let me know how

Thanks

ninachen03 commented 7 months ago

Verified this issue with Visual Studio 17.10.0 Preview 4 (8.0.0-rc.2.9530 & 8.0.21).I can repro this issue with sample project.