am: Fully reverse swkbd configuration structure

This commit is contained in:
jduncanator 2019-11-30 15:31:53 +11:00
parent bb7600e215
commit 4e38cadcad
3 changed files with 236 additions and 35 deletions

View file

@ -1,4 +1,5 @@
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
using System;
using System.IO;
@ -22,7 +23,8 @@ namespace Ryujinx.HLE.HOS.Applets
private SoftwareKeyboardConfig _keyboardConfig;
private string _textValue = DEFAULT_TEXT;
private string _textValue = DEFAULT_TEXT;
private Encoding _encoding = Encoding.Unicode;
public event EventHandler AppletStateChanged;
@ -41,6 +43,7 @@ namespace Ryujinx.HLE.HOS.Applets
var transferMemory = _normalSession.Pop();
_keyboardConfig = ReadStruct<SoftwareKeyboardConfig>(keyboardConfig);
_encoding = _keyboardConfig.UseUtf8 ? Encoding.UTF8 : Encoding.Unicode;
_state = SoftwareKeyboardState.Ready;
@ -58,7 +61,7 @@ namespace Ryujinx.HLE.HOS.Applets
{
// If the keyboard type is numbers only, we swap to a default
// text that only contains numbers.
if (_keyboardConfig.Type == SoftwareKeyboardType.NumbersOnly)
if (_keyboardConfig.Mode == KeyboardMode.NumbersOnly)
{
_textValue = DEFAULT_NUMB;
}
@ -70,6 +73,15 @@ namespace Ryujinx.HLE.HOS.Applets
_keyboardConfig.StringLengthMax = 100;
}
// If the game requests a string with a minimum length less
// than our default text, repeat our default text until we meet
// the minimum length requirement.
// This should always be done before the text truncation step.
while (_textValue.Length < _keyboardConfig.StringLengthMin)
{
_textValue = String.Join(" ", _textValue, _textValue);
}
// If our default text is longer than the allowed length,
// we truncate it.
if (_textValue.Length > _keyboardConfig.StringLengthMax)
@ -77,6 +89,7 @@ namespace Ryujinx.HLE.HOS.Applets
_textValue = _textValue.Substring(0, (int)_keyboardConfig.StringLengthMax);
}
// Does the application want to validate the text itself?
if (!_keyboardConfig.CheckText)
{
// If the application doesn't need to validate the response,
@ -136,12 +149,12 @@ namespace Ryujinx.HLE.HOS.Applets
private byte[] BuildResponse(string text, bool interactive)
{
int bufferSize = !interactive ? STANDARD_BUFFER_SIZE : INTERACTIVE_BUFFER_SIZE;
int bufferSize = interactive ? INTERACTIVE_BUFFER_SIZE : STANDARD_BUFFER_SIZE;
using (MemoryStream stream = new MemoryStream(new byte[bufferSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
byte[] output = Encoding.Unicode.GetBytes(text);
byte[] output = _encoding.GetBytes(text);
if (!interactive)
{

View file

@ -2,32 +2,240 @@
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
{
// TODO(jduncanator): Define all fields
[StructLayout(LayoutKind.Explicit)]
/// <summary>
///
/// </summary>
internal enum KeyboardMode : uint
{
/// <summary>
/// Normal keyboard.
/// </summary>
Default,
/// <summary>
/// Number pad. The buttons at the bottom left/right are only available when they're set in the config by leftButtonText / rightButtonText.
/// </summary>
NumbersOnly,
/// <summary>
/// QWERTY (and variants) keyboard only.
/// </summary>
LettersOnly
}
/// <summary>
///
/// </summary>
internal enum InvalidCharFlags : uint
{
None = 0 << 1,
Space = 1 << 1,
AtSymbol = 1 << 2,
Percent = 1 << 3,
ForwardSlash = 1 << 4,
BackSlash = 1 << 5,
Numbers = 1 << 6,
DownloadCode = 1 << 7,
Username = 1 << 8
}
/// <summary>
///
/// </summary>
internal enum PasswordMode : uint
{
/// <summary>
///
/// </summary>
Disabled,
/// <summary>
///
/// </summary>
Enabled
}
/// <summary>
///
/// </summary>
internal enum InputFormMode : uint
{
/// <summary>
///
/// </summary>
SingleLine,
/// <summary>
///
/// </summary>
MultiLine
}
/// <summary>
///
/// </summary>
internal enum InitialCursorPosition : uint
{
/// <summary>
///
/// </summary>
Start,
/// <summary>
///
/// </summary>
End
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct SoftwareKeyboardConfig
{
/// <summary>
///
/// </summary>
const int SubmitTextLength = 8;
/// <summary>
///
/// </summary>
const int HeaderTextLength = 64;
/// <summary>
///
/// </summary>
const int SubtitleTextLength = 128;
/// <summary>
///
/// </summary>
const int GuideTextLength = 256;
/// <summary>
/// Type of keyboard.
/// </summary>
[FieldOffset(0x0)]
public SoftwareKeyboardType Type;
public KeyboardMode Mode;
/// <summary>
///
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = SubmitTextLength + 1)]
public string SubmitText;
/// <summary>
///
/// </summary>
public char LeftOptionalSymbolKey;
/// <summary>
///
/// </summary>
public char RightOptionalSymbolKey;
/// <summary>
///
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool PredictionEnabled;
/// <summary>
///
/// </summary>
public InvalidCharFlags InvalidCharFlag;
/// <summary>
///
/// </summary>
public InitialCursorPosition InitialCursorPosition;
/// <summary>
///
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = HeaderTextLength + 1)]
public string HeaderText;
/// <summary>
///
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = SubtitleTextLength + 1)]
public string SubtitleText;
/// <summary>
///
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = GuideTextLength + 1)]
public string GuideText;
/// <summary>
/// When non-zero, specifies the max string length. When the input is too long, swkbd will stop accepting more input until text is deleted via the B button (Backspace).
/// </summary>
[FieldOffset(0x3AC)]
public uint StringLengthMax;
public int StringLengthMax;
/// <summary>
/// When non-zero, specifies the max string length. When the input is too long, swkbd will display an icon and disable the ok-button.
/// When non-zero, specifies the minimum string length.
/// </summary>
[FieldOffset(0x3B0)]
public uint StringLengthMaxExtended;
public int StringLengthMin;
/// <summary>
///
/// </summary>
public PasswordMode PasswordMode;
/// <summary>
///
/// </summary>
public InputFormMode InputFormMode;
/// <summary>
///
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool UseNewLine;
/// <summary>
/// When set, the software keyboard will return a string UTF-8 encoded, rather than UTF-16.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool UseUtf8;
/// <summary>
///
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool UseBlurBackground;
/// <summary>
///
/// </summary>
public int InitialStringOffset;
/// <summary>
///
/// </summary>
public int InitialStringLength;
/// <summary>
///
/// </summary>
public int CustomDictionaryOffset;
/// <summary>
///
/// </summary>
public int CustomDictionaryCount;
/// <summary>
/// When set, the application will validate the entered text whilst the swkbd is still on screen.
/// </summary>
[FieldOffset(0x3D0), MarshalAs(UnmanagedType.I1)]
[MarshalAs(UnmanagedType.I1)]
public bool CheckText;
}
}

View file

@ -1,20 +0,0 @@
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
{
internal enum SoftwareKeyboardType : uint
{
/// <summary>
/// Normal keyboard.
/// </summary>
Default = 0,
/// <summary>
/// Number pad. The buttons at the bottom left/right are only available when they're set in the config by leftButtonText / rightButtonText.
/// </summary>
NumbersOnly = 1,
/// <summary>
/// QWERTY (and variants) keyboard only.
/// </summary>
LettersOnly = 2
}
}