Merge pull request #6408 from frenzibyte/text-input-properties

Allow `TextBox` to specify type of text being input
This commit is contained in:
Dean Herbert
2025-01-14 14:35:33 +09:00
committed by GitHub
20 changed files with 241 additions and 130 deletions

View File

@@ -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);

View File

@@ -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>();

View File

@@ -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);
}
}

View File

@@ -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()

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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; }
}
}

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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()

View 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);
}

View File

@@ -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)
{
}

View 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;
}
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -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;

View File

@@ -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(() =>

View File

@@ -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));

View File

@@ -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));

View File

@@ -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()