mirror of
https://github.com/SK-la/osu-framework.git
synced 2026-03-15 03:20:30 +00:00
Merge pull request #6408 from frenzibyte/text-input-properties
Allow `TextBox` to specify type of text being input
This commit is contained in:
@@ -122,8 +122,9 @@ namespace osu.Framework.Tests.Visual.UserInterface
|
||||
TabbableContentContainer = otherTextBoxes
|
||||
});
|
||||
|
||||
otherTextBoxes.Add(new BasicPasswordTextBox
|
||||
otherTextBoxes.Add(new BasicTextBox
|
||||
{
|
||||
InputProperties = new TextInputProperties(TextInputType.Password),
|
||||
PlaceholderText = @"Password textbox",
|
||||
Text = "Secret ;)",
|
||||
Size = new Vector2(500, 30),
|
||||
@@ -169,12 +170,13 @@ namespace osu.Framework.Tests.Visual.UserInterface
|
||||
[Test]
|
||||
public void TestNumbersOnly()
|
||||
{
|
||||
NumberTextBox numbers = null;
|
||||
BasicTextBox numbers = null;
|
||||
|
||||
AddStep("add number textbox", () =>
|
||||
{
|
||||
textBoxes.Add(numbers = new NumberTextBox
|
||||
textBoxes.Add(numbers = new BasicTextBox
|
||||
{
|
||||
InputProperties = new TextInputProperties(TextInputType.Number),
|
||||
PlaceholderText = @"Only numbers",
|
||||
Size = new Vector2(500, 30),
|
||||
TabbableContentContainer = textBoxes
|
||||
@@ -1076,13 +1078,6 @@ namespace osu.Framework.Tests.Visual.UserInterface
|
||||
public new void InsertString(string text) => base.InsertString(text);
|
||||
}
|
||||
|
||||
private partial class NumberTextBox : BasicTextBox
|
||||
{
|
||||
protected override bool CanAddCharacter(char character) => char.IsAsciiDigit(character);
|
||||
|
||||
protected override bool AllowIme => false;
|
||||
}
|
||||
|
||||
private partial class CustomTextBox : BasicTextBox
|
||||
{
|
||||
protected override Drawable GetDrawableCharacter(char c) => new ScalingText(c, FontSize);
|
||||
|
||||
@@ -206,7 +206,7 @@ namespace osu.Framework.Tests.Visual.UserInterface
|
||||
|
||||
AddAssert("text input not deactivated", () => textInput.DeactivationQueue.Count == 0);
|
||||
AddAssert("text input not activated again", () => textInput.ActivationQueue.Count == 0);
|
||||
AddAssert("text input ensure activated", () => textInput.EnsureActivatedQueue.Dequeue() && textInput.EnsureActivatedQueue.Count == 0);
|
||||
AddAssert("text input ensure activated", () => textInput.EnsureActivatedQueue.Dequeue() != default && textInput.EnsureActivatedQueue.Count == 0);
|
||||
|
||||
AddStep("click deselection", () =>
|
||||
{
|
||||
@@ -217,7 +217,7 @@ namespace osu.Framework.Tests.Visual.UserInterface
|
||||
|
||||
AddAssert("text input not deactivated", () => textInput.DeactivationQueue.Count == 0);
|
||||
AddAssert("text input not activated again", () => textInput.ActivationQueue.Count == 0);
|
||||
AddAssert("text input ensure activated", () => textInput.EnsureActivatedQueue.Dequeue() && textInput.EnsureActivatedQueue.Count == 0);
|
||||
AddAssert("text input ensure activated", () => textInput.EnsureActivatedQueue.Dequeue() != default && textInput.EnsureActivatedQueue.Count == 0);
|
||||
|
||||
AddStep("click-drag selection", () =>
|
||||
{
|
||||
@@ -500,7 +500,7 @@ namespace osu.Framework.Tests.Visual.UserInterface
|
||||
|
||||
AddStep("add second textbox", () => textInputContainer.Add(secondTextBox = new EventQueuesTextBox
|
||||
{
|
||||
ImeAllowed = allowIme,
|
||||
InputProperties = new TextInputProperties(TextInputType.Text, allowIme),
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
CommitOnFocusLost = true,
|
||||
@@ -517,7 +517,7 @@ namespace osu.Framework.Tests.Visual.UserInterface
|
||||
|
||||
AddAssert("text input not deactivated", () => textInput.DeactivationQueue.Count == 0);
|
||||
AddAssert("text input not activated again", () => textInput.ActivationQueue.Count == 0);
|
||||
AddAssert($"text input ensure activated {(allowIme ? "with" : "without")} IME", () => textInput.EnsureActivatedQueue.Dequeue() == allowIme && textInput.EnsureActivatedQueue.Count == 0);
|
||||
AddAssert($"text input ensure activated {(allowIme ? "with" : "without")} IME", () => textInput.EnsureActivatedQueue.Dequeue().AllowIme == allowIme && textInput.EnsureActivatedQueue.Count == 0);
|
||||
|
||||
AddStep("commit text", () => InputManager.Key(Key.Enter));
|
||||
AddAssert("text input deactivated", () => textInput.DeactivationQueue.Dequeue());
|
||||
@@ -574,10 +574,6 @@ namespace osu.Framework.Tests.Visual.UserInterface
|
||||
|
||||
public partial class EventQueuesTextBox : TestSceneTextBox.InsertableTextBox
|
||||
{
|
||||
public bool ImeAllowed { get; set; } = true;
|
||||
|
||||
protected override bool AllowIme => ImeAllowed;
|
||||
|
||||
public readonly Queue<bool> InputErrorQueue = new Queue<bool>();
|
||||
public readonly Queue<string> UserConsumedTextQueue = new Queue<string>();
|
||||
public readonly Queue<string> UserRemovedTextQueue = new Queue<string>();
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Input;
|
||||
|
||||
namespace osu.Framework.Graphics.UserInterface
|
||||
{
|
||||
public partial class BasicPasswordTextBox : BasicTextBox, ISuppressKeyEventLogging
|
||||
{
|
||||
protected virtual char MaskCharacter => '*';
|
||||
|
||||
protected override bool AllowClipboardExport => false;
|
||||
|
||||
protected override bool AllowWordNavigation => false;
|
||||
|
||||
protected override bool AllowIme => false;
|
||||
|
||||
protected override Drawable AddCharacterToFlow(char c) => base.AddCharacterToFlow(MaskCharacter);
|
||||
}
|
||||
}
|
||||
@@ -192,20 +192,20 @@ namespace osu.Framework.Graphics.UserInterface
|
||||
platformSource.OnImeResult += TriggerImeResult;
|
||||
}
|
||||
|
||||
protected override void ActivateTextInput(bool allowIme)
|
||||
protected override void ActivateTextInput(TextInputProperties properties)
|
||||
{
|
||||
base.ActivateTextInput(allowIme);
|
||||
base.ActivateTextInput(properties);
|
||||
|
||||
if (allowTextInput)
|
||||
platformSource.Activate(allowIme, imeRectangle ?? RectangleF.Empty);
|
||||
platformSource.Activate(properties, imeRectangle ?? RectangleF.Empty);
|
||||
}
|
||||
|
||||
protected override void EnsureTextInputActivated(bool allowIme)
|
||||
protected override void EnsureTextInputActivated(TextInputProperties properties)
|
||||
{
|
||||
base.EnsureTextInputActivated(allowIme);
|
||||
base.EnsureTextInputActivated(properties);
|
||||
|
||||
if (allowTextInput)
|
||||
platformSource.EnsureActivated(allowIme, imeRectangle);
|
||||
platformSource.EnsureActivated(properties, imeRectangle);
|
||||
}
|
||||
|
||||
protected override void DeactivateTextInput()
|
||||
|
||||
@@ -29,13 +29,18 @@ using osuTK.Input;
|
||||
|
||||
namespace osu.Framework.Graphics.UserInterface
|
||||
{
|
||||
public abstract partial class TextBox : TabbableContainer, IHasCurrentValue<string>, IKeyBindingHandler<PlatformAction>
|
||||
public abstract partial class TextBox : TabbableContainer, IHasCurrentValue<string>, IKeyBindingHandler<PlatformAction>, ICanSuppressKeyEventLogging
|
||||
{
|
||||
protected FillFlowContainer TextFlow { get; private set; }
|
||||
protected Container TextContainer { get; private set; }
|
||||
|
||||
public override bool HandleNonPositionalInput => HasFocus;
|
||||
|
||||
/// <summary>
|
||||
/// A character displayed whenever the type of text input set by <see cref="TextInputProperties.Type"/> is hidden.
|
||||
/// </summary>
|
||||
protected virtual char MaskCharacter => '*';
|
||||
|
||||
/// <summary>
|
||||
/// Padding to be used within the TextContainer. Requires special handling due to the sideways scrolling of text content.
|
||||
/// </summary>
|
||||
@@ -50,12 +55,14 @@ namespace osu.Framework.Graphics.UserInterface
|
||||
/// <summary>
|
||||
/// Whether clipboard copying functionality is allowed.
|
||||
/// </summary>
|
||||
protected virtual bool AllowClipboardExport => true;
|
||||
protected virtual bool AllowClipboardExport => !InputProperties.Type.IsPassword();
|
||||
|
||||
/// <summary>
|
||||
/// Whether seeking to word boundaries is allowed.
|
||||
/// </summary>
|
||||
protected virtual bool AllowWordNavigation => true;
|
||||
protected virtual bool AllowWordNavigation => !InputProperties.Type.IsPassword();
|
||||
|
||||
bool ICanSuppressKeyEventLogging.SuppressKeyEventLogging => InputProperties.Type.IsPassword();
|
||||
|
||||
/// <summary>
|
||||
/// Represents the left/right selection coordinates of the word double clicked on when dragging.
|
||||
@@ -67,18 +74,14 @@ namespace osu.Framework.Graphics.UserInterface
|
||||
/// </summary>
|
||||
public virtual bool HandleLeftRightArrows => true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to allow IME input when this text box has input focus.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is just a hint to the native implementation, some might respect this,
|
||||
/// while others will ignore and always have the IME (dis)allowed.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// Useful for situations where IME input is not wanted, such as for passwords, numbers, or romanised text.
|
||||
/// </example>
|
||||
[Obsolete($"Use {nameof(InputProperties)} instead.")] // can be removed 20250506
|
||||
protected virtual bool AllowIme => true;
|
||||
|
||||
/// <summary>
|
||||
/// A set of properties to consider when interacting with this <see cref="TextBox"/>.
|
||||
/// </summary>
|
||||
public TextInputProperties InputProperties { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Check if a character can be added to this TextBox.
|
||||
/// </summary>
|
||||
@@ -87,9 +90,14 @@ namespace osu.Framework.Graphics.UserInterface
|
||||
protected virtual bool CanAddCharacter(char character) => true;
|
||||
|
||||
/// <summary>
|
||||
/// Private helper for <see cref="CanAddCharacter"/>, additionally requiring that the character is not a control character.
|
||||
/// Private helper for <see cref="CanAddCharacter"/>, additionally requiring that the character is not a control character and obeys <see cref="TextInputProperties.Type"/>.
|
||||
/// </summary>
|
||||
private bool canAddCharacter(char character) => !char.IsControl(character) && CanAddCharacter(character);
|
||||
private bool canAddCharacter(char character)
|
||||
{
|
||||
return !char.IsControl(character)
|
||||
&& (!InputProperties.Type.IsNumerical() || char.IsAsciiDigit(character))
|
||||
&& CanAddCharacter(character);
|
||||
}
|
||||
|
||||
private bool readOnly;
|
||||
|
||||
@@ -158,6 +166,10 @@ namespace osu.Framework.Graphics.UserInterface
|
||||
|
||||
protected TextBox()
|
||||
{
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
InputProperties = new TextInputProperties(TextInputType.Text, AllowIme);
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
Masking = true;
|
||||
|
||||
Children = new Drawable[]
|
||||
@@ -790,6 +802,9 @@ namespace osu.Framework.Graphics.UserInterface
|
||||
|
||||
protected virtual Drawable AddCharacterToFlow(char c)
|
||||
{
|
||||
if (InputProperties.Type.IsPassword())
|
||||
c = MaskCharacter;
|
||||
|
||||
// Remove all characters to the right and store them in a local list,
|
||||
// such that their depth can be updated.
|
||||
List<Drawable> charsRight = new List<Drawable>();
|
||||
@@ -1340,7 +1355,7 @@ namespace osu.Framework.Graphics.UserInterface
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
if (!ReadOnly && textInputBound)
|
||||
textInput.EnsureActivated(AllowIme);
|
||||
textInput.EnsureActivated(InputProperties);
|
||||
|
||||
return !ReadOnly;
|
||||
}
|
||||
@@ -1367,7 +1382,7 @@ namespace osu.Framework.Graphics.UserInterface
|
||||
|
||||
if (textInputBound)
|
||||
{
|
||||
textInput.EnsureActivated(AllowIme);
|
||||
textInput.EnsureActivated(InputProperties);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1375,9 +1390,9 @@ namespace osu.Framework.Graphics.UserInterface
|
||||
// We don't deactivate and activate, but instead keep text input active during the focus handoff, so that virtual keyboards on phones don't flicker.
|
||||
|
||||
if (previous?.textInput == textInput)
|
||||
textInput.EnsureActivated(AllowIme, ScreenSpaceDrawQuad.AABBFloat);
|
||||
textInput.EnsureActivated(InputProperties, ScreenSpaceDrawQuad.AABBFloat);
|
||||
else
|
||||
textInput.Activate(AllowIme, ScreenSpaceDrawQuad.AABBFloat);
|
||||
textInput.Activate(InputProperties, ScreenSpaceDrawQuad.AABBFloat);
|
||||
|
||||
textInput.OnTextInput += handleTextInput;
|
||||
textInput.OnImeComposition += handleImeComposition;
|
||||
|
||||
@@ -133,9 +133,18 @@ namespace osu.Framework.Input
|
||||
}
|
||||
|
||||
if (handledBy != null)
|
||||
Logger.Log($"{e} handled by {handledBy}.", LoggingTarget.Runtime, LogLevel.Debug);
|
||||
{
|
||||
Logger.Log(SuppressLoggingEventInformation(handledBy)
|
||||
? $"{e.GetType().Name} handled by {handledBy}."
|
||||
: $"{e} handled by {handledBy}.", LoggingTarget.Runtime, LogLevel.Debug);
|
||||
}
|
||||
|
||||
return handledBy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether information about the event should be suppressed from logging for the given drawable.
|
||||
/// </summary>
|
||||
protected virtual bool SuppressLoggingEventInformation(Drawable drawable) => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
namespace osu.Framework.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker interface which suppresses logging of keyboard input events.
|
||||
/// An interface which suppresses logging of keyboard input events.
|
||||
/// Useful for password fields, where user input should not be logged.
|
||||
/// </summary>
|
||||
public interface ISuppressKeyEventLogging
|
||||
public interface ICanSuppressKeyEventLogging
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether key event logging should be suppressed for this drawable.
|
||||
/// </summary>
|
||||
bool SuppressKeyEventLogging { get; }
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ using System.Diagnostics;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.ListExtensions;
|
||||
using osu.Framework.Extensions.TypeExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
@@ -1002,37 +1001,13 @@ namespace osu.Framework.Input
|
||||
{
|
||||
foreach (var d in drawables)
|
||||
{
|
||||
if (!d.TriggerEvent(e)) continue;
|
||||
|
||||
if (shouldLog(e))
|
||||
{
|
||||
string detail = d is ISuppressKeyEventLogging ? e.GetType().ReadableName() : e.ToString();
|
||||
Logger.Log($"{detail} handled by {d}.", LoggingTarget.Runtime, LogLevel.Debug);
|
||||
}
|
||||
|
||||
return true;
|
||||
if (d.TriggerEvent(e))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool shouldLog(UIEvent eventType)
|
||||
{
|
||||
switch (eventType)
|
||||
{
|
||||
case KeyDownEvent k:
|
||||
return !k.Repeat;
|
||||
|
||||
case DragEvent:
|
||||
case ScrollEvent:
|
||||
case MouseMoveEvent:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unfocus the current focused drawable if it is no longer in a valid state.
|
||||
/// </summary>
|
||||
|
||||
@@ -33,5 +33,7 @@ namespace osu.Framework.Input
|
||||
|
||||
protected override void HandleButtonUp(InputState state, List<Drawable> targets) =>
|
||||
PropagateButtonEvent(targets, new KeyUpEvent(state, Button));
|
||||
|
||||
protected override bool SuppressLoggingEventInformation(Drawable drawable) => drawable is ICanSuppressKeyEventLogging canSuppress && canSuppress.SuppressKeyEventLogging;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,16 +37,16 @@ namespace osu.Framework.Input
|
||||
TriggerImeComposition(text, selectionStart, selectionLength);
|
||||
}
|
||||
|
||||
protected override void ActivateTextInput(bool allowIme)
|
||||
protected override void ActivateTextInput(TextInputProperties properties)
|
||||
{
|
||||
window.TextInput += handleTextInput;
|
||||
window.TextEditing += handleTextEditing;
|
||||
window.StartTextInput(allowIme);
|
||||
window.StartTextInput(properties);
|
||||
}
|
||||
|
||||
protected override void EnsureTextInputActivated(bool allowIme)
|
||||
protected override void EnsureTextInputActivated(TextInputProperties properties)
|
||||
{
|
||||
window.StartTextInput(allowIme);
|
||||
window.StartTextInput(properties);
|
||||
}
|
||||
|
||||
protected override void DeactivateTextInput()
|
||||
|
||||
20
osu.Framework/Input/TextInputProperties.cs
Normal file
20
osu.Framework/Input/TextInputProperties.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
namespace osu.Framework.Input
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a number of properties to consider during a text input session.
|
||||
/// </summary>
|
||||
/// <param name="Type">The type of text being input.</param>
|
||||
/// <param name="AllowIme">
|
||||
/// <para>
|
||||
/// Whether IME should be allowed during this text input session, if supported by the given text input type.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Note that this is just a hint to the native implementation, some might respect this,
|
||||
/// while others will ignore and always have the IME (dis)allowed.
|
||||
/// </para>
|
||||
/// </param>
|
||||
public record struct TextInputProperties(TextInputType Type, bool AllowIme = true);
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
@@ -29,7 +27,7 @@ namespace osu.Framework.Input
|
||||
/// Activates this <see cref="TextInputSource"/>.
|
||||
/// User text input can be acquired through <see cref="OnTextInput"/>, <see cref="OnImeComposition"/> and <see cref="OnImeResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="allowIme">Whether input using IME should be allowed.</param>
|
||||
/// <param name="properties">A set of properties to consider during this text input session.</param>
|
||||
/// <param name="imeRectangle">
|
||||
/// Rough location of where the text will be input, so the native implementation
|
||||
/// can adjust virtual keyboards and IME popups.
|
||||
@@ -37,36 +35,36 @@ namespace osu.Framework.Input
|
||||
/// <remarks>
|
||||
/// Each <see cref="Activate"/> must be followed by a <see cref="Deactivate"/>.
|
||||
/// </remarks>
|
||||
public void Activate(bool allowIme, RectangleF imeRectangle)
|
||||
public void Activate(TextInputProperties properties, RectangleF imeRectangle)
|
||||
{
|
||||
if (Interlocked.Increment(ref activationCounter) == 1)
|
||||
{
|
||||
SetImeRectangle(imeRectangle);
|
||||
ActivateTextInput(allowIme);
|
||||
ActivateTextInput(properties);
|
||||
}
|
||||
else
|
||||
// the latest consumer that activated should always take precedence in (dis)allowing IME.
|
||||
EnsureActivated(allowIme, imeRectangle);
|
||||
EnsureActivated(properties, imeRectangle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the native implementation that retrieves user text input is activated
|
||||
/// and that the user can start entering text.
|
||||
/// </summary>
|
||||
/// <param name="allowIme">Whether input using IME should be allowed.</param>
|
||||
/// <param name="properties">A set of properties to consider during this text input session.</param>
|
||||
/// <param name="imeRectangle">
|
||||
/// Rough location of where the text will be input, so the native implementation
|
||||
/// can adjust virtual keyboards and IME popups. Can be <c>null</c> to avoid changing
|
||||
/// the IME rectangle.
|
||||
/// </param>
|
||||
public void EnsureActivated(bool allowIme, RectangleF? imeRectangle = null)
|
||||
public void EnsureActivated(TextInputProperties properties, RectangleF? imeRectangle = null)
|
||||
{
|
||||
if (activationCounter >= 1)
|
||||
{
|
||||
if (imeRectangle.HasValue)
|
||||
SetImeRectangle(imeRectangle.Value);
|
||||
|
||||
EnsureTextInputActivated(allowIme);
|
||||
EnsureTextInputActivated(properties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,29 +101,29 @@ namespace osu.Framework.Input
|
||||
/// <summary>
|
||||
/// Invoked on text input.
|
||||
/// </summary>
|
||||
public event Action<string> OnTextInput;
|
||||
public event Action<string>? OnTextInput;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when IME composition starts or changes.
|
||||
/// </summary>
|
||||
/// <remarks>Empty string for text means that the composition has been cancelled.</remarks>
|
||||
public event ImeCompositionDelegate OnImeComposition;
|
||||
public event ImeCompositionDelegate? OnImeComposition;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when IME composition successfully completes.
|
||||
/// </summary>
|
||||
public event Action<string> OnImeResult;
|
||||
public event Action<string>? OnImeResult;
|
||||
|
||||
/// <summary>
|
||||
/// Activates the native implementation that provides text input.
|
||||
/// Should be overriden per-platform.
|
||||
/// </summary>
|
||||
/// <param name="allowIme">Whether input using IME should be allowed.</param>
|
||||
/// <param name="properties">A set of properties to consider during this text input session.</param>
|
||||
/// <remarks>
|
||||
/// An active native implementation should call <see cref="TriggerTextInput"/> on new text input
|
||||
/// and forward IME composition events through <see cref="TriggerImeComposition"/> and <see cref="TriggerImeResult"/>.
|
||||
/// </remarks>
|
||||
protected virtual void ActivateTextInput(bool allowIme)
|
||||
protected virtual void ActivateTextInput(TextInputProperties properties)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -134,7 +132,7 @@ namespace osu.Framework.Input
|
||||
/// <remarks>
|
||||
/// Only called if the native implementation has been activated with <see cref="Activate"/>.
|
||||
/// </remarks>
|
||||
protected virtual void EnsureTextInputActivated(bool allowIme)
|
||||
protected virtual void EnsureTextInputActivated(TextInputProperties properties)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
74
osu.Framework/Input/TextInputType.cs
Normal file
74
osu.Framework/Input/TextInputType.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
namespace osu.Framework.Input
|
||||
{
|
||||
public enum TextInputType
|
||||
{
|
||||
/// <summary>
|
||||
/// Plain text, default type of text input.
|
||||
/// </summary>
|
||||
Text,
|
||||
|
||||
/// <summary>
|
||||
/// The text input is a person's name.
|
||||
/// </summary>
|
||||
Name,
|
||||
|
||||
/// <summary>
|
||||
/// The text input is an email address.
|
||||
/// </summary>
|
||||
EmailAddress,
|
||||
|
||||
/// <summary>
|
||||
/// The text input is a username.
|
||||
/// </summary>
|
||||
Username,
|
||||
|
||||
/// <summary>
|
||||
/// The text input is numerical.
|
||||
/// </summary>
|
||||
Number,
|
||||
|
||||
/// <summary>
|
||||
/// The text input is a password hidden from the user.
|
||||
/// </summary>
|
||||
Password,
|
||||
|
||||
/// <summary>
|
||||
/// The text input is a numerical password hidden from the user.
|
||||
/// </summary>
|
||||
NumericalPassword,
|
||||
}
|
||||
|
||||
public static class TextInputTypeExtensions
|
||||
{
|
||||
public static bool IsPassword(this TextInputType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TextInputType.Password:
|
||||
case TextInputType.NumericalPassword:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsNumerical(this TextInputType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case TextInputType.Number:
|
||||
case TextInputType.NumericalPassword:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SupportsIme(this TextInputType type) => type == TextInputType.Name || type == TextInputType.Text;
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ namespace osu.Framework.Platform
|
||||
|
||||
void UpdateMousePosition(Vector2 position);
|
||||
|
||||
void StartTextInput(bool allowIme);
|
||||
void StartTextInput(TextInputProperties properties);
|
||||
void StopTextInput();
|
||||
void SetTextInputRect(RectangleF rectangle);
|
||||
void ResetIme();
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace osu.Framework.Platform.SDL2
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void StartTextInput(bool allowIme) => ScheduleCommand(SDL_StartTextInput);
|
||||
public virtual void StartTextInput(TextInputProperties properties) => ScheduleCommand(SDL_StartTextInput);
|
||||
|
||||
public void StopTextInput() => ScheduleCommand(SDL_StopTextInput);
|
||||
|
||||
|
||||
@@ -1011,6 +1011,34 @@ namespace osu.Framework.Platform.SDL3
|
||||
w = rectangle.Width,
|
||||
};
|
||||
|
||||
public static SDL_TextInputType ToSDLTextInputType(this TextInputType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
case TextInputType.Text:
|
||||
return SDL_TextInputType.SDL_TEXTINPUT_TYPE_TEXT;
|
||||
|
||||
case TextInputType.Name:
|
||||
return SDL_TextInputType.SDL_TEXTINPUT_TYPE_TEXT_NAME;
|
||||
|
||||
case TextInputType.EmailAddress:
|
||||
return SDL_TextInputType.SDL_TEXTINPUT_TYPE_TEXT_EMAIL;
|
||||
|
||||
case TextInputType.Username:
|
||||
return SDL_TextInputType.SDL_TEXTINPUT_TYPE_TEXT_USERNAME;
|
||||
|
||||
case TextInputType.Number:
|
||||
return SDL_TextInputType.SDL_TEXTINPUT_TYPE_NUMBER;
|
||||
|
||||
case TextInputType.Password:
|
||||
return SDL_TextInputType.SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN;
|
||||
|
||||
case TextInputType.NumericalPassword:
|
||||
return SDL_TextInputType.SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe DisplayMode ToDisplayMode(this SDL_DisplayMode mode, int displayIndex)
|
||||
{
|
||||
int bpp;
|
||||
|
||||
@@ -187,7 +187,16 @@ namespace osu.Framework.Platform.SDL3
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void StartTextInput(bool allowIme) => ScheduleCommand(() => SDL_StartTextInput(SDLWindowHandle));
|
||||
private SDL_PropertiesID? currentTextInputProperties;
|
||||
|
||||
public virtual void StartTextInput(TextInputProperties properties) => ScheduleCommand(() =>
|
||||
{
|
||||
currentTextInputProperties ??= SDL_CreateProperties();
|
||||
|
||||
var props = currentTextInputProperties.Value;
|
||||
SDL_SetNumberProperty(props, SDL_PROP_TEXTINPUT_TYPE_NUMBER, (long)properties.Type.ToSDLTextInputType());
|
||||
SDL_StartTextInputWithProperties(SDLWindowHandle, props);
|
||||
});
|
||||
|
||||
public void StopTextInput() => ScheduleCommand(() => SDL_StopTextInput(SDLWindowHandle));
|
||||
|
||||
@@ -198,7 +207,11 @@ namespace osu.Framework.Platform.SDL3
|
||||
public virtual void ResetIme() => ScheduleCommand(() =>
|
||||
{
|
||||
SDL_StopTextInput(SDLWindowHandle);
|
||||
SDL_StartTextInput(SDLWindowHandle);
|
||||
|
||||
if (currentTextInputProperties is SDL_PropertiesID props)
|
||||
SDL_StartTextInputWithProperties(SDLWindowHandle, props);
|
||||
else
|
||||
SDL_StartTextInput(SDLWindowHandle);
|
||||
});
|
||||
|
||||
public void SetTextInputRect(RectangleF rect) => ScheduleCommand(() =>
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Handlers.Mouse;
|
||||
using osu.Framework.Platform.SDL2;
|
||||
using osu.Framework.Platform.Windows.Native;
|
||||
@@ -138,10 +139,10 @@ namespace osu.Framework.Platform.Windows
|
||||
|
||||
#region IME handling
|
||||
|
||||
public override void StartTextInput(bool allowIme)
|
||||
public override void StartTextInput(TextInputProperties properties)
|
||||
{
|
||||
base.StartTextInput(allowIme);
|
||||
ScheduleCommand(() => Imm.SetImeAllowed(WindowHandle, allowIme));
|
||||
base.StartTextInput(properties);
|
||||
ScheduleCommand(() => Imm.SetImeAllowed(WindowHandle, properties.Type.SupportsIme() && properties.AllowIme));
|
||||
}
|
||||
|
||||
public override void ResetIme() => ScheduleCommand(() => Imm.CancelComposition(WindowHandle));
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Handlers.Mouse;
|
||||
using osu.Framework.Platform.SDL3;
|
||||
using osu.Framework.Platform.Windows.Native;
|
||||
@@ -92,10 +93,10 @@ namespace osu.Framework.Platform.Windows
|
||||
}
|
||||
}
|
||||
|
||||
public override void StartTextInput(bool allowIme)
|
||||
public override void StartTextInput(TextInputProperties properties)
|
||||
{
|
||||
base.StartTextInput(allowIme);
|
||||
ScheduleCommand(() => Imm.SetImeAllowed(WindowHandle, allowIme));
|
||||
base.StartTextInput(properties);
|
||||
ScheduleCommand(() => Imm.SetImeAllowed(WindowHandle, properties.Type.SupportsIme() && properties.AllowIme));
|
||||
}
|
||||
|
||||
public override void ResetIme() => ScheduleCommand(() => Imm.CancelComposition(WindowHandle));
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace osu.Framework.Testing.Input
|
||||
{
|
||||
public class ManualTextInputSource : TextInputSource
|
||||
{
|
||||
public readonly Queue<bool> ActivationQueue = new Queue<bool>();
|
||||
public readonly Queue<bool> EnsureActivatedQueue = new Queue<bool>();
|
||||
public readonly Queue<TextInputProperties> ActivationQueue = new Queue<TextInputProperties>();
|
||||
public readonly Queue<TextInputProperties> EnsureActivatedQueue = new Queue<TextInputProperties>();
|
||||
public readonly Queue<bool> DeactivationQueue = new Queue<bool>();
|
||||
|
||||
public void Text(string text) => TriggerTextInput(text);
|
||||
@@ -32,16 +32,16 @@ namespace osu.Framework.Testing.Input
|
||||
base.TriggerImeComposition(string.Empty, 0, 0);
|
||||
}
|
||||
|
||||
protected override void ActivateTextInput(bool allowIme)
|
||||
protected override void ActivateTextInput(TextInputProperties properties)
|
||||
{
|
||||
base.ActivateTextInput(allowIme);
|
||||
ActivationQueue.Enqueue(allowIme);
|
||||
base.ActivateTextInput(properties);
|
||||
ActivationQueue.Enqueue(properties);
|
||||
}
|
||||
|
||||
protected override void EnsureTextInputActivated(bool allowIme)
|
||||
protected override void EnsureTextInputActivated(TextInputProperties properties)
|
||||
{
|
||||
base.EnsureTextInputActivated(allowIme);
|
||||
EnsureActivatedQueue.Enqueue(allowIme);
|
||||
base.EnsureTextInputActivated(properties);
|
||||
EnsureActivatedQueue.Enqueue(properties);
|
||||
}
|
||||
|
||||
protected override void DeactivateTextInput()
|
||||
|
||||
Reference in New Issue
Block a user