diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor
index 8bfa1d6014..1c88f35106 100644
--- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor
+++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor
@@ -16,7 +16,7 @@
- _client != null;
+ public bool IsComposing { get; private set; }
+
internal INativeControlHostImpl GetNativeControlHostImpl()
{
return _nativeControlHost ?? throw new InvalidOperationException("Blazor View wasn't initialized yet");
@@ -231,20 +234,6 @@ namespace Avalonia.Web.Blazor
}
}
- private void OnInput(ChangeEventArgs e)
- {
- if (e.Value != null)
- {
- var inputData = e.Value.ToString();
- if (inputData != null)
- {
- _topLevelImpl.RawTextEvent(inputData);
- }
- }
-
- _inputHelper?.Clear();
- }
-
[Parameter(CaptureUnmatchedValues = true)]
public IReadOnlyDictionary? AdditionalAttributes { get; set; }
@@ -261,6 +250,7 @@ namespace Avalonia.Web.Blazor
_inputHelper = new InputHelperInterop(_avaloniaModule, _inputElement);
_inputHelper.CompositionEvent += InputHelperOnCompositionEvent;
+ _inputHelper.InputEvent += InputHelperOnInputEvent;
HideIme();
_canvasHelper.SetCursor("default");
@@ -333,6 +323,16 @@ namespace Avalonia.Web.Blazor
}
}
+ private void InputHelperOnInputEvent(object? sender, WebInputEventArgs e)
+ {
+ if (IsComposing)
+ {
+ return;
+ }
+
+ _topLevelImpl.RawTextEvent(e.Data);
+ }
+
private void InputHelperOnCompositionEvent(object? sender, WebCompositionEventArgs e)
{
if(_client == null)
@@ -344,12 +344,15 @@ namespace Avalonia.Web.Blazor
{
case WebCompositionEventArgs.WebCompositionEventType.Start:
_client.SetPreeditText(null);
+ IsComposing = true;
break;
case WebCompositionEventArgs.WebCompositionEventType.Update:
_client?.SetPreeditText(e.Data);
break;
case WebCompositionEventArgs.WebCompositionEventType.End:
+ IsComposing = false;
_client?.SetPreeditText(null);
+ _topLevelImpl.RawTextEvent(e.Data);
break;
}
}
@@ -462,9 +465,12 @@ namespace Avalonia.Web.Blazor
private void SurroundingTextChanged(object? sender, EventArgs e)
{
- var surroundingText = _client.SurroundingText;
+ if(_client != null && IsComposing)
+ {
+ var surroundingText = _client.SurroundingText;
- _inputHelper?.SetSurroundingText(surroundingText.Text, surroundingText.AnchorOffset, surroundingText.CursorOffset);
+ _inputHelper?.SetSurroundingText(surroundingText.Text, surroundingText.AnchorOffset, surroundingText.CursorOffset);
+ }
}
public void SetCursorRect(Rect rect)
diff --git a/src/Web/Avalonia.Web.Blazor/Interop/InputHelperInterop.cs b/src/Web/Avalonia.Web.Blazor/Interop/InputHelperInterop.cs
index bd4e3f92f6..2dbc2027ab 100644
--- a/src/Web/Avalonia.Web.Blazor/Interop/InputHelperInterop.cs
+++ b/src/Web/Avalonia.Web.Blazor/Interop/InputHelperInterop.cs
@@ -1,5 +1,4 @@
-using System.Diagnostics;
-using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace Avalonia.Web.Blazor.Interop
@@ -30,6 +29,19 @@ namespace Avalonia.Web.Blazor.Interop
public string Data { get; }
}
+
+ internal class WebInputEventArgs
+ {
+ public WebInputEventArgs(string type, string data)
+ {
+ Type = type;
+ Data = data;
+ }
+
+ public string Type { get; }
+
+ public string Data { get; }
+ }
internal class InputHelperInterop
{
@@ -39,23 +51,29 @@ namespace Avalonia.Web.Blazor.Interop
private const string HideSymbol = "InputHelper.hide";
private const string ShowSymbol = "InputHelper.show";
private const string StartSymbol = "InputHelper.start";
+ private const string SetSurroundingTextSymbol = "InputHelper.setSurroundingText";
private readonly AvaloniaModule _module;
private readonly ElementReference _inputElement;
- private readonly ActionHelper _actionHelper;
- private DotNetObjectReference>? callbackReference;
+ private readonly ActionHelper _compositionAction;
+ private readonly ActionHelper _inputAction;
+
+ private DotNetObjectReference>? compositionActionReference;
+ private DotNetObjectReference>? inputActionReference;
public InputHelperInterop(AvaloniaModule module, ElementReference inputElement)
{
_module = module;
_inputElement = inputElement;
- _actionHelper = new ActionHelper(OnCompositionEvent);
-
+ _compositionAction = new ActionHelper(OnCompositionEvent);
+ _inputAction = new ActionHelper(OnInputEvent);
+
Start();
}
- public event EventHandler? CompositionEvent;
+ public event EventHandler? CompositionEvent;
+ public event EventHandler? InputEvent;
private void OnCompositionEvent(string type, string data)
{
@@ -63,6 +81,12 @@ namespace Avalonia.Web.Blazor.Interop
CompositionEvent?.Invoke(this, new WebCompositionEventArgs(type, data));
}
+ private void OnInputEvent(string type, string data)
+ {
+ Console.WriteLine($"InputEvent Handler Helper {InputEvent == null} ");
+ InputEvent?.Invoke(this, new WebInputEventArgs(type, data));
+ }
+
public void Clear() => _module.Invoke(ClearSymbol, _inputElement);
public void Focus() => _module.Invoke(FocusSymbol, _inputElement);
@@ -75,12 +99,21 @@ namespace Avalonia.Web.Blazor.Interop
private void Start()
{
- if(callbackReference != null)
+ if(compositionActionReference != null)
+ {
return;
-
- callbackReference = DotNetObjectReference.Create(_actionHelper);
+ }
+
+ compositionActionReference = DotNetObjectReference.Create(_compositionAction);
- _module.Invoke(StartSymbol, _inputElement, callbackReference);
+ inputActionReference = DotNetObjectReference.Create(_inputAction);
+
+ _module.Invoke(StartSymbol, _inputElement, compositionActionReference, inputActionReference);
+ }
+
+ public void SetSurroundingText(string text, int start, int end)
+ {
+ _module.Invoke(SetSurroundingTextSymbol, _inputElement, text, start, end);
}
}
}
diff --git a/src/Web/Avalonia.Web.Blazor/webapp/modules/Avalonia/InputHelper.ts b/src/Web/Avalonia.Web.Blazor/webapp/modules/Avalonia/InputHelper.ts
index 409fdebae9..c38eb66e67 100644
--- a/src/Web/Avalonia.Web.Blazor/webapp/modules/Avalonia/InputHelper.ts
+++ b/src/Web/Avalonia.Web.Blazor/webapp/modules/Avalonia/InputHelper.ts
@@ -1,13 +1,18 @@
export class InputHelper {
- static callback?: DotNet.DotNetObject;
+ static inputCallback?: DotNet.DotNetObject;
+ static compositionCallback?: DotNet.DotNetObject
- public static start(inputElement: HTMLInputElement, callback: DotNet.DotNetObject)
- {
- InputHelper.callback = callback;
+ public static start(inputElement: HTMLInputElement, compositionCallback: DotNet.DotNetObject, inputCallback: DotNet.DotNetObject)
+ {
+ InputHelper.compositionCallback = compositionCallback;
inputElement.addEventListener('compositionstart', InputHelper.onCompositionEvent);
inputElement.addEventListener('compositionupdate', InputHelper.onCompositionEvent);
- inputElement.addEventListener('compositionend', InputHelper.onCompositionEvent);
+ inputElement.addEventListener('compositionend', InputHelper.onCompositionEvent);
+
+ InputHelper.inputCallback = inputCallback;
+
+ inputElement.addEventListener('input', InputHelper.onInputEvent);
}
public static clear(inputElement: HTMLInputElement) {
@@ -30,9 +35,18 @@
inputElement.style.display = 'block';
}
+ public static setSurroundingText(inputElement: HTMLInputElement, text: string, start: number, end: number) {
+ if (!inputElement) {
+ return;
+ }
+
+ inputElement.value = text;
+ inputElement.setSelectionRange(start, end);
+ }
+
private static onCompositionEvent(ev: CompositionEvent)
{
- if(!InputHelper.callback)
+ if(!InputHelper.compositionCallback)
return;
switch (ev.type)
@@ -40,9 +54,18 @@
case "compositionstart":
case "compositionupdate":
case "compositionend":
- InputHelper.callback.invokeMethod('Invoke', ev.type, ev.data);
+ InputHelper.compositionCallback.invokeMethod('Invoke', ev.type, ev.data);
break;
}
}
+
+ private static onInputEvent(ev: Event) {
+ if (!InputHelper.inputCallback)
+ return;
+
+ var inputEvent = ev as InputEvent;
+
+ InputHelper.inputCallback.invokeMethod('Invoke', ev.type, inputEvent.data);
+ }
}