diff --git a/src/Browser/Avalonia.Browser/AvaloniaView.cs b/src/Browser/Avalonia.Browser/AvaloniaView.cs index 294216ee03..16c2b2a0b4 100644 --- a/src/Browser/Avalonia.Browser/AvaloniaView.cs +++ b/src/Browser/Avalonia.Browser/AvaloniaView.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices.JavaScript; using Avalonia.Browser.Interop; @@ -15,6 +16,7 @@ using Avalonia.Platform; using Avalonia.Rendering.Composition; using Avalonia.Threading; using SkiaSharp; +using static System.Runtime.CompilerServices.RuntimeHelpers; namespace Avalonia.Browser { @@ -94,6 +96,7 @@ namespace Avalonia.Browser InputHelper.SubscribeTextEvents( _inputElement, + OnBeforeInput, OnTextInput, OnCompositionStart, OnCompositionUpdate, @@ -316,11 +319,37 @@ namespace Avalonia.Browser return _topLevelImpl.RawTextEvent(data); } + private bool OnBeforeInput(JSObject arg, int start, int end) + { + var type = arg.GetPropertyAsString("inputType"); + Console.WriteLine(type); + if (type != "deleteByComposition") + { + if (type == "deleteContentBackward") + { + start = _inputElement.GetPropertyAsInt32("selectionStart"); + end = _inputElement.GetPropertyAsInt32("selectionEnd"); + } + else + { + start = -1; + end = -1; + } + } + + if(start != -1 && end != -1 && _client != null) + { + _client.SelectInSurroundingText(start, end); + } + return false; + } + private bool OnCompositionStart (JSObject args) { if (_client == null) return false; + Console.WriteLine("composition start"); _client.SetPreeditText(null); IsComposing = true; @@ -331,6 +360,7 @@ namespace Avalonia.Browser { if (_client == null) return false; + Console.WriteLine("composition update"); _client.SetPreeditText(args.GetPropertyAsString("data")); @@ -342,6 +372,7 @@ namespace Avalonia.Browser if (_client == null) return false; + Console.WriteLine("composition end"); IsComposing = false; _client.SetPreeditText(null); _topLevelImpl.RawTextEvent(args.GetPropertyAsString("data")!); diff --git a/src/Browser/Avalonia.Browser/Interop/InputHelper.cs b/src/Browser/Avalonia.Browser/Interop/InputHelper.cs index 7a010dc782..a816e39da8 100644 --- a/src/Browser/Avalonia.Browser/Interop/InputHelper.cs +++ b/src/Browser/Avalonia.Browser/Interop/InputHelper.cs @@ -18,6 +18,8 @@ internal static partial class InputHelper [JSImport("InputHelper.subscribeTextEvents", AvaloniaModule.MainModuleName)] public static partial void SubscribeTextEvents( JSObject htmlElement, + [JSMarshalAs>] + Func onBeforeInput, [JSMarshalAs>] Func onInput, [JSMarshalAs>] diff --git a/src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts b/src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts index 83e8ee7f1c..0f0e5eb512 100644 --- a/src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts +++ b/src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts @@ -47,6 +47,7 @@ export class InputHelper { public static subscribeTextEvents( element: HTMLInputElement, + beforeInputCallback: (args: InputEvent, start: number, end: number) => boolean, inputCallback: (type: string, data: string | null) => boolean, compositionStartCallback: (args: CompositionEvent) => boolean, compositionUpdateCallback: (args: CompositionEvent) => boolean, @@ -68,6 +69,25 @@ export class InputHelper { }; element.addEventListener("compositionstart", compositionStartHandler); + const beforeInputHandler = (args: InputEvent) => { + const ranges = args.getTargetRanges(); + let start = -1; + let end = -1; + if (ranges.length > 0) { + start = ranges[0].startOffset; + end = ranges[0].endOffset; + } + + if (args.inputType === "insertCompositionText") { + start = 2; + end = start + 2; + } + if (beforeInputCallback(args, start, end)) { + args.preventDefault(); + } + }; + element.addEventListener("beforeinput", beforeInputHandler); + const compositionUpdateHandler = (args: CompositionEvent) => { if (compositionUpdateCallback(args)) { args.preventDefault();