From ed19f5fc9a17defbf4ce56c77e70c47dc387de9e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 00:30:03 +0000 Subject: [PATCH 01/22] remove old softkey hack. --- src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs | 6 ++++ src/iOS/Avalonia.iOS/AvaloniaView.Text.cs | 32 --------------------- src/iOS/Avalonia.iOS/Platform.cs | 7 ----- src/iOS/Avalonia.iOS/SoftKeyboardHelper.cs | 24 ---------------- 4 files changed, 6 insertions(+), 63 deletions(-) create mode 100644 src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs delete mode 100644 src/iOS/Avalonia.iOS/AvaloniaView.Text.cs delete mode 100644 src/iOS/Avalonia.iOS/SoftKeyboardHelper.cs diff --git a/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs b/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs new file mode 100644 index 0000000000..7cc853312c --- /dev/null +++ b/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs @@ -0,0 +1,6 @@ +namespace Avalonia.iOS; + +public class AvaloniaUIResponder +{ + +} diff --git a/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs b/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs deleted file mode 100644 index dc963726b0..0000000000 --- a/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Avalonia.Input; -using Avalonia.Input.Raw; -using Foundation; -using ObjCRuntime; -using UIKit; - -namespace Avalonia.iOS -{ - [Adopts("UIKeyInput")] - public partial class AvaloniaView - { - public override bool CanBecomeFirstResponder => true; - - [Export("hasText")] public bool HasText => false; - - [Export("insertText:")] - public void InsertText(string text) => - _topLevelImpl.Input?.Invoke(new RawTextInputEventArgs(KeyboardDevice.Instance, - 0, InputRoot, text)); - - [Export("deleteBackward")] - public void DeleteBackward() - { - // TODO: pass this through IME infrastructure instead of emulating a backspace press - _topLevelImpl.Input?.Invoke(new RawKeyEventArgs(KeyboardDevice.Instance, - 0, InputRoot, RawKeyEventType.KeyDown, Key.Back, RawInputModifiers.None)); - - _topLevelImpl.Input?.Invoke(new RawKeyEventArgs(KeyboardDevice.Instance, - 0, InputRoot, RawKeyEventType.KeyUp, Key.Back, RawInputModifiers.None)); - } - } -} \ No newline at end of file diff --git a/src/iOS/Avalonia.iOS/Platform.cs b/src/iOS/Avalonia.iOS/Platform.cs index f8815e9030..2738e502de 100644 --- a/src/iOS/Avalonia.iOS/Platform.cs +++ b/src/iOS/Avalonia.iOS/Platform.cs @@ -44,7 +44,6 @@ namespace Avalonia.iOS GlFeature ??= new EaglFeature(); Timer ??= new DisplayLinkTimer(); var keyboard = new KeyboardDevice(); - var softKeyboard = new SoftKeyboardHelper(); AvaloniaLocator.CurrentMutable .Bind().ToConstant(GlFeature) @@ -58,12 +57,6 @@ namespace Avalonia.iOS .Bind().ToConstant(Timer) .Bind().ToConstant(new PlatformThreadingInterface()) .Bind().ToConstant(keyboard); - - keyboard.PropertyChanged += (_, changed) => - { - if (changed.PropertyName == nameof(KeyboardDevice.FocusedElement)) - softKeyboard.UpdateKeyboard(keyboard.FocusedElement); - }; } diff --git a/src/iOS/Avalonia.iOS/SoftKeyboardHelper.cs b/src/iOS/Avalonia.iOS/SoftKeyboardHelper.cs deleted file mode 100644 index b05ab280d2..0000000000 --- a/src/iOS/Avalonia.iOS/SoftKeyboardHelper.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Input; - -namespace Avalonia.iOS -{ - public class SoftKeyboardHelper - { - private AvaloniaView _oldView; - - public void UpdateKeyboard(IInputElement focusedElement) - { - if (_oldView?.IsFirstResponder == true) - _oldView?.ResignFirstResponder(); - _oldView = null; - - //TODO: Raise a routed event to determine if any control wants to become the text input handler - if (focusedElement is TextBox) - { - var view = ((focusedElement.VisualRoot as TopLevel)?.PlatformImpl as AvaloniaView.TopLevelImpl)?.View; - view?.BecomeFirstResponder(); - } - } - } -} \ No newline at end of file From d717d10de802da0df60f715c381d0786de67d5f3 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 00:31:21 +0000 Subject: [PATCH 02/22] use ime api to hide and show osk. --- src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs | 54 ++++++++++++++++++++- src/iOS/Avalonia.iOS/AvaloniaView.cs | 7 ++- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs b/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs index 7cc853312c..a687eb9bf8 100644 --- a/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs +++ b/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs @@ -1,6 +1,56 @@ +using Foundation; +using ObjCRuntime; +using UIKit; +using Avalonia.Input.TextInput; + namespace Avalonia.iOS; -public class AvaloniaUIResponder +[Adopts("UIKeyInput")] +public partial class AvaloniaView : ITextInputMethodImpl { - + public override bool CanResignFirstResponder => true; + public override bool CanBecomeFirstResponder => true; + public override bool CanBecomeFocused => true; + + [Export("hasText")] public bool HasText => false; + + [Export("insertText:")] + public void InsertText(string text) + { + + } + + [Export("deleteBackward")] + public void DeleteBackward() + { + } + + void ITextInputMethodImpl.SetActive(bool active) + { + if (active) + { + var isFr = IsFirstResponder; + var next = NextResponder; + var result = BecomeFirstResponder(); + } + else + { + ResignFirstResponder(); + } + } + + void ITextInputMethodImpl.SetCursorRect(Rect rect) + { + + } + + void ITextInputMethodImpl.SetOptions(TextInputOptionsQueryEventArgs options) + { + + } + + void ITextInputMethodImpl.Reset() + { + + } } diff --git a/src/iOS/Avalonia.iOS/AvaloniaView.cs b/src/iOS/Avalonia.iOS/AvaloniaView.cs index 5bb2f64879..e8108dd3de 100644 --- a/src/iOS/Avalonia.iOS/AvaloniaView.cs +++ b/src/iOS/Avalonia.iOS/AvaloniaView.cs @@ -2,12 +2,13 @@ using System; using System.Collections.Generic; using Avalonia.Controls; using Avalonia.Controls.Embedding; +using Avalonia.Controls.Platform; using Avalonia.Input; using Avalonia.Input.Raw; +using Avalonia.Input.TextInput; using Avalonia.Platform; using Avalonia.Rendering; using CoreAnimation; -using CoreGraphics; using Foundation; using ObjCRuntime; using OpenGLES; @@ -42,7 +43,7 @@ namespace Avalonia.iOS MultipleTouchEnabled = true; } - internal class TopLevelImpl : ITopLevelImpl + internal class TopLevelImpl : ITopLevelImplWithTextInputMethod { private readonly AvaloniaView _view; public AvaloniaView View => _view; @@ -109,6 +110,8 @@ namespace Avalonia.iOS public AcrylicPlatformCompensationLevels AcrylicCompensationLevels { get; } = new AcrylicPlatformCompensationLevels(); + + public ITextInputMethodImpl? TextInputMethod => _view; } [Export("layerClass")] From 1c8295022f5c7aa913ee3a5b56aae3af30010488 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 11:59:35 +0000 Subject: [PATCH 03/22] working basic text input ios --- src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs b/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs index a687eb9bf8..cd298efd30 100644 --- a/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs +++ b/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs @@ -2,6 +2,8 @@ using Foundation; using ObjCRuntime; using UIKit; using Avalonia.Input.TextInput; +using Avalonia.Input; +using Avalonia.Input.Raw; namespace Avalonia.iOS; @@ -17,12 +19,26 @@ public partial class AvaloniaView : ITextInputMethodImpl [Export("insertText:")] public void InsertText(string text) { - + if (KeyboardDevice.Instance is { }) + { + _topLevelImpl.Input?.Invoke(new RawTextInputEventArgs(KeyboardDevice.Instance, + 0, InputRoot, text)); + } + } [Export("deleteBackward")] public void DeleteBackward() { + if (KeyboardDevice.Instance is { }) + { + // TODO: pass this through IME infrastructure instead of emulating a backspace press + _topLevelImpl.Input?.Invoke(new RawKeyEventArgs(KeyboardDevice.Instance, + 0, InputRoot, RawKeyEventType.KeyDown, Key.Back, RawInputModifiers.None)); + + _topLevelImpl.Input?.Invoke(new RawKeyEventArgs(KeyboardDevice.Instance, + 0, InputRoot, RawKeyEventType.KeyUp, Key.Back, RawInputModifiers.None)); + } } void ITextInputMethodImpl.SetActive(bool active) From 557eb84d732c1d13722831cf97864b07c8af019b Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 12:08:36 +0000 Subject: [PATCH 04/22] update plist --- samples/ControlCatalog.iOS/Info.plist | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/ControlCatalog.iOS/Info.plist b/samples/ControlCatalog.iOS/Info.plist index d4b91b381e..6ffe3ba662 100644 --- a/samples/ControlCatalog.iOS/Info.plist +++ b/samples/ControlCatalog.iOS/Info.plist @@ -5,7 +5,7 @@ CFBundleDisplayName ControlCatalog.iOS CFBundleIdentifier - com.companyname.ControlCatalog.iOS + Avalonia.ControlCatalog CFBundleShortVersionString 1.0 CFBundleVersion @@ -39,9 +39,9 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIStatusBarHidden - - UIViewControllerBasedStatusBarAppearance - + UIStatusBarHidden + + UIViewControllerBasedStatusBarAppearance + From c7c0e7fd516e8bc3008476f2db0b771cdb204415 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 14:20:50 +0000 Subject: [PATCH 05/22] remove legacy ios sample project. --- Avalonia.sln | 27 ---- .../ControlCatalog.iOS.Legacy/AppDelegate.cs | 15 --- .../AppIcon.appiconset/Contents.json | 117 ------------------ .../ControlCatalog.iOS.Legacy.csproj | 99 --------------- .../Entitlements.plist | 6 - samples/ControlCatalog.iOS.Legacy/Info.plist | 47 ------- samples/ControlCatalog.iOS.Legacy/Main.cs | 15 --- .../Resources/LaunchScreen.xib | 43 ------- 8 files changed, 369 deletions(-) delete mode 100644 samples/ControlCatalog.iOS.Legacy/AppDelegate.cs delete mode 100644 samples/ControlCatalog.iOS.Legacy/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 samples/ControlCatalog.iOS.Legacy/ControlCatalog.iOS.Legacy.csproj delete mode 100644 samples/ControlCatalog.iOS.Legacy/Entitlements.plist delete mode 100644 samples/ControlCatalog.iOS.Legacy/Info.plist delete mode 100644 samples/ControlCatalog.iOS.Legacy/Main.cs delete mode 100644 samples/ControlCatalog.iOS.Legacy/Resources/LaunchScreen.xib diff --git a/Avalonia.sln b/Avalonia.sln index c4f64be109..a989fb828d 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -234,8 +234,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.PlatformSupport", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS.Legacy", "samples\ControlCatalog.iOS.Legacy\ControlCatalog.iOS.Legacy.csproj", "{3AF75F00-B497-4517-9491-922173DE216E}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -2214,30 +2212,6 @@ Global {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|iPhone.Build.0 = Release|Any CPU {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.AppStore|iPhone.Build.0 = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Debug|iPhone.Build.0 = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Release|Any CPU.Build.0 = Release|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Release|iPhone.ActiveCfg = Release|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Release|iPhone.Build.0 = Release|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {3AF75F00-B497-4517-9491-922173DE216E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2302,7 +2276,6 @@ Global {26A98DA1-D89D-4A95-8152-349F404DA2E2} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9} {A0D0A6A4-5C72-4ADA-9B27-621C7D94F270} = {9B9E3891-2366-4253-A952-D08BCEB71098} {70B9F5CC-E2F9-4314-9514-EDE762ACCC4B} = {9B9E3891-2366-4253-A952-D08BCEB71098} - {3AF75F00-B497-4517-9491-922173DE216E} = {9B9E3891-2366-4253-A952-D08BCEB71098} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A} diff --git a/samples/ControlCatalog.iOS.Legacy/AppDelegate.cs b/samples/ControlCatalog.iOS.Legacy/AppDelegate.cs deleted file mode 100644 index a67de98259..0000000000 --- a/samples/ControlCatalog.iOS.Legacy/AppDelegate.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Avalonia.iOS; -using Foundation; -using UIKit; - -namespace ControlCatalog.iOS.Legacy -{ - // The UIApplicationDelegate for the application. This class is responsible for launching the - // User Interface of the application, as well as listening (and optionally responding) to - // application events from iOS. - [Register("AppDelegate")] - public partial class AppDelegate : AvaloniaAppDelegate - { - - } -} diff --git a/samples/ControlCatalog.iOS.Legacy/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/ControlCatalog.iOS.Legacy/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 98f4d035c8..0000000000 --- a/samples/ControlCatalog.iOS.Legacy/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "images": [ - { - "scale": "2x", - "size": "20x20", - "idiom": "iphone", - "filename": "Icon40.png" - }, - { - "scale": "3x", - "size": "20x20", - "idiom": "iphone", - "filename": "Icon60.png" - }, - { - "scale": "2x", - "size": "29x29", - "idiom": "iphone", - "filename": "Icon58.png" - }, - { - "scale": "3x", - "size": "29x29", - "idiom": "iphone", - "filename": "Icon87.png" - }, - { - "scale": "2x", - "size": "40x40", - "idiom": "iphone", - "filename": "Icon80.png" - }, - { - "scale": "3x", - "size": "40x40", - "idiom": "iphone", - "filename": "Icon120.png" - }, - { - "scale": "2x", - "size": "60x60", - "idiom": "iphone", - "filename": "Icon120.png" - }, - { - "scale": "3x", - "size": "60x60", - "idiom": "iphone", - "filename": "Icon180.png" - }, - { - "scale": "1x", - "size": "20x20", - "idiom": "ipad", - "filename": "Icon20.png" - }, - { - "scale": "2x", - "size": "20x20", - "idiom": "ipad", - "filename": "Icon40.png" - }, - { - "scale": "1x", - "size": "29x29", - "idiom": "ipad", - "filename": "Icon29.png" - }, - { - "scale": "2x", - "size": "29x29", - "idiom": "ipad", - "filename": "Icon58.png" - }, - { - "scale": "1x", - "size": "40x40", - "idiom": "ipad", - "filename": "Icon40.png" - }, - { - "scale": "2x", - "size": "40x40", - "idiom": "ipad", - "filename": "Icon80.png" - }, - { - "scale": "1x", - "size": "76x76", - "idiom": "ipad", - "filename": "Icon76.png" - }, - { - "scale": "2x", - "size": "76x76", - "idiom": "ipad", - "filename": "Icon152.png" - }, - { - "scale": "2x", - "size": "83.5x83.5", - "idiom": "ipad", - "filename": "Icon167.png" - }, - { - "scale": "1x", - "size": "1024x1024", - "idiom": "ios-marketing", - "filename": "Icon1024.png" - } - ], - "properties": {}, - "info": { - "version": 1, - "author": "xcode" - } -} \ No newline at end of file diff --git a/samples/ControlCatalog.iOS.Legacy/ControlCatalog.iOS.Legacy.csproj b/samples/ControlCatalog.iOS.Legacy/ControlCatalog.iOS.Legacy.csproj deleted file mode 100644 index 045114ff5a..0000000000 --- a/samples/ControlCatalog.iOS.Legacy/ControlCatalog.iOS.Legacy.csproj +++ /dev/null @@ -1,99 +0,0 @@ - - - xamarin.ios10 - 15.0 - true - Debug - iPhoneSimulator - {3AF75F00-B497-4517-9491-922173DE216E} - {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Exe - ControlCatalog.iOS.Legacy - Resources - ControlCatalog.iOS.Legacy - NSUrlSessionHandler - manual - -all - - - true - full - false - bin\iPhoneSimulator\Debug - DEBUG - prompt - 4 - false - x86_64 - None - true - - - none - true - bin\iPhoneSimulator\Release - prompt - 4 - None - x86_64 - false - - - true - full - false - bin\iPhone\Debug - DEBUG - prompt - 4 - false - ARM64 - Entitlements.plist - true - - - none - true - bin\iPhone\Release - prompt - 4 - Entitlements.plist - ARM64 - false - - - - - - - - - - - - - - false - - - - - - - - {d2221c82-4a25-4583-9b43-d791e3f6820c} - Avalonia.Controls - - - {4488ad85-1495-4809-9aa4-ddfe0a48527e} - Avalonia.iOS - - - {d0a739b9-3c68-4ba6-a328-41606954b6bd} - ControlCatalog - - - - - - diff --git a/samples/ControlCatalog.iOS.Legacy/Entitlements.plist b/samples/ControlCatalog.iOS.Legacy/Entitlements.plist deleted file mode 100644 index 36a8706706..0000000000 --- a/samples/ControlCatalog.iOS.Legacy/Entitlements.plist +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/samples/ControlCatalog.iOS.Legacy/Info.plist b/samples/ControlCatalog.iOS.Legacy/Info.plist deleted file mode 100644 index 430ffb3aca..0000000000 --- a/samples/ControlCatalog.iOS.Legacy/Info.plist +++ /dev/null @@ -1,47 +0,0 @@ - - - - - CFBundleDisplayName - ControlCatalog - CFBundleIdentifier - com.companyname.ControlCatalog.iOS - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1.0 - LSRequiresIPhoneOS - - MinimumOSVersion - 15.0 - UIDeviceFamily - - 12 - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - XSAppIconAssets - Assets.xcassets/AppIcon.appiconset - UIStatusBarHidden - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/samples/ControlCatalog.iOS.Legacy/Main.cs b/samples/ControlCatalog.iOS.Legacy/Main.cs deleted file mode 100644 index 08b3831d73..0000000000 --- a/samples/ControlCatalog.iOS.Legacy/Main.cs +++ /dev/null @@ -1,15 +0,0 @@ -using UIKit; - -namespace ControlCatalog.iOS.Legacy -{ - public class Application - { - // This is the main entry point of the application. - static void Main(string[] args) - { - // if you want to use a different Application Delegate class from "AppDelegate" - // you can specify it here. - UIApplication.Main(args, null, "AppDelegate"); - } - } -} diff --git a/samples/ControlCatalog.iOS.Legacy/Resources/LaunchScreen.xib b/samples/ControlCatalog.iOS.Legacy/Resources/LaunchScreen.xib deleted file mode 100644 index 3a3df8b38e..0000000000 --- a/samples/ControlCatalog.iOS.Legacy/Resources/LaunchScreen.xib +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 005d8e522201ed2bed004a736696f20017417a30 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 14:36:02 +0000 Subject: [PATCH 06/22] dont report an inputclient if textbox is in readonly mode. --- src/Avalonia.Controls/TextBox.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs index 995ec142a5..4d71717776 100644 --- a/src/Avalonia.Controls/TextBox.cs +++ b/src/Avalonia.Controls/TextBox.cs @@ -202,7 +202,10 @@ namespace Avalonia.Controls FocusableProperty.OverrideDefaultValue(typeof(TextBox), true); TextInputMethodClientRequestedEvent.AddClassHandler((tb, e) => { - e.Client = tb._imClient; + if (!tb.IsReadOnly) + { + e.Client = tb._imClient; + } }); } From 409be7f33f892189982f85642d444e16792e6dbf Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 14:40:40 +0000 Subject: [PATCH 07/22] remove event for querying text input options. replace with attached property that is inheritable. --- samples/ControlCatalog/Pages/TextBoxPage.xaml | 3 +- .../ControlCatalog/Pages/TextBoxPage.xaml.cs | 6 -- .../DBusIme/DBusTextInputMethodBase.cs | 4 +- src/Avalonia.Input/ApiCompatBaseline.txt | 8 ++- src/Avalonia.Input/InputElement.cs | 17 ----- src/Avalonia.Input/Properties/AssemblyInfo.cs | 1 + .../TextInput/ITextInputMethodImpl.cs | 2 +- .../TextInput/InputMethodManager.cs | 31 ++++---- .../TextInput/TextInputOptions.cs | 37 ++++++++++ src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs | 71 +++++++++++++++---- 10 files changed, 128 insertions(+), 52 deletions(-) create mode 100644 src/Avalonia.Input/TextInput/TextInputOptions.cs 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(); } } From 6be7ca9653bb98e09d6f7a7acb666675729c4680 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 14:43:28 +0000 Subject: [PATCH 08/22] fix issue count. --- src/Avalonia.Visuals/ApiCompatBaseline.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/ApiCompatBaseline.txt b/src/Avalonia.Visuals/ApiCompatBaseline.txt index b74b678632..e93a2b5632 100644 --- a/src/Avalonia.Visuals/ApiCompatBaseline.txt +++ b/src/Avalonia.Visuals/ApiCompatBaseline.txt @@ -153,4 +153,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Media.GlyphR MembersMustExist : Member 'public Avalonia.Media.GlyphRun Avalonia.Platform.ITextShaperImpl.ShapeText(Avalonia.Utilities.ReadOnlySlice, Avalonia.Media.Typeface, System.Double, System.Globalization.CultureInfo)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'protected void Avalonia.Rendering.RendererBase.RenderFps(Avalonia.Platform.IDrawingContextImpl, Avalonia.Rect, System.Nullable)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Utilities.ReadOnlySlice..ctor(System.ReadOnlyMemory, System.Int32, System.Int32)' does not exist in the implementation but it does exist in the contract. -Total Issues: 153 +Total Issues: 154 From 079c193a82cac1428859c7c409d2821735745823 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 14:56:29 +0000 Subject: [PATCH 09/22] replace eventargs with simple options class. --- .../TextInput/ITextInputMethodImpl.cs | 2 +- .../TextInput/InputMethodManager.cs | 5 +- .../TextInput/TextInputOptions.cs | 195 +++++++++++++++++- .../TextInputOptionsQueryEventArgs.cs | 32 --- src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs | 2 +- 5 files changed, 191 insertions(+), 45 deletions(-) delete mode 100644 src/Avalonia.Input/TextInput/TextInputOptionsQueryEventArgs.cs diff --git a/src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs b/src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs index 99edb1f83a..729b517f88 100644 --- a/src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs +++ b/src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs @@ -4,7 +4,7 @@ namespace Avalonia.Input.TextInput { void SetActive(ITextInputMethodClient? client); void SetCursorRect(Rect rect); - void SetOptions(TextInputOptionsQueryEventArgs options); + void SetOptions(TextInputOptions options); void Reset(); } diff --git a/src/Avalonia.Input/TextInput/InputMethodManager.cs b/src/Avalonia.Input/TextInput/InputMethodManager.cs index 93af84d5a0..e2d6a1fd9f 100644 --- a/src/Avalonia.Input/TextInput/InputMethodManager.cs +++ b/src/Avalonia.Input/TextInput/InputMethodManager.cs @@ -40,10 +40,7 @@ namespace Avalonia.Input.TextInput if (_focusedElement is AvaloniaObject target) { - var options = - new TextInputOptionsQueryEventArgs { ContentType = TextInputOptions.GetContentType(target) }; - - _im?.SetOptions(options); + _im?.SetOptions(TextInputOptions.FromAvaloniaObject(target)); } _transformTracker.SetVisual(_client?.TextViewVisual); diff --git a/src/Avalonia.Input/TextInput/TextInputOptions.cs b/src/Avalonia.Input/TextInput/TextInputOptions.cs index 8e144e1cfb..c60473ad78 100644 --- a/src/Avalonia.Input/TextInput/TextInputOptions.cs +++ b/src/Avalonia.Input/TextInput/TextInputOptions.cs @@ -2,6 +2,21 @@ namespace Avalonia.Input.TextInput; public class TextInputOptions { + public static TextInputOptions FromAvaloniaObject(AvaloniaObject avaloniaObject) + { + var result = new TextInputOptions + { + ContentType = GetContentType(avaloniaObject), + Multiline = GetMultiline(avaloniaObject), + AutoCapitalization = GetAutoCapitalization(avaloniaObject), + IsSensitive = GetIsSensitive(avaloniaObject), + Lowercase = GetLowercase(avaloniaObject), + Uppercase = GetUppercase(avaloniaObject) + }; + + return result; + } + /// /// Defines the property. /// @@ -11,7 +26,6 @@ public class TextInputOptions defaultValue: TextInputContentType.Normal, inherits: true); - /// /// Sets the value of the attached on a control. /// @@ -20,18 +34,185 @@ public class TextInputOptions public static void SetContentType(AvaloniaObject avaloniaObject, TextInputContentType value) { avaloniaObject.SetValue(ContentTypeProperty, value); - - } - + /// - /// Gets the value of the attached on a control. + /// Gets the value of the attached . /// - /// The control. - /// The font family. + /// The target. + /// TextInputContentType public static TextInputContentType GetContentType(AvaloniaObject avaloniaObject) { return avaloniaObject.GetValue(ContentTypeProperty); } + /// + /// The content type (mostly for determining the shape of the virtual keyboard) + /// + public TextInputContentType ContentType { get; set; } + + /// + /// Defines the property. + /// + public static readonly AttachedProperty MultilineProperty = + AvaloniaProperty.RegisterAttached( + "Multiline", + inherits: true); + + /// + /// Sets the value of the attached on a control. + /// + /// The control. + /// The property value to set. + public static void SetMultiline(AvaloniaObject avaloniaObject, bool value) + { + avaloniaObject.SetValue(MultilineProperty, value); + } + + /// + /// Gets the value of the attached . + /// + /// The target. + /// true if multiline + public static bool GetMultiline(AvaloniaObject avaloniaObject) + { + return avaloniaObject.GetValue(MultilineProperty); + } + + /// + /// Text is multiline + /// + public bool Multiline { get; set; } + + /// + /// Defines the property. + /// + public static readonly AttachedProperty LowercaseProperty = + AvaloniaProperty.RegisterAttached( + "Lowercase", + inherits: true); + + /// + /// Sets the value of the attached on a control. + /// + /// The control. + /// The property value to set. + public static void SetLowercase(AvaloniaObject avaloniaObject, bool value) + { + avaloniaObject.SetValue(LowercaseProperty, value); + } + + /// + /// Gets the value of the attached . + /// + /// The target. + /// true if Lowercase + public static bool GetLowercase(AvaloniaObject avaloniaObject) + { + return avaloniaObject.GetValue(LowercaseProperty); + } + + /// + /// Text is in lower case + /// + public bool Lowercase { get; set; } + + /// + /// Defines the property. + /// + public static readonly AttachedProperty UppercaseProperty = + AvaloniaProperty.RegisterAttached( + "Uppercase", + inherits: true); + + /// + /// Sets the value of the attached on a control. + /// + /// The control. + /// The property value to set. + public static void SetUppercase(AvaloniaObject avaloniaObject, bool value) + { + avaloniaObject.SetValue(UppercaseProperty, value); + } + + /// + /// Gets the value of the attached . + /// + /// The target. + /// true if Uppercase + public static bool GetUppercase(AvaloniaObject avaloniaObject) + { + return avaloniaObject.GetValue(UppercaseProperty); + } + + /// + /// Text is in upper case + /// + public bool Uppercase { get; set; } + + /// + /// Defines the property. + /// + public static readonly AttachedProperty AutoCapitalizationProperty = + AvaloniaProperty.RegisterAttached( + "AutoCapitalization", + inherits: true); + + /// + /// Sets the value of the attached on a control. + /// + /// The control. + /// The property value to set. + public static void SetAutoCapitalization(AvaloniaObject avaloniaObject, bool value) + { + avaloniaObject.SetValue(AutoCapitalizationProperty, value); + } + + /// + /// Gets the value of the attached . + /// + /// The target. + /// true if AutoCapitalization + public static bool GetAutoCapitalization(AvaloniaObject avaloniaObject) + { + return avaloniaObject.GetValue(AutoCapitalizationProperty); + } + + /// + /// Automatically capitalize letters at the start of the sentence + /// + public bool AutoCapitalization { get; set; } + + /// + /// Defines the property. + /// + public static readonly AttachedProperty IsSensitiveProperty = + AvaloniaProperty.RegisterAttached( + "IsSensitive", + inherits: true); + + /// + /// Sets the value of the attached on a control. + /// + /// The control. + /// The property value to set. + public static void SetIsSensitive(AvaloniaObject avaloniaObject, bool value) + { + avaloniaObject.SetValue(IsSensitiveProperty, value); + } + + /// + /// Gets the value of the attached . + /// + /// The target. + /// true if IsSensitive + public static bool GetIsSensitive(AvaloniaObject avaloniaObject) + { + return avaloniaObject.GetValue(IsSensitiveProperty); + } + + /// + /// Text contains sensitive data like card numbers and should not be stored + /// + public bool IsSensitive { get; set; } } diff --git a/src/Avalonia.Input/TextInput/TextInputOptionsQueryEventArgs.cs b/src/Avalonia.Input/TextInput/TextInputOptionsQueryEventArgs.cs deleted file mode 100644 index 924d0eb166..0000000000 --- a/src/Avalonia.Input/TextInput/TextInputOptionsQueryEventArgs.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Avalonia.Interactivity; - -namespace Avalonia.Input.TextInput -{ - public class TextInputOptionsQueryEventArgs : RoutedEventArgs - { - /// - /// The content type (mostly for determining the shape of the virtual keyboard) - /// - public TextInputContentType ContentType { get; set; } - /// - /// Text is multiline - /// - public bool Multiline { get; set; } - /// - /// Text is in lower case - /// - public bool Lowercase { get; set; } - /// - /// Text is in upper case - /// - public bool Uppercase { get; set; } - /// - /// Automatically capitalize letters at the start of the sentence - /// - public bool AutoCapitalization { get; set; } - /// - /// Text contains sensitive data like card numbers and should not be stored - /// - public bool IsSensitive { get; set; } - } -} diff --git a/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs b/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs index e3a33ff2b4..d1df67895d 100644 --- a/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs +++ b/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs @@ -80,7 +80,7 @@ public partial class AvaloniaView : ITextInputMethodImpl } - void ITextInputMethodImpl.SetOptions(TextInputOptionsQueryEventArgs options) + void ITextInputMethodImpl.SetOptions(TextInputOptions options) { switch (options.ContentType) { From 2b99e0159d74ee0446e4e2d0aa6e0aecffca3eae Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 14:59:33 +0000 Subject: [PATCH 10/22] fix baseline. --- src/Avalonia.Input/ApiCompatBaseline.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Input/ApiCompatBaseline.txt b/src/Avalonia.Input/ApiCompatBaseline.txt index 32cd7ae1ba..900c646d40 100644 --- a/src/Avalonia.Input/ApiCompatBaseline.txt +++ b/src/Avalonia.Input/ApiCompatBaseline.txt @@ -16,5 +16,9 @@ MembersMustExist : Member 'public void Avalonia.Input.InputElement.remove_TextIn 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. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetOptions(Avalonia.Input.TextInput.TextInputOptions)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetOptions(Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs)' is present in the contract but not in the implementation. +MembersMustExist : Member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetOptions(Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs)' does not exist in the implementation but it does exist in the contract. +TypesMustExist : Type 'Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs' 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: 18 +Total Issues: 22 From 2228d83eb187b22f5efa15680dfc65a27fe0297c Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 16:09:59 +0000 Subject: [PATCH 11/22] use styledelement instread of AvaloniaObject --- .../TextInput/TextInputOptions.cs | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Avalonia.Input/TextInput/TextInputOptions.cs b/src/Avalonia.Input/TextInput/TextInputOptions.cs index c60473ad78..c704d6b914 100644 --- a/src/Avalonia.Input/TextInput/TextInputOptions.cs +++ b/src/Avalonia.Input/TextInput/TextInputOptions.cs @@ -2,7 +2,7 @@ namespace Avalonia.Input.TextInput; public class TextInputOptions { - public static TextInputOptions FromAvaloniaObject(AvaloniaObject avaloniaObject) + public static TextInputOptions FromStyledElement(StyledElement avaloniaObject) { var result = new TextInputOptions { @@ -21,7 +21,7 @@ public class TextInputOptions /// Defines the property. /// public static readonly AttachedProperty ContentTypeProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( "ContentType", defaultValue: TextInputContentType.Normal, inherits: true); @@ -31,7 +31,7 @@ public class TextInputOptions /// /// The control. /// The property value to set. - public static void SetContentType(AvaloniaObject avaloniaObject, TextInputContentType value) + public static void SetContentType(StyledElement avaloniaObject, TextInputContentType value) { avaloniaObject.SetValue(ContentTypeProperty, value); } @@ -41,7 +41,7 @@ public class TextInputOptions /// /// The target. /// TextInputContentType - public static TextInputContentType GetContentType(AvaloniaObject avaloniaObject) + public static TextInputContentType GetContentType(StyledElement avaloniaObject) { return avaloniaObject.GetValue(ContentTypeProperty); } @@ -55,7 +55,7 @@ public class TextInputOptions /// Defines the property. /// public static readonly AttachedProperty MultilineProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( "Multiline", inherits: true); @@ -64,7 +64,7 @@ public class TextInputOptions /// /// The control. /// The property value to set. - public static void SetMultiline(AvaloniaObject avaloniaObject, bool value) + public static void SetMultiline(StyledElement avaloniaObject, bool value) { avaloniaObject.SetValue(MultilineProperty, value); } @@ -74,7 +74,7 @@ public class TextInputOptions /// /// The target. /// true if multiline - public static bool GetMultiline(AvaloniaObject avaloniaObject) + public static bool GetMultiline(StyledElement avaloniaObject) { return avaloniaObject.GetValue(MultilineProperty); } @@ -88,7 +88,7 @@ public class TextInputOptions /// Defines the property. /// public static readonly AttachedProperty LowercaseProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( "Lowercase", inherits: true); @@ -97,7 +97,7 @@ public class TextInputOptions /// /// The control. /// The property value to set. - public static void SetLowercase(AvaloniaObject avaloniaObject, bool value) + public static void SetLowercase(StyledElement avaloniaObject, bool value) { avaloniaObject.SetValue(LowercaseProperty, value); } @@ -107,7 +107,7 @@ public class TextInputOptions /// /// The target. /// true if Lowercase - public static bool GetLowercase(AvaloniaObject avaloniaObject) + public static bool GetLowercase(StyledElement avaloniaObject) { return avaloniaObject.GetValue(LowercaseProperty); } @@ -121,7 +121,7 @@ public class TextInputOptions /// Defines the property. /// public static readonly AttachedProperty UppercaseProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( "Uppercase", inherits: true); @@ -130,7 +130,7 @@ public class TextInputOptions /// /// The control. /// The property value to set. - public static void SetUppercase(AvaloniaObject avaloniaObject, bool value) + public static void SetUppercase(StyledElement avaloniaObject, bool value) { avaloniaObject.SetValue(UppercaseProperty, value); } @@ -140,7 +140,7 @@ public class TextInputOptions /// /// The target. /// true if Uppercase - public static bool GetUppercase(AvaloniaObject avaloniaObject) + public static bool GetUppercase(StyledElement avaloniaObject) { return avaloniaObject.GetValue(UppercaseProperty); } @@ -154,7 +154,7 @@ public class TextInputOptions /// Defines the property. /// public static readonly AttachedProperty AutoCapitalizationProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( "AutoCapitalization", inherits: true); @@ -163,7 +163,7 @@ public class TextInputOptions /// /// The control. /// The property value to set. - public static void SetAutoCapitalization(AvaloniaObject avaloniaObject, bool value) + public static void SetAutoCapitalization(StyledElement avaloniaObject, bool value) { avaloniaObject.SetValue(AutoCapitalizationProperty, value); } @@ -173,7 +173,7 @@ public class TextInputOptions /// /// The target. /// true if AutoCapitalization - public static bool GetAutoCapitalization(AvaloniaObject avaloniaObject) + public static bool GetAutoCapitalization(StyledElement avaloniaObject) { return avaloniaObject.GetValue(AutoCapitalizationProperty); } @@ -187,7 +187,7 @@ public class TextInputOptions /// Defines the property. /// public static readonly AttachedProperty IsSensitiveProperty = - AvaloniaProperty.RegisterAttached( + AvaloniaProperty.RegisterAttached( "IsSensitive", inherits: true); @@ -196,7 +196,7 @@ public class TextInputOptions /// /// The control. /// The property value to set. - public static void SetIsSensitive(AvaloniaObject avaloniaObject, bool value) + public static void SetIsSensitive(StyledElement avaloniaObject, bool value) { avaloniaObject.SetValue(IsSensitiveProperty, value); } @@ -206,7 +206,7 @@ public class TextInputOptions /// /// The target. /// true if IsSensitive - public static bool GetIsSensitive(AvaloniaObject avaloniaObject) + public static bool GetIsSensitive(StyledElement avaloniaObject) { return avaloniaObject.GetValue(IsSensitiveProperty); } From 784b25539a7126c664b8f94827f17f5b0026d530 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 16:26:35 +0000 Subject: [PATCH 12/22] rename file. --- .../Avalonia.iOS/{AvaloniaUIResponder.cs => AvaloniaView.Text.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/iOS/Avalonia.iOS/{AvaloniaUIResponder.cs => AvaloniaView.Text.cs} (100%) diff --git a/src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs b/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs similarity index 100% rename from src/iOS/Avalonia.iOS/AvaloniaUIResponder.cs rename to src/iOS/Avalonia.iOS/AvaloniaView.Text.cs From b1d5d9b8bdab1a8a4dca6c0caf6beb849f2df900 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 16:26:47 +0000 Subject: [PATCH 13/22] fix styledelement. --- src/Avalonia.Input/TextInput/InputMethodManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Input/TextInput/InputMethodManager.cs b/src/Avalonia.Input/TextInput/InputMethodManager.cs index e2d6a1fd9f..12305dfe33 100644 --- a/src/Avalonia.Input/TextInput/InputMethodManager.cs +++ b/src/Avalonia.Input/TextInput/InputMethodManager.cs @@ -38,9 +38,9 @@ namespace Avalonia.Input.TextInput _im?.Reset(); - if (_focusedElement is AvaloniaObject target) + if (_focusedElement is StyledElement target) { - _im?.SetOptions(TextInputOptions.FromAvaloniaObject(target)); + _im?.SetOptions(TextInputOptions.FromStyledElement(target)); } _transformTracker.SetVisual(_client?.TextViewVisual); From 18b53b875d81d3890a9fc6f77efced954ba27e91 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 16:30:41 +0000 Subject: [PATCH 14/22] remove no longer needed check. --- src/Avalonia.Input/TextInput/InputMethodManager.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Avalonia.Input/TextInput/InputMethodManager.cs b/src/Avalonia.Input/TextInput/InputMethodManager.cs index 12305dfe33..9f686a150a 100644 --- a/src/Avalonia.Input/TextInput/InputMethodManager.cs +++ b/src/Avalonia.Input/TextInput/InputMethodManager.cs @@ -96,11 +96,6 @@ namespace Avalonia.Input.TextInput _im = inputMethod; TryFindAndApplyClient(); - - if (_im != inputMethod) - { - _im?.SetActive(Client); - } } private void TryFindAndApplyClient() From 8b8253c3bfb6f5efc636227dbca88adc5a4b18eb Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 16:35:35 +0000 Subject: [PATCH 15/22] fix broken apis. --- .../DBusIme/DBusTextInputMethodBase.cs | 4 ++-- .../DBusIme/Fcitx/FcitxX11TextInputMethod.cs | 2 +- src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs | 2 +- src/Avalonia.Input/TextInput/InputMethodManager.cs | 9 +++++++-- src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs | 2 +- src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs | 2 +- 6 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs b/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs index 640befba62..864c579319 100644 --- a/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs +++ b/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs @@ -198,7 +198,7 @@ namespace Avalonia.FreeDesktop.DBusIme UpdateActive(); } - void ITextInputMethodImpl.SetActive(ITextInputMethodClient client) + void ITextInputMethodImpl.SetClient(ITextInputMethodClient client) { _controlActive = client is { }; UpdateActive(); @@ -272,7 +272,7 @@ namespace Avalonia.FreeDesktop.DBusIme UpdateCursorRect(); } - public abstract void SetOptions(TextInputOptionsQueryEventArgs options); + public abstract void SetOptions(TextInputOptions options); void ITextInputMethodImpl.Reset() { diff --git a/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs b/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs index 31a061571f..15dc131e4e 100644 --- a/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs +++ b/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs @@ -93,7 +93,7 @@ namespace Avalonia.FreeDesktop.DBusIme.Fcitx (uint)args.Timestamp).ConfigureAwait(false); } - public override void SetOptions(TextInputOptionsQueryEventArgs options) => + public override void SetOptions(TextInputOptions options) => Enqueue(async () => { if(_context == null) diff --git a/src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs b/src/Avalonia.Input/TextInput/ITextInputMethodImpl.cs index 729b517f88..4404c903b7 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(ITextInputMethodClient? client); + void SetClient(ITextInputMethodClient? client); void SetCursorRect(Rect rect); void SetOptions(TextInputOptions options); void Reset(); diff --git a/src/Avalonia.Input/TextInput/InputMethodManager.cs b/src/Avalonia.Input/TextInput/InputMethodManager.cs index 9f686a150a..e19bf91f95 100644 --- a/src/Avalonia.Input/TextInput/InputMethodManager.cs +++ b/src/Avalonia.Input/TextInput/InputMethodManager.cs @@ -46,11 +46,11 @@ namespace Avalonia.Input.TextInput _transformTracker.SetVisual(_client?.TextViewVisual); UpdateCursorRect(); - _im?.SetActive(_client); + _im?.SetClient(_client); } else { - _im?.SetActive(null); + _im?.SetClient(null); _transformTracker.SetVisual(null); } } @@ -92,6 +92,11 @@ namespace Avalonia.Input.TextInput _focusedElement = element; var inputMethod = (element?.VisualRoot as ITextInputMethodRoot)?.InputMethod; + + if (_im != inputMethod) + { + _im?.SetClient(null); + } _im = inputMethod; diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs index 3649a884a6..cdc41bebf5 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs @@ -386,7 +386,7 @@ namespace Avalonia.Web.Blazor { } - public void SetOptions(TextInputOptionsQueryEventArgs options) + public void SetOptions(TextInputOptions options) { } diff --git a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs index 71e33554f1..ad6c112043 100644 --- a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs +++ b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs @@ -216,7 +216,7 @@ namespace Avalonia.Win32.Input ImmSetCompositionFont(himc, ref logFont); } - public void SetOptions(TextInputOptionsQueryEventArgs options) + public void SetOptions(TextInputOptions options) { // we're skipping this. not usable on windows } From 04d4c37c4fe433a5113dfbb42850535a4bcdc544 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 17:12:42 +0000 Subject: [PATCH 16/22] restore default options if no properties are found. --- src/Avalonia.Input/TextInput/InputMethodManager.cs | 4 ++++ src/Avalonia.Input/TextInput/TextInputOptions.cs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/Avalonia.Input/TextInput/InputMethodManager.cs b/src/Avalonia.Input/TextInput/InputMethodManager.cs index e19bf91f95..4734224da4 100644 --- a/src/Avalonia.Input/TextInput/InputMethodManager.cs +++ b/src/Avalonia.Input/TextInput/InputMethodManager.cs @@ -42,6 +42,10 @@ namespace Avalonia.Input.TextInput { _im?.SetOptions(TextInputOptions.FromStyledElement(target)); } + else + { + _im?.SetOptions(TextInputOptions.Default); + } _transformTracker.SetVisual(_client?.TextViewVisual); UpdateCursorRect(); diff --git a/src/Avalonia.Input/TextInput/TextInputOptions.cs b/src/Avalonia.Input/TextInput/TextInputOptions.cs index c704d6b914..af5f142a25 100644 --- a/src/Avalonia.Input/TextInput/TextInputOptions.cs +++ b/src/Avalonia.Input/TextInput/TextInputOptions.cs @@ -16,6 +16,8 @@ public class TextInputOptions return result; } + + public static readonly TextInputOptions Default = new(); /// /// Defines the property. From 47989e484a77bf913a82881e7894858d604aafb2 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 17:13:08 +0000 Subject: [PATCH 17/22] osx no need to reset text options. manually on reset. --- src/iOS/Avalonia.iOS/AvaloniaView.Text.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs b/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs index d1df67895d..85d984229f 100644 --- a/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs +++ b/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs @@ -61,7 +61,7 @@ public partial class AvaloniaView : ITextInputMethodImpl } } - void ITextInputMethodImpl.SetActive(ITextInputMethodClient? client) + void ITextInputMethodImpl.SetClient(ITextInputMethodClient? client) { _currentClient = client; @@ -112,8 +112,6 @@ public partial class AvaloniaView : ITextInputMethodImpl void ITextInputMethodImpl.Reset() { - IsSecureEntry = false; - KeyboardType = UIKeyboardType.Default; ResignFirstResponder(); } } From 9871144d3fad8da811d93473e48da118cc2effef Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 17:14:54 +0000 Subject: [PATCH 18/22] fix ime implementations with new api. --- .../DBusIme/IBus/IBusX11TextInputMethod.cs | 2 +- src/Avalonia.Input/ApiCompatBaseline.txt | 2 +- src/Avalonia.X11/X11Window.Xim.cs | 7 +++---- src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs | 4 +++- src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs | 6 +++--- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs b/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs index a73de9dae8..1397eaa57b 100644 --- a/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs +++ b/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs @@ -97,7 +97,7 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus return _context.ProcessKeyEventAsync((uint)keyVal, (uint)keyCode, (uint)state); } - public override void SetOptions(TextInputOptionsQueryEventArgs options) + public override void SetOptions(TextInputOptions options) { // No-op, because ibus } diff --git a/src/Avalonia.Input/ApiCompatBaseline.txt b/src/Avalonia.Input/ApiCompatBaseline.txt index 900c646d40..529e93fd82 100644 --- a/src/Avalonia.Input/ApiCompatBaseline.txt +++ b/src/Avalonia.Input/ApiCompatBaseline.txt @@ -13,9 +13,9 @@ MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_TextInput 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. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetClient(Avalonia.Input.TextInput.ITextInputMethodClient)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetOptions(Avalonia.Input.TextInput.TextInputOptions)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetOptions(Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs)' is present in the contract but not in the implementation. MembersMustExist : Member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetOptions(Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs)' does not exist in the implementation but it does exist in the contract. diff --git a/src/Avalonia.X11/X11Window.Xim.cs b/src/Avalonia.X11/X11Window.Xim.cs index ecb23ff097..bedd1d22fc 100644 --- a/src/Avalonia.X11/X11Window.Xim.cs +++ b/src/Avalonia.X11/X11Window.Xim.cs @@ -10,7 +10,6 @@ namespace Avalonia.X11 { partial class X11Window { - class XimInputMethod : ITextInputMethodImpl, IX11InputMethodControl { private readonly X11Window _parent; @@ -58,9 +57,9 @@ namespace Avalonia.X11 UpdateActive(); } - public void SetActive(bool active) + public void SetClient(ITextInputMethodClient client) { - _controlActive = active; + _controlActive = client is { }; UpdateActive(); } @@ -87,7 +86,7 @@ namespace Avalonia.X11 // No-op } - public void SetOptions(TextInputOptionsQueryEventArgs options) + public void SetOptions(TextInputOptions options) { // No-op } diff --git a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs index cdc41bebf5..1ccf53943a 100644 --- a/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs +++ b/src/Web/Avalonia.Web.Blazor/AvaloniaView.razor.cs @@ -367,10 +367,12 @@ namespace Avalonia.Web.Blazor } } - public void SetActive(bool active) + public void SetClient(ITextInputMethodClient? client) { _inputHelper.Clear(); + var active = client is { }; + if (active) { _inputHelper.Show(); diff --git a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs index ad6c112043..9ff6f76ac4 100644 --- a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs +++ b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs @@ -74,12 +74,12 @@ namespace Avalonia.Win32.Input } } - public void SetActive(bool active) + public void SetClient(ITextInputMethodClient client) { - _active = active; + _active = client is { }; Dispatcher.UIThread.Post(() => { - if (active) + if (_active) { if (DefaultImc != IntPtr.Zero) { From b2ce338adec61934fea596a8ca53e580351166a6 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 17:17:32 +0000 Subject: [PATCH 19/22] add empty baselines. --- src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt | 1 + src/Avalonia.DesignerSupport/ApiCompatBaseline.txt | 1 + src/Avalonia.Interactivity/ApiCompatBaseline.txt | 1 + src/Avalonia.Layout/ApiCompatBaseline.txt | 1 + src/Avalonia.Remote.Protocol/ApiCompatBaseline.txt | 1 + src/Avalonia.Themes.Default/ApiCompatBaseline.txt | 1 + src/Avalonia.Themes.Fluent/ApiCompatBaseline.txt | 1 + src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt | 1 + src/Markup/Avalonia.Markup/ApiCompatBaseline.txt | 1 + 9 files changed, 9 insertions(+) create mode 100644 src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt create mode 100644 src/Avalonia.DesignerSupport/ApiCompatBaseline.txt create mode 100644 src/Avalonia.Interactivity/ApiCompatBaseline.txt create mode 100644 src/Avalonia.Layout/ApiCompatBaseline.txt create mode 100644 src/Avalonia.Remote.Protocol/ApiCompatBaseline.txt create mode 100644 src/Avalonia.Themes.Default/ApiCompatBaseline.txt create mode 100644 src/Avalonia.Themes.Fluent/ApiCompatBaseline.txt create mode 100644 src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt create mode 100644 src/Markup/Avalonia.Markup/ApiCompatBaseline.txt diff --git a/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt b/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt new file mode 100644 index 0000000000..fcc74cf864 --- /dev/null +++ b/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt @@ -0,0 +1 @@ +Total Issues: 0 diff --git a/src/Avalonia.DesignerSupport/ApiCompatBaseline.txt b/src/Avalonia.DesignerSupport/ApiCompatBaseline.txt new file mode 100644 index 0000000000..fcc74cf864 --- /dev/null +++ b/src/Avalonia.DesignerSupport/ApiCompatBaseline.txt @@ -0,0 +1 @@ +Total Issues: 0 diff --git a/src/Avalonia.Interactivity/ApiCompatBaseline.txt b/src/Avalonia.Interactivity/ApiCompatBaseline.txt new file mode 100644 index 0000000000..fcc74cf864 --- /dev/null +++ b/src/Avalonia.Interactivity/ApiCompatBaseline.txt @@ -0,0 +1 @@ +Total Issues: 0 diff --git a/src/Avalonia.Layout/ApiCompatBaseline.txt b/src/Avalonia.Layout/ApiCompatBaseline.txt new file mode 100644 index 0000000000..fcc74cf864 --- /dev/null +++ b/src/Avalonia.Layout/ApiCompatBaseline.txt @@ -0,0 +1 @@ +Total Issues: 0 diff --git a/src/Avalonia.Remote.Protocol/ApiCompatBaseline.txt b/src/Avalonia.Remote.Protocol/ApiCompatBaseline.txt new file mode 100644 index 0000000000..fcc74cf864 --- /dev/null +++ b/src/Avalonia.Remote.Protocol/ApiCompatBaseline.txt @@ -0,0 +1 @@ +Total Issues: 0 diff --git a/src/Avalonia.Themes.Default/ApiCompatBaseline.txt b/src/Avalonia.Themes.Default/ApiCompatBaseline.txt new file mode 100644 index 0000000000..fcc74cf864 --- /dev/null +++ b/src/Avalonia.Themes.Default/ApiCompatBaseline.txt @@ -0,0 +1 @@ +Total Issues: 0 diff --git a/src/Avalonia.Themes.Fluent/ApiCompatBaseline.txt b/src/Avalonia.Themes.Fluent/ApiCompatBaseline.txt new file mode 100644 index 0000000000..fcc74cf864 --- /dev/null +++ b/src/Avalonia.Themes.Fluent/ApiCompatBaseline.txt @@ -0,0 +1 @@ +Total Issues: 0 diff --git a/src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt b/src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt new file mode 100644 index 0000000000..fcc74cf864 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt @@ -0,0 +1 @@ +Total Issues: 0 diff --git a/src/Markup/Avalonia.Markup/ApiCompatBaseline.txt b/src/Markup/Avalonia.Markup/ApiCompatBaseline.txt new file mode 100644 index 0000000000..fcc74cf864 --- /dev/null +++ b/src/Markup/Avalonia.Markup/ApiCompatBaseline.txt @@ -0,0 +1 @@ +Total Issues: 0 From 31ee43dccb696ea61e1b9b0c829fb1a2407cc9d1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 17:52:00 +0000 Subject: [PATCH 20/22] add full range of keyboard content types. --- .../DBusIme/Fcitx/FcitxX11TextInputMethod.cs | 2 +- src/Avalonia.Input/ApiCompatBaseline.txt | 7 ++- .../TextInput/TextInputContentType.cs | 62 +++++++++++++++++-- src/iOS/Avalonia.iOS/AvaloniaView.Text.cs | 14 ++++- 4 files changed, 76 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs b/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs index 15dc131e4e..0b85965de7 100644 --- a/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs +++ b/src/Avalonia.FreeDesktop/DBusIme/Fcitx/FcitxX11TextInputMethod.cs @@ -111,7 +111,7 @@ namespace Avalonia.FreeDesktop.DBusIme.Fcitx flags |= FcitxCapabilityFlags.CAPACITY_NUMBER; else if (options.ContentType == TextInputContentType.Password) flags |= FcitxCapabilityFlags.CAPACITY_PASSWORD; - else if (options.ContentType == TextInputContentType.Phone) + else if (options.ContentType == TextInputContentType.Digits) flags |= FcitxCapabilityFlags.CAPACITY_DIALABLE; else if (options.ContentType == TextInputContentType.Url) flags |= FcitxCapabilityFlags.CAPACITY_URL; diff --git a/src/Avalonia.Input/ApiCompatBaseline.txt b/src/Avalonia.Input/ApiCompatBaseline.txt index 529e93fd82..68b4d4754f 100644 --- a/src/Avalonia.Input/ApiCompatBaseline.txt +++ b/src/Avalonia.Input/ApiCompatBaseline.txt @@ -19,6 +19,11 @@ InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.T InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetOptions(Avalonia.Input.TextInput.TextInputOptions)' is present in the implementation but not in the contract. InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetOptions(Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs)' is present in the contract but not in the implementation. MembersMustExist : Member 'public void Avalonia.Input.TextInput.ITextInputMethodImpl.SetOptions(Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs)' does not exist in the implementation but it does exist in the contract. +EnumValuesMustMatch : Enum value 'Avalonia.Input.TextInput.TextInputContentType Avalonia.Input.TextInput.TextInputContentType.Email' is (System.Int32)5 in the implementation but (System.Int32)1 in the contract. +EnumValuesMustMatch : Enum value 'Avalonia.Input.TextInput.TextInputContentType Avalonia.Input.TextInput.TextInputContentType.Number' is (System.Int32)4 in the implementation but (System.Int32)3 in the contract. +EnumValuesMustMatch : Enum value 'Avalonia.Input.TextInput.TextInputContentType Avalonia.Input.TextInput.TextInputContentType.Password' is (System.Int32)8 in the implementation but (System.Int32)5 in the contract. +MembersMustExist : Member 'public Avalonia.Input.TextInput.TextInputContentType Avalonia.Input.TextInput.TextInputContentType Avalonia.Input.TextInput.TextInputContentType.Phone' does not exist in the implementation but it does exist in the contract. +EnumValuesMustMatch : Enum value 'Avalonia.Input.TextInput.TextInputContentType Avalonia.Input.TextInput.TextInputContentType.Url' is (System.Int32)6 in the implementation but (System.Int32)4 in the contract. TypesMustExist : Type 'Avalonia.Input.TextInput.TextInputOptionsQueryEventArgs' 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: 22 +Total Issues: 27 diff --git a/src/Avalonia.Input/TextInput/TextInputContentType.cs b/src/Avalonia.Input/TextInput/TextInputContentType.cs index 5d73fc1552..02a9385354 100644 --- a/src/Avalonia.Input/TextInput/TextInputContentType.cs +++ b/src/Avalonia.Input/TextInput/TextInputContentType.cs @@ -1,12 +1,62 @@ namespace Avalonia.Input.TextInput -{ +{ public enum TextInputContentType { + /// + /// Default keyboard for the users configured input method. + /// Normal = 0, - Email = 1, - Phone = 2, - Number = 3, - Url = 4, - Password = 5 + + /// + /// Display a keyboard that only has alphabetic characters. + /// + Alpha, + + /// + /// Display a numeric keypad only capable of numbers. i.e. Phone number + /// + Digits, + + /// + /// Display a numeric keypad for inputting a PIN. + /// + Pin, + + /// + /// Display a numeric keypad capable of inputting numbers including decimal seperator and sign. + /// + Number, + + /// + /// Display a keyboard for entering an email address. + /// + Email, + + /// + /// Display a keyboard for entering a URL. + /// + Url, + + /// + /// Display a keyboard for entering a persons name. + /// + Name, + + /// + /// Display a keyboard for entering sensitive data. + /// + Password, + + /// + /// Display a keyboard suitable for #tag and @mentions. + /// Not available on all platforms, will fallback to a suitable keyboard + /// when not available. + /// + Social, + + /// + /// Display a keyboard for entering a search keyword. + /// + Search } } diff --git a/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs b/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs index 85d984229f..4f4b917a78 100644 --- a/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs +++ b/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs @@ -82,6 +82,8 @@ public partial class AvaloniaView : ITextInputMethodImpl void ITextInputMethodImpl.SetOptions(TextInputOptions options) { + IsSecureEntry = false; + switch (options.ContentType) { case TextInputContentType.Email: @@ -89,14 +91,19 @@ public partial class AvaloniaView : ITextInputMethodImpl break; case TextInputContentType.Number: + KeyboardType = UIKeyboardType.PhonePad; + break; + + case TextInputContentType.Pin: KeyboardType = UIKeyboardType.NumberPad; + IsSecureEntry = true; break; case TextInputContentType.Password: IsSecureEntry = true; break; - case TextInputContentType.Phone: + case TextInputContentType.Digits: KeyboardType = UIKeyboardType.PhonePad; break; @@ -108,6 +115,11 @@ public partial class AvaloniaView : ITextInputMethodImpl KeyboardType = UIKeyboardType.Default; break; } + + if (options.IsSensitive) + { + IsSecureEntry = true; + } } void ITextInputMethodImpl.Reset() From 56845e22d58db1e9cfa7c3d7f1882e4ec5d9acb5 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 17:59:17 +0000 Subject: [PATCH 21/22] ios support all input types. --- src/iOS/Avalonia.iOS/AvaloniaView.Text.cs | 39 ++++++++++++++++------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs b/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs index 4f4b917a78..d49ce5310c 100644 --- a/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs +++ b/src/iOS/Avalonia.iOS/AvaloniaView.Text.cs @@ -86,11 +86,15 @@ public partial class AvaloniaView : ITextInputMethodImpl switch (options.ContentType) { - case TextInputContentType.Email: - KeyboardType = UIKeyboardType.EmailAddress; + case TextInputContentType.Normal: + KeyboardType = UIKeyboardType.Default; break; - - case TextInputContentType.Number: + + case TextInputContentType.Alpha: + KeyboardType = UIKeyboardType.AsciiCapable; + break; + + case TextInputContentType.Digits: KeyboardType = UIKeyboardType.PhonePad; break; @@ -98,21 +102,34 @@ public partial class AvaloniaView : ITextInputMethodImpl KeyboardType = UIKeyboardType.NumberPad; IsSecureEntry = true; break; - - case TextInputContentType.Password: - IsSecureEntry = true; - break; - - case TextInputContentType.Digits: + + case TextInputContentType.Number: KeyboardType = UIKeyboardType.PhonePad; break; + + case TextInputContentType.Email: + KeyboardType = UIKeyboardType.EmailAddress; + break; case TextInputContentType.Url: KeyboardType = UIKeyboardType.Url; break; - case TextInputContentType.Normal: + case TextInputContentType.Name: + KeyboardType = UIKeyboardType.NamePhonePad; + break; + + case TextInputContentType.Password: KeyboardType = UIKeyboardType.Default; + IsSecureEntry = true; + break; + + case TextInputContentType.Social: + KeyboardType = UIKeyboardType.Twitter; + break; + + case TextInputContentType.Search: + KeyboardType = UIKeyboardType.WebSearch; break; } From 2da1d3cfe3280efc76eeac2ea87ec472c34e5547 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 10 Mar 2022 18:37:12 +0000 Subject: [PATCH 22/22] remove android keyboard hacks. --- .../Avalonia.Android/AndroidInputMethod.cs | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/Android/Avalonia.Android/AndroidInputMethod.cs b/src/Android/Avalonia.Android/AndroidInputMethod.cs index b6491a5890..880b210a6c 100644 --- a/src/Android/Avalonia.Android/AndroidInputMethod.cs +++ b/src/Android/Avalonia.Android/AndroidInputMethod.cs @@ -13,7 +13,6 @@ namespace Avalonia.Android { private readonly TView _host; private readonly InputMethodManager _imm; - private IInputElement _inputElement; public AndroidInputMethod(TView host) { @@ -33,8 +32,10 @@ namespace Avalonia.Android _imm.RestartInput(_host); } - public void SetActive(bool active) + public void SetClient(ITextInputMethodClient client) { + var active = client is { }; + if (active) { _host.RequestFocus(); @@ -49,20 +50,8 @@ namespace Avalonia.Android { } - public void SetOptions(TextInputOptionsQueryEventArgs options) + public void SetOptions(TextInputOptions options) { - if (_inputElement != null) - { - _inputElement.PointerReleased -= RestoreSoftKeyboard; - } - - _inputElement = options.Source as InputElement; - - if (_inputElement == null) - { - _imm.HideSoftInputFromWindow(_host.WindowToken, HideSoftInputFlags.None); - } - _host.InitEditorInfo((outAttrs) => { outAttrs.InputType = options.ContentType switch @@ -70,7 +59,7 @@ namespace Avalonia.Android TextInputContentType.Email => global::Android.Text.InputTypes.TextVariationEmailAddress, TextInputContentType.Number => global::Android.Text.InputTypes.ClassNumber, TextInputContentType.Password => global::Android.Text.InputTypes.TextVariationPassword, - TextInputContentType.Phone => global::Android.Text.InputTypes.ClassPhone, + TextInputContentType.Digits => global::Android.Text.InputTypes.ClassPhone, TextInputContentType.Url => global::Android.Text.InputTypes.TextVariationUri, _ => global::Android.Text.InputTypes.ClassText }; @@ -86,8 +75,6 @@ namespace Avalonia.Android outAttrs.ImeOptions |= ImeFlags.NoFullscreen | ImeFlags.NoExtractUi; }); - - //_inputElement.PointerReleased += RestoreSoftKeyboard; } private void RestoreSoftKeyboard(object sender, PointerReleasedEventArgs e)