diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml
index f15ac8ffd6..dec5f74da8 100644
--- a/samples/ControlCatalog/Pages/TextBoxPage.xaml
+++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml
@@ -18,7 +18,7 @@
-
+
diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml.cs b/samples/ControlCatalog/Pages/TextBoxPage.xaml.cs
index 9eeefebb02..cd5f790312 100644
--- a/samples/ControlCatalog/Pages/TextBoxPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml.cs
@@ -13,12 +13,6 @@ namespace ControlCatalog.Pages
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
-
- this.Get("numericWatermark")
- .TextInputOptionsQuery += (s, a) =>
- {
- a.ContentType = Avalonia.Input.TextInput.TextInputContentType.Number;
- };
}
}
}
diff --git a/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs b/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs
index a7e83140ae..640befba62 100644
--- a/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs
+++ b/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs
@@ -198,9 +198,9 @@ namespace Avalonia.FreeDesktop.DBusIme
UpdateActive();
}
- void ITextInputMethodImpl.SetActive(bool active)
+ void ITextInputMethodImpl.SetActive(ITextInputMethodClient client)
{
- _controlActive = active;
+ _controlActive = client is { };
UpdateActive();
}
diff --git a/src/Avalonia.Input/ApiCompatBaseline.txt b/src/Avalonia.Input/ApiCompatBaseline.txt
index 270c5305e5..32cd7ae1ba 100644
--- a/src/Avalonia.Input/ApiCompatBaseline.txt
+++ b/src/Avalonia.Input/ApiCompatBaseline.txt
@@ -4,11 +4,17 @@ MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.Gestures.RightTappedEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.Gestures.TappedEvent' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.IFocusManager.RemoveFocusScope(Avalonia.Input.IFocusScope)' is present in the implementation but not in the contract.
+MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.InputElement.TextInputOptionsQueryEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.InputElement.DoubleTappedEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.InputElement.TappedEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_DoubleTapped(System.EventHandler)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_Tapped(System.EventHandler)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_TextInputOptionsQuery(System.EventHandler)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Input.InputElement.remove_DoubleTapped(System.EventHandler)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Input.InputElement.remove_Tapped(System.EventHandler)' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public void Avalonia.Input.InputElement.remove_TextInputOptionsQuery(System.EventHandler)' does not exist in the implementation but it does exist in the contract.
+InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetActive(Avalonia.Input.TextInput.ITextInputMethodClient)' is present in the implementation but not in the contract.
+InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetActive(System.Boolean)' is present in the contract but not in the implementation.
+MembersMustExist : Member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetActive(System.Boolean)' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Platform.IStandardCursorFactory' does not exist in the implementation but it does exist in the contract.
-Total Issues: 12
+Total Issues: 18
diff --git a/src/Avalonia.Input/InputElement.cs b/src/Avalonia.Input/InputElement.cs
index 5ec0bd6ee4..6bc9294ddd 100644
--- a/src/Avalonia.Input/InputElement.cs
+++ b/src/Avalonia.Input/InputElement.cs
@@ -126,14 +126,6 @@ namespace Avalonia.Input
RoutedEvent.Register(
"TextInputMethodClientRequested",
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
-
- ///
- /// Defines the event.
- ///
- public static readonly RoutedEvent TextInputOptionsQueryEvent =
- RoutedEvent.Register(
- "TextInputOptionsQuery",
- RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
///
/// Defines the event.
@@ -283,15 +275,6 @@ namespace Avalonia.Input
add { AddHandler(TextInputMethodClientRequestedEvent, value); }
remove { RemoveHandler(TextInputMethodClientRequestedEvent, value); }
}
-
- ///
- /// Occurs when an input element gains input focus and input method is asking for required content options
- ///
- public event EventHandler? TextInputOptionsQuery
- {
- add { AddHandler(TextInputOptionsQueryEvent, value); }
- remove { RemoveHandler(TextInputOptionsQueryEvent, value); }
- }
///
/// Occurs when the pointer enters the control.
diff --git a/src/Avalonia.Input/Properties/AssemblyInfo.cs b/src/Avalonia.Input/Properties/AssemblyInfo.cs
index 433f821ca3..6a68bf60d1 100644
--- a/src/Avalonia.Input/Properties/AssemblyInfo.cs
+++ b/src/Avalonia.Input/Properties/AssemblyInfo.cs
@@ -2,4 +2,5 @@ using System.Reflection;
using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Input")]
+[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Input.TextInput")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Input.GestureRecognizers")]
diff --git a/src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs b/src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs
index 2d24ed30a0..99edb1f83a 100644
--- a/src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs
+++ b/src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs
@@ -2,7 +2,7 @@ namespace Avalonia.Input.TextInput
{
public interface ITextInputMethodImpl
{
- void SetActive(bool active);
+ void SetActive(ITextInputMethodClient? client);
void SetCursorRect(Rect rect);
void SetOptions(TextInputOptionsQueryEventArgs options);
void Reset();
diff --git a/src/Avalonia.Input/TextInput/InputMethodManager.cs b/src/Avalonia.Input/TextInput/InputMethodManager.cs
index 64422a7fdf..93af84d5a0 100644
--- a/src/Avalonia.Input/TextInput/InputMethodManager.cs
+++ b/src/Avalonia.Input/TextInput/InputMethodManager.cs
@@ -35,21 +35,25 @@ namespace Avalonia.Input.TextInput
{
_client.CursorRectangleChanged += OnCursorRectangleChanged;
_client.TextViewVisualChanged += OnTextViewVisualChanged;
- var optionsQuery = new TextInputOptionsQueryEventArgs
- {
- RoutedEvent = InputElement.TextInputOptionsQueryEvent
- };
- _focusedElement?.RaiseEvent(optionsQuery);
+
_im?.Reset();
- _im?.SetOptions(optionsQuery);
- _transformTracker?.SetVisual(_client?.TextViewVisual);
+
+ if (_focusedElement is AvaloniaObject target)
+ {
+ var options =
+ new TextInputOptionsQueryEventArgs { ContentType = TextInputOptions.GetContentType(target) };
+
+ _im?.SetOptions(options);
+ }
+
+ _transformTracker.SetVisual(_client?.TextViewVisual);
UpdateCursorRect();
- _im?.SetActive(true);
+ _im?.SetActive(_client);
}
else
{
- _im?.SetActive(false);
+ _im?.SetActive(null);
_transformTracker.SetVisual(null);
}
}
@@ -91,12 +95,15 @@ namespace Avalonia.Input.TextInput
_focusedElement = element;
var inputMethod = (element?.VisualRoot as ITextInputMethodRoot)?.InputMethod;
- if (_im != inputMethod)
- _im?.SetActive(false);
-
+
_im = inputMethod;
TryFindAndApplyClient();
+
+ if (_im != inputMethod)
+ {
+ _im?.SetActive(Client);
+ }
}
private void TryFindAndApplyClient()
diff --git a/src/Avalonia.Input/TextInput/TextInputOptions.cs b/src/Avalonia.Input/TextInput/TextInputOptions.cs
new file mode 100644
index 0000000000..8e144e1cfb
--- /dev/null
+++ b/src/Avalonia.Input/TextInput/TextInputOptions.cs
@@ -0,0 +1,37 @@
+namespace Avalonia.Input.TextInput;
+
+public class TextInputOptions
+{
+ ///
+ /// Defines the property.
+ ///
+ public static readonly AttachedProperty ContentTypeProperty =
+ AvaloniaProperty.RegisterAttached(
+ "ContentType",
+ defaultValue: TextInputContentType.Normal,
+ inherits: true);
+
+
+ ///
+ /// Sets the value of the attached on a control.
+ ///
+ /// The control.
+ /// The property value to set.
+ public static void SetContentType(AvaloniaObject avaloniaObject, TextInputContentType value)
+ {
+ avaloniaObject.SetValue(ContentTypeProperty, value);
+
+
+ }
+
+ ///
+ /// Gets the value of the attached on a control.
+ ///
+ /// The control.
+ /// The font family.
+ public static TextInputContentType GetContentType(AvaloniaObject avaloniaObject)
+ {
+ return avaloniaObject.GetValue(ContentTypeProperty);
+ }
+
+}
diff --git a/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs b/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs
index cd298efd30..e3a33ff2b4 100644
--- a/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs
+++ b/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs
@@ -1,20 +1,41 @@
using Foundation;
using ObjCRuntime;
-using UIKit;
using Avalonia.Input.TextInput;
using Avalonia.Input;
using Avalonia.Input.Raw;
+using UIKit;
namespace Avalonia.iOS;
+#nullable enable
+
+[Adopts("UITextInputTraits")]
[Adopts("UIKeyInput")]
public partial class AvaloniaView : ITextInputMethodImpl
{
+ private ITextInputMethodClient? _currentClient;
+
public override bool CanResignFirstResponder => true;
public override bool CanBecomeFirstResponder => true;
- public override bool CanBecomeFocused => true;
- [Export("hasText")] public bool HasText => false;
+ [Export("hasText")]
+ public bool HasText
+ {
+ get
+ {
+ if (_currentClient is { } && _currentClient.SupportsSurroundingText &&
+ _currentClient.SurroundingText.Text.Length > 0)
+ {
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ [Export("keyboardType")] public UIKeyboardType KeyboardType { get; private set; } = UIKeyboardType.Default;
+
+ [Export("isSecureTextEntry")] public bool IsSecureEntry { get; private set; }
[Export("insertText:")]
public void InsertText(string text)
@@ -24,7 +45,6 @@ public partial class AvaloniaView : ITextInputMethodImpl
_topLevelImpl.Input?.Invoke(new RawTextInputEventArgs(KeyboardDevice.Instance,
0, InputRoot, text));
}
-
}
[Export("deleteBackward")]
@@ -41,13 +61,13 @@ public partial class AvaloniaView : ITextInputMethodImpl
}
}
- void ITextInputMethodImpl.SetActive(bool active)
+ void ITextInputMethodImpl.SetActive(ITextInputMethodClient? client)
{
- if (active)
+ _currentClient = client;
+
+ if (client is { })
{
- var isFr = IsFirstResponder;
- var next = NextResponder;
- var result = BecomeFirstResponder();
+ BecomeFirstResponder();
}
else
{
@@ -57,16 +77,43 @@ public partial class AvaloniaView : ITextInputMethodImpl
void ITextInputMethodImpl.SetCursorRect(Rect rect)
{
-
+
}
void ITextInputMethodImpl.SetOptions(TextInputOptionsQueryEventArgs options)
{
-
+ switch (options.ContentType)
+ {
+ case TextInputContentType.Email:
+ KeyboardType = UIKeyboardType.EmailAddress;
+ break;
+
+ case TextInputContentType.Number:
+ KeyboardType = UIKeyboardType.NumberPad;
+ break;
+
+ case TextInputContentType.Password:
+ IsSecureEntry = true;
+ break;
+
+ case TextInputContentType.Phone:
+ KeyboardType = UIKeyboardType.PhonePad;
+ break;
+
+ case TextInputContentType.Url:
+ KeyboardType = UIKeyboardType.Url;
+ break;
+
+ case TextInputContentType.Normal:
+ KeyboardType = UIKeyboardType.Default;
+ break;
+ }
}
void ITextInputMethodImpl.Reset()
{
-
+ IsSecureEntry = false;
+ KeyboardType = UIKeyboardType.Default;
+ ResignFirstResponder();
}
}