Check KeyboardMode in GUI (#4343)

* Update SoftwareKeyboard to send KeyboardMode to UI

* Update GTK UI to check text against KeyboardMode

* Update Ava UI to check text against KeyboardMode

* Restructure input validation

* true when text is not empty

* Add English validation text for SoftwareKeyboardMode

* Add Chinese validation text for SoftwareKeyboardMode

* Update base on feedback

---------

Co-authored-by: TSR Berry <20988865+TSRBerry@users.noreply.github.com>
This commit is contained in:
WilliamWsyHK 2023-06-04 11:30:24 +08:00 committed by GitHub
parent 21c9ac6240
commit d511c845b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 109 additions and 22 deletions

View File

@ -544,6 +544,9 @@
"SwkbdMinCharacters": "Must be at least {0} characters long", "SwkbdMinCharacters": "Must be at least {0} characters long",
"SwkbdMinRangeCharacters": "Must be {0}-{1} characters long", "SwkbdMinRangeCharacters": "Must be {0}-{1} characters long",
"SoftwareKeyboard": "Software Keyboard", "SoftwareKeyboard": "Software Keyboard",
"SoftwareKeyboardModeNumbersOnly": "Must be numbers only",
"SoftwareKeyboardModeAlphabet": "Must be alphabets only",
"SoftwareKeyboardModeASCII": "Must be ASCII text only",
"DialogControllerAppletMessagePlayerRange": "Application requests {0} player(s) with:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}Please open Settings and reconfigure Input now or press Close.", "DialogControllerAppletMessagePlayerRange": "Application requests {0} player(s) with:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}Please open Settings and reconfigure Input now or press Close.",
"DialogControllerAppletMessage": "Application requests exactly {0} player(s) with:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}Please open Settings and reconfigure Input now or press Close.", "DialogControllerAppletMessage": "Application requests exactly {0} player(s) with:\n\nTYPES: {1}\n\nPLAYERS: {2}\n\n{3}Please open Settings and reconfigure Input now or press Close.",
"DialogControllerAppletDockModeSet": "Docked mode set. Handheld is also invalid.\n\n", "DialogControllerAppletDockModeSet": "Docked mode set. Handheld is also invalid.\n\n",

View File

@ -527,6 +527,9 @@
"SwkbdMinCharacters": "至少应为 {0} 个字长", "SwkbdMinCharacters": "至少应为 {0} 个字长",
"SwkbdMinRangeCharacters": "必须为 {0}-{1} 个字长", "SwkbdMinRangeCharacters": "必须为 {0}-{1} 个字长",
"SoftwareKeyboard": "软件键盘", "SoftwareKeyboard": "软件键盘",
"SoftwareKeyboardModeNumbersOnly": "只接受数字",
"SoftwareKeyboardModeAlphabet": "只接受英文字母",
"SoftwareKeyboardModeASCII": "只接受 ASCII 符号",
"DialogControllerAppletMessagePlayerRange": "游戏需要 {0} 个玩家并满足以下要求:\n\n手柄类型{1}\n\n玩家类型{2}\n\n{3}请打开设置窗口,重新配置手柄输入;或者关闭返回。", "DialogControllerAppletMessagePlayerRange": "游戏需要 {0} 个玩家并满足以下要求:\n\n手柄类型{1}\n\n玩家类型{2}\n\n{3}请打开设置窗口,重新配置手柄输入;或者关闭返回。",
"DialogControllerAppletMessage": "游戏需要刚好 {0} 个玩家并满足以下要求:\n\n手柄类型{1}\n\n玩家类型{2}\n\n{3}请打开设置窗口,重新配置手柄输入;或者关闭返回。", "DialogControllerAppletMessage": "游戏需要刚好 {0} 个玩家并满足以下要求:\n\n手柄类型{1}\n\n玩家类型{2}\n\n{3}请打开设置窗口,重新配置手柄输入;或者关闭返回。",
"DialogControllerAppletDockModeSet": "目前处于主机模式,无法使用掌机操作方式", "DialogControllerAppletDockModeSet": "目前处于主机模式,无法使用掌机操作方式",

View File

@ -527,6 +527,9 @@
"SwkbdMinCharacters": "至少應為 {0} 個字長", "SwkbdMinCharacters": "至少應為 {0} 個字長",
"SwkbdMinRangeCharacters": "必須為 {0}-{1} 個字長", "SwkbdMinRangeCharacters": "必須為 {0}-{1} 個字長",
"SoftwareKeyboard": "軟體鍵盤", "SoftwareKeyboard": "軟體鍵盤",
"SoftwareKeyboardModeNumbersOnly": "只接受數字",
"SoftwareKeyboardModeAlphabet": "只接受英文字母",
"SoftwareKeyboardModeASCII": "只接受 ASCII 符號",
"DialogControllerAppletMessagePlayerRange": "本遊戲需要 {0} 個玩家持有:\n\n類型{1}\n\n玩家{2}\n\n{3}請打開設定畫面,配置手把,或者關閉本視窗。", "DialogControllerAppletMessagePlayerRange": "本遊戲需要 {0} 個玩家持有:\n\n類型{1}\n\n玩家{2}\n\n{3}請打開設定畫面,配置手把,或者關閉本視窗。",
"DialogControllerAppletMessage": "本遊戲需要剛好 {0} 個玩家持有:\n\n類型{1}\n\n玩家{2}\n\n{3}請打開設定畫面,配置手把,或者關閉本視窗。", "DialogControllerAppletMessage": "本遊戲需要剛好 {0} 個玩家持有:\n\n類型{1}\n\n玩家{2}\n\n{3}請打開設定畫面,配置手把,或者關閉本視窗。",
"DialogControllerAppletDockModeSet": "現在處於主機模式,無法使用掌機操作方式\n\n", "DialogControllerAppletDockModeSet": "現在處於主機模式,無法使用掌機操作方式\n\n",

View File

@ -9,14 +9,17 @@ using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Applets;
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
using System; using System;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Controls namespace Ryujinx.Ava.UI.Controls
{ {
internal partial class SwkbdAppletDialog : UserControl internal partial class SwkbdAppletDialog : UserControl
{ {
private Predicate<int> _checkLength; private Predicate<int> _checkLength = _ => true;
private Predicate<string> _checkInput = _ => true;
private int _inputMax; private int _inputMax;
private int _inputMin; private int _inputMin;
private string _placeholder; private string _placeholder;
@ -35,8 +38,6 @@ namespace Ryujinx.Ava.UI.Controls
Input.Watermark = _placeholder; Input.Watermark = _placeholder;
Input.AddHandler(TextInputEvent, Message_TextInput, RoutingStrategies.Tunnel, true); Input.AddHandler(TextInputEvent, Message_TextInput, RoutingStrategies.Tunnel, true);
SetInputLengthValidation(0, int.MaxValue); // Disable by default.
} }
public SwkbdAppletDialog() public SwkbdAppletDialog()
@ -67,6 +68,7 @@ namespace Ryujinx.Ava.UI.Controls
string input = string.Empty; string input = string.Empty;
content.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax); content.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);
content.SetInputValidation(args.KeyboardMode);
content._host = contentDialog; content._host = contentDialog;
contentDialog.Title = title; contentDialog.Title = title;
@ -91,6 +93,12 @@ namespace Ryujinx.Ava.UI.Controls
return (result, input); return (result, input);
} }
private void ApplyValidationInfo(string text)
{
Error.IsVisible = !string.IsNullOrEmpty(text);
Error.Text = text;
}
public void SetInputLengthValidation(int min, int max) public void SetInputLengthValidation(int min, int max)
{ {
_inputMin = Math.Min(min, max); _inputMin = Math.Min(min, max);
@ -99,6 +107,8 @@ namespace Ryujinx.Ava.UI.Controls
Error.IsVisible = false; Error.IsVisible = false;
Error.FontStyle = FontStyle.Italic; Error.FontStyle = FontStyle.Italic;
string validationInfoText = "";
if (_inputMin <= 0 && _inputMax == int.MaxValue) // Disable. if (_inputMin <= 0 && _inputMax == int.MaxValue) // Disable.
{ {
Error.IsVisible = false; Error.IsVisible = false;
@ -107,21 +117,48 @@ namespace Ryujinx.Ava.UI.Controls
} }
else if (_inputMin > 0 && _inputMax == int.MaxValue) else if (_inputMin > 0 && _inputMax == int.MaxValue)
{ {
Error.IsVisible = true; validationInfoText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SwkbdMinCharacters, _inputMin);
Error.Text = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SwkbdMinCharacters, _inputMin);
_checkLength = length => _inputMin <= length; _checkLength = length => _inputMin <= length;
} }
else else
{ {
Error.IsVisible = true; validationInfoText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SwkbdMinRangeCharacters, _inputMin, _inputMax);
Error.Text = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SwkbdMinRangeCharacters, _inputMin, _inputMax);
_checkLength = length => _inputMin <= length && length <= _inputMax; _checkLength = length => _inputMin <= length && length <= _inputMax;
} }
ApplyValidationInfo(validationInfoText);
Message_TextInput(this, new TextInputEventArgs());
}
private void SetInputValidation(KeyboardMode mode)
{
string validationInfoText = Error.Text;
string localeText;
switch (mode)
{
case KeyboardMode.NumbersOnly:
localeText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SoftwareKeyboardModeNumbersOnly);
validationInfoText = string.IsNullOrEmpty(validationInfoText) ? localeText : string.Join("\n", validationInfoText, localeText);
_checkInput = text => text.All(char.IsDigit);
break;
case KeyboardMode.Alphabet:
localeText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SoftwareKeyboardModeAlphabet);
validationInfoText = string.IsNullOrEmpty(validationInfoText) ? localeText : string.Join("\n", validationInfoText, localeText);
_checkInput = text => text.All(char.IsAsciiLetter);
break;
case KeyboardMode.ASCII:
localeText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SoftwareKeyboardModeASCII);
validationInfoText = string.IsNullOrEmpty(validationInfoText) ? localeText : string.Join("\n", validationInfoText, localeText);
_checkInput = text => text.All(char.IsAscii);
break;
default:
_checkInput = _ => true;
break;
}
ApplyValidationInfo(validationInfoText);
Message_TextInput(this, new TextInputEventArgs()); Message_TextInput(this, new TextInputEventArgs());
} }
@ -129,7 +166,7 @@ namespace Ryujinx.Ava.UI.Controls
{ {
if (_host != null) if (_host != null)
{ {
_host.IsPrimaryButtonEnabled = _checkLength(Message.Length); _host.IsPrimaryButtonEnabled = _checkLength(Message.Length) && _checkInput(Message);
} }
} }
@ -141,7 +178,7 @@ namespace Ryujinx.Ava.UI.Controls
} }
else else
{ {
_host.IsPrimaryButtonEnabled = _checkLength(Message.Length); _host.IsPrimaryButtonEnabled = _checkLength(Message.Length) && _checkInput(Message);
} }
} }
} }

View File

@ -3,7 +3,7 @@
/// <summary> /// <summary>
/// Identifies the variant of keyboard displayed on screen. /// Identifies the variant of keyboard displayed on screen.
/// </summary> /// </summary>
enum KeyboardMode : uint public enum KeyboardMode : uint
{ {
/// <summary> /// <summary>
/// A full alpha-numeric keyboard. /// A full alpha-numeric keyboard.

View File

@ -209,6 +209,7 @@ namespace Ryujinx.HLE.HOS.Applets
// Call the configured GUI handler to get user's input. // Call the configured GUI handler to get user's input.
var args = new SoftwareKeyboardUiArgs var args = new SoftwareKeyboardUiArgs
{ {
KeyboardMode = _keyboardForegroundConfig.Mode,
HeaderText = StripUnicodeControlCodes(_keyboardForegroundConfig.HeaderText), HeaderText = StripUnicodeControlCodes(_keyboardForegroundConfig.HeaderText),
SubtitleText = StripUnicodeControlCodes(_keyboardForegroundConfig.SubtitleText), SubtitleText = StripUnicodeControlCodes(_keyboardForegroundConfig.SubtitleText),
GuideText = StripUnicodeControlCodes(_keyboardForegroundConfig.GuideText), GuideText = StripUnicodeControlCodes(_keyboardForegroundConfig.GuideText),

View File

@ -1,7 +1,10 @@
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
namespace Ryujinx.HLE.HOS.Applets namespace Ryujinx.HLE.HOS.Applets
{ {
public struct SoftwareKeyboardUiArgs public struct SoftwareKeyboardUiArgs
{ {
public KeyboardMode KeyboardMode;
public string HeaderText; public string HeaderText;
public string SubtitleText; public string SubtitleText;
public string InitialText; public string InitialText;

View File

@ -106,6 +106,7 @@ namespace Ryujinx.Ui.Applet
swkbdDialog.OkButton.Label = args.SubmitText; swkbdDialog.OkButton.Label = args.SubmitText;
swkbdDialog.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax); swkbdDialog.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);
swkbdDialog.SetInputValidation(args.KeyboardMode);
if (swkbdDialog.Run() == (int)ResponseType.Ok) if (swkbdDialog.Run() == (int)ResponseType.Ok)
{ {

View File

@ -1,5 +1,7 @@
using Gtk; using Gtk;
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
using System; using System;
using System.Linq;
namespace Ryujinx.Ui.Applet namespace Ryujinx.Ui.Applet
{ {
@ -7,8 +9,12 @@ namespace Ryujinx.Ui.Applet
{ {
private int _inputMin; private int _inputMin;
private int _inputMax; private int _inputMax;
private KeyboardMode _mode;
private Predicate<int> _checkLength; private string _validationInfoText = "";
private Predicate<int> _checkLength = _ => true;
private Predicate<string> _checkInput = _ => true;
private readonly Label _validationInfo; private readonly Label _validationInfo;
@ -38,8 +44,12 @@ namespace Ryujinx.Ui.Applet
((Box)MessageArea).PackEnd(_validationInfo, true, true, 0); ((Box)MessageArea).PackEnd(_validationInfo, true, true, 0);
((Box)MessageArea).PackEnd(InputEntry, true, true, 4); ((Box)MessageArea).PackEnd(InputEntry, true, true, 4);
}
SetInputLengthValidation(0, int.MaxValue); // Disable by default. private void ApplyValidationInfo()
{
_validationInfo.Visible = !string.IsNullOrEmpty(_validationInfoText);
_validationInfo.Markup = _validationInfoText;
} }
public void SetInputLengthValidation(int min, int max) public void SetInputLengthValidation(int min, int max)
@ -53,23 +63,49 @@ namespace Ryujinx.Ui.Applet
{ {
_validationInfo.Visible = false; _validationInfo.Visible = false;
_checkLength = (length) => true; _checkLength = _ => true;
} }
else if (_inputMin > 0 && _inputMax == int.MaxValue) else if (_inputMin > 0 && _inputMax == int.MaxValue)
{ {
_validationInfo.Visible = true; _validationInfoText = $"<i>Must be at least {_inputMin} characters long.</i> ";
_validationInfo.Markup = $"<i>Must be at least {_inputMin} characters long</i>";
_checkLength = (length) => _inputMin <= length; _checkLength = length => _inputMin <= length;
} }
else else
{ {
_validationInfo.Visible = true; _validationInfoText = $"<i>Must be {_inputMin}-{_inputMax} characters long.</i> ";
_validationInfo.Markup = $"<i>Must be {_inputMin}-{_inputMax} characters long</i>";
_checkLength = (length) => _inputMin <= length && length <= _inputMax; _checkLength = length => _inputMin <= length && length <= _inputMax;
} }
ApplyValidationInfo();
OnInputChanged(this, EventArgs.Empty);
}
public void SetInputValidation(KeyboardMode mode)
{
_mode = mode;
switch (mode)
{
case KeyboardMode.NumbersOnly:
_validationInfoText += "<i>Must be numbers only.</i>";
_checkInput = text => text.All(char.IsDigit);
break;
case KeyboardMode.Alphabet:
_validationInfoText += "<i>Must be alphabets only.</i>";
_checkInput = text => text.All(char.IsAsciiLetter);
break;
case KeyboardMode.ASCII:
_validationInfoText += "<i>Must be ASCII text only.</i>";
_checkInput = text => text.All(char.IsAscii);
break;
default:
_checkInput = _ => true;
break;
}
ApplyValidationInfo();
OnInputChanged(this, EventArgs.Empty); OnInputChanged(this, EventArgs.Empty);
} }
@ -83,7 +119,7 @@ namespace Ryujinx.Ui.Applet
private void OnInputChanged(object sender, EventArgs e) private void OnInputChanged(object sender, EventArgs e)
{ {
OkButton.Sensitive = _checkLength(InputEntry.Text.Length); OkButton.Sensitive = _checkLength(InputEntry.Text.Length) && _checkInput(InputEntry.Text);
} }
} }
} }