[Ryujinx.HLE] Address dotnet-format issues (#5380)

* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Address or silence dotnet format IDE1006 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA2208 warnings

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address dotnet format CA2211 warnings

* Address dotnet format CA1822 warnings

* Address or silence dotnet format CA1069 warnings

* Make dotnet format succeed in style mode

* Address or silence dotnet format CA2211 warnings

* Address review comments

* Address dotnet format CA2208 warnings properly

* Make ProcessResult readonly

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add previously silenced warnings back

I have no clue how these disappeared

* Revert formatting changes for while and for-loops

* Format if-blocks correctly

* Run dotnet format style after rebase

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format analyzers after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Fix a few disabled warnings

* Fix naming rule violation, Convert shader properties to auto-property and convert values to const

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Run dotnet format after rebase

* Use using declaration instead of block syntax

* Address IDE0251 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Fix naming rule violations

* Fix typo

* Add trailing commas, use targeted new and use array initializer

* Fix build issues

* Fix remaining build issues

* Remove SuppressMessage for CA1069 where possible

* Address dotnet format issues

* Address formatting issues

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Add GetHashCode implementation for RenderingSurfaceInfo

* Explicitly silence CA1822 for every affected method in Syscall

* Address formatting issues in Demangler.cs

* Address review feedback

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Revert marking service methods as static

* Next dotnet format pass

* Address review feedback

---------

Co-authored-by: Ac_K <acoustik666@gmail.com>
This commit is contained in:
TSRBerry 2023-07-16 19:31:14 +02:00 committed by GitHub
parent fec8291c17
commit 326749498b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
1015 changed files with 8173 additions and 7615 deletions

View file

@ -8,7 +8,7 @@ namespace Ryujinx.HLE.HOS.Applets
{
static class AppletManager
{
private static Dictionary<AppletId, Type> _appletMapping;
private static readonly Dictionary<AppletId, Type> _appletMapping;
static AppletManager()
{
@ -20,7 +20,7 @@ namespace Ryujinx.HLE.HOS.Applets
{ AppletId.SoftwareKeyboard, typeof(SoftwareKeyboardApplet) },
{ AppletId.LibAppletWeb, typeof(BrowserApplet) },
{ AppletId.LibAppletShop, typeof(BrowserApplet) },
{ AppletId.LibAppletOff, typeof(BrowserApplet) }
{ AppletId.LibAppletOff, typeof(BrowserApplet) },
};
}

View file

@ -6,6 +6,6 @@
Offline,
Black,
Share,
Lobby
Lobby,
}
}

View file

@ -13,13 +13,12 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
public event EventHandler AppletStateChanged;
private AppletSession _normalSession;
private AppletSession _interactiveSession;
private CommonArguments _commonArguments;
private List<BrowserArgument> _arguments;
private ShimKind _shimKind;
public BrowserApplet(Horizon system) {}
public BrowserApplet(Horizon system) { }
public ResultCode GetResult()
{
@ -29,7 +28,6 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
{
_normalSession = normalSession;
_interactiveSession = interactiveSession;
_commonArguments = IApplet.ReadStruct<CommonArguments>(_normalSession.Pop());
@ -48,17 +46,18 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
if ((_commonArguments.AppletVersion >= 0x80000 && _shimKind == ShimKind.Web) || (_commonArguments.AppletVersion >= 0x30000 && _shimKind == ShimKind.Share))
{
List<BrowserOutput> result = new List<BrowserOutput>();
result.Add(new BrowserOutput(BrowserOutputType.ExitReason, (uint)WebExitReason.ExitButton));
List<BrowserOutput> result = new()
{
new BrowserOutput(BrowserOutputType.ExitReason, (uint)WebExitReason.ExitButton),
};
_normalSession.Push(BuildResponseNew(result));
}
else
{
WebCommonReturnValue result = new WebCommonReturnValue()
WebCommonReturnValue result = new()
{
ExitReason = WebExitReason.ExitButton,
ExitReason = WebExitReason.ExitButton,
};
_normalSession.Push(BuildResponseOld(result));
@ -69,36 +68,32 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
return ResultCode.Success;
}
private byte[] BuildResponseOld(WebCommonReturnValue result)
private static byte[] BuildResponseOld(WebCommonReturnValue result)
{
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.WriteStruct(result);
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
using BinaryWriter writer = new(stream);
writer.WriteStruct(result);
return stream.ToArray();
}
return stream.ToArray();
}
private byte[] BuildResponseNew(List<BrowserOutput> outputArguments)
{
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
using (BinaryWriter writer = new BinaryWriter(stream))
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
using BinaryWriter writer = new(stream);
writer.WriteStruct(new WebArgHeader
{
writer.WriteStruct(new WebArgHeader
{
Count = (ushort)outputArguments.Count,
ShimKind = _shimKind
});
Count = (ushort)outputArguments.Count,
ShimKind = _shimKind,
});
foreach (BrowserOutput output in outputArguments)
{
output.Write(writer);
}
writer.Write(new byte[0x2000 - writer.BaseStream.Position]);
return stream.ToArray();
foreach (BrowserOutput output in outputArguments)
{
output.Write(writer);
}
writer.Write(new byte[0x2000 - writer.BaseStream.Position]);
return stream.ToArray();
}
}
}

View file

@ -8,16 +8,16 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
{
class BrowserArgument
{
public WebArgTLVType Type { get; }
public byte[] Value { get; }
public WebArgTLVType Type { get; }
public byte[] Value { get; }
public BrowserArgument(WebArgTLVType type, byte[] value)
{
Type = type;
Type = type;
Value = value;
}
private static readonly Dictionary<WebArgTLVType, Type> _typeRegistry = new Dictionary<WebArgTLVType, Type>
private static readonly Dictionary<WebArgTLVType, Type> _typeRegistry = new()
{
{ WebArgTLVType.InitialURL, typeof(string) },
{ WebArgTLVType.CallbackUrl, typeof(string) },
@ -64,11 +64,11 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
public static (ShimKind, List<BrowserArgument>) ParseArguments(ReadOnlySpan<byte> data)
{
List<BrowserArgument> browserArguments = new List<BrowserArgument>();
List<BrowserArgument> browserArguments = new();
WebArgHeader header = IApplet.ReadStruct<WebArgHeader>(data.Slice(0, 8));
WebArgHeader header = IApplet.ReadStruct<WebArgHeader>(data[..8]);
ReadOnlySpan<byte> rawTLVs = data.Slice(8);
ReadOnlySpan<byte> rawTLVs = data[8..];
for (int i = 0; i < header.Count; i++)
{
@ -77,7 +77,7 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
browserArguments.Add(new BrowserArgument((WebArgTLVType)tlv.Type, tlvData.ToArray()));
rawTLVs = rawTLVs.Slice(Unsafe.SizeOf<WebArgTLV>() + tlv.Size);
rawTLVs = rawTLVs[(Unsafe.SizeOf<WebArgTLV>() + tlv.Size)..];
}
return (header.ShimKind, browserArguments);

View file

@ -11,25 +11,25 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
public BrowserOutput(BrowserOutputType type, byte[] value)
{
Type = type;
Type = type;
Value = value;
}
public BrowserOutput(BrowserOutputType type, uint value)
{
Type = type;
Value = BitConverter.GetBytes(value);
Type = type;
Value = BitConverter.GetBytes(value);
}
public BrowserOutput(BrowserOutputType type, ulong value)
{
Type = type;
Type = type;
Value = BitConverter.GetBytes(value);
}
public BrowserOutput(BrowserOutputType type, bool value)
{
Type = type;
Type = type;
Value = BitConverter.GetBytes(value);
}
@ -38,7 +38,7 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
writer.WriteStruct(new WebArgTLV
{
Type = (ushort)Type,
Size = (ushort)Value.Length
Size = (ushort)Value.Length,
});
writer.Write(Value);

View file

@ -2,13 +2,13 @@
{
enum BrowserOutputType : ushort
{
ExitReason = 0x1,
LastUrl = 0x2,
LastUrlSize = 0x3,
SharePostResult = 0x4,
PostServiceName = 0x5,
PostServiceNameSize = 0x6,
PostId = 0x7,
MediaPlayerAutoClosedByCompletion = 0x8
ExitReason = 0x1,
LastUrl = 0x2,
LastUrlSize = 0x3,
SharePostResult = 0x4,
PostServiceName = 0x5,
PostServiceNameSize = 0x6,
PostId = 0x7,
MediaPlayerAutoClosedByCompletion = 0x8,
}
}

View file

@ -4,6 +4,6 @@
{
OfflineHtmlPage = 1,
ApplicationLegalInformation,
SystemDataPage
SystemDataPage,
}
}

View file

@ -3,6 +3,6 @@
enum LeftStickMode
{
Pointer = 0,
Cursor
Cursor,
}
}

View file

@ -8,6 +8,6 @@
Share,
Web,
Wifi,
Lobby
Lobby,
}
}

View file

@ -2,8 +2,8 @@
{
public struct WebArgHeader
{
public ushort Count;
public ushort Padding;
public ushort Count;
public ushort Padding;
public ShimKind ShimKind;
}
}

View file

@ -4,6 +4,6 @@
{
public ushort Type;
public ushort Size;
public uint Padding;
public uint Padding;
}
}

View file

@ -2,61 +2,61 @@
{
enum WebArgTLVType : ushort
{
InitialURL = 0x1,
CallbackUrl = 0x3,
CallbackableUrl = 0x4,
ApplicationId = 0x5,
DocumentPath = 0x6,
DocumentKind = 0x7,
SystemDataId = 0x8,
ShareStartPage = 0x9,
Whitelist = 0xA,
NewsFlag = 0xB,
UserID = 0xE,
AlbumEntry0 = 0xF,
ScreenShotEnabled = 0x10,
EcClientCertEnabled = 0x11,
PlayReportEnabled = 0x13,
UnknownFlag0x14 = 0x14,
UnknownFlag0x15 = 0x15,
BootDisplayKind = 0x17,
BackgroundKind = 0x18,
FooterEnabled = 0x19,
PointerEnabled = 0x1A,
LeftStickMode = 0x1B,
KeyRepeatFrame1 = 0x1C,
KeyRepeatFrame2 = 0x1D,
BootAsMediaPlayerInverted = 0x1E,
DisplayUrlKind = 0x1F,
BootAsMediaPlayer = 0x21,
ShopJumpEnabled = 0x22,
MediaAutoPlayEnabled = 0x23,
LobbyParameter = 0x24,
ApplicationAlbumEntry = 0x26,
JsExtensionEnabled = 0x27,
AdditionalCommentText = 0x28,
TouchEnabledOnContents = 0x29,
UserAgentAdditionalString = 0x2A,
AdditionalMediaData0 = 0x2B,
MediaPlayerAutoCloseEnabled = 0x2C,
PageCacheEnabled = 0x2D,
WebAudioEnabled = 0x2E,
FooterFixedKind = 0x32,
PageFadeEnabled = 0x33,
InitialURL = 0x1,
CallbackUrl = 0x3,
CallbackableUrl = 0x4,
ApplicationId = 0x5,
DocumentPath = 0x6,
DocumentKind = 0x7,
SystemDataId = 0x8,
ShareStartPage = 0x9,
Whitelist = 0xA,
NewsFlag = 0xB,
UserID = 0xE,
AlbumEntry0 = 0xF,
ScreenShotEnabled = 0x10,
EcClientCertEnabled = 0x11,
PlayReportEnabled = 0x13,
UnknownFlag0x14 = 0x14,
UnknownFlag0x15 = 0x15,
BootDisplayKind = 0x17,
BackgroundKind = 0x18,
FooterEnabled = 0x19,
PointerEnabled = 0x1A,
LeftStickMode = 0x1B,
KeyRepeatFrame1 = 0x1C,
KeyRepeatFrame2 = 0x1D,
BootAsMediaPlayerInverted = 0x1E,
DisplayUrlKind = 0x1F,
BootAsMediaPlayer = 0x21,
ShopJumpEnabled = 0x22,
MediaAutoPlayEnabled = 0x23,
LobbyParameter = 0x24,
ApplicationAlbumEntry = 0x26,
JsExtensionEnabled = 0x27,
AdditionalCommentText = 0x28,
TouchEnabledOnContents = 0x29,
UserAgentAdditionalString = 0x2A,
AdditionalMediaData0 = 0x2B,
MediaPlayerAutoCloseEnabled = 0x2C,
PageCacheEnabled = 0x2D,
WebAudioEnabled = 0x2E,
FooterFixedKind = 0x32,
PageFadeEnabled = 0x33,
MediaCreatorApplicationRatingAge = 0x34,
BootLoadingIconEnabled = 0x35,
PageScrollIndicatorEnabled = 0x36,
MediaPlayerSpeedControlEnabled = 0x37,
AlbumEntry1 = 0x38,
AlbumEntry2 = 0x39,
AlbumEntry3 = 0x3A,
AdditionalMediaData1 = 0x3B,
AdditionalMediaData2 = 0x3C,
AdditionalMediaData3 = 0x3D,
BootFooterButton = 0x3E,
OverrideWebAudioVolume = 0x3F,
OverrideMediaAudioVolume = 0x40,
BootMode = 0x41,
MediaPlayerUiEnabled = 0x43
BootLoadingIconEnabled = 0x35,
PageScrollIndicatorEnabled = 0x36,
MediaPlayerSpeedControlEnabled = 0x37,
AlbumEntry1 = 0x38,
AlbumEntry2 = 0x39,
AlbumEntry3 = 0x3A,
AdditionalMediaData1 = 0x3B,
AdditionalMediaData2 = 0x3C,
AdditionalMediaData3 = 0x3D,
BootFooterButton = 0x3E,
OverrideWebAudioVolume = 0x3F,
OverrideMediaAudioVolume = 0x40,
BootMode = 0x41,
MediaPlayerUiEnabled = 0x43,
}
}

View file

@ -5,8 +5,8 @@ namespace Ryujinx.HLE.HOS.Applets.Browser
public struct WebCommonReturnValue
{
public WebExitReason ExitReason;
public uint Padding;
public uint Padding;
public ByteArray4096 LastUrl;
public ulong LastUrlSize;
public ulong LastUrlSize;
}
}

View file

@ -6,6 +6,6 @@
BackButton,
Requested,
LastUrl,
ErrorDialog = 7
ErrorDialog = 7,
}
}

View file

@ -5,12 +5,12 @@ namespace Ryujinx.HLE.HOS.Applets
[StructLayout(LayoutKind.Sequential, Pack = 8)]
struct CommonArguments
{
public uint Version;
public uint StructureSize;
public uint AppletVersion;
public uint ThemeColor;
public uint Version;
public uint StructureSize;
public uint AppletVersion;
public uint ThemeColor;
[MarshalAs(UnmanagedType.I1)]
public bool PlayStartupSound;
public bool PlayStartupSound;
public ulong SystemTicks;
}
}

View file

@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Applets
{
internal class ControllerApplet : IApplet
{
private Horizon _system;
private readonly Horizon _system;
private AppletSession _normalSession;
@ -65,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Applets
}
else
{
Logger.Stub?.PrintStub(LogClass.ServiceHid, $"ControllerSupportArg Version Unknown");
Logger.Stub?.PrintStub(LogClass.ServiceHid, "ControllerSupportArg Version Unknown");
argHeader = IApplet.ReadStruct<ControllerSupportArgHeader>(controllerSupportArg); // Read just the header
}
@ -82,17 +82,17 @@ namespace Ryujinx.HLE.HOS.Applets
playerMin = playerMax = 1;
}
int configuredCount = 0;
PlayerIndex primaryIndex = PlayerIndex.Unknown;
int configuredCount;
PlayerIndex primaryIndex;
while (!_system.Device.Hid.Npads.Validate(playerMin, playerMax, (ControllerType)privateArg.NpadStyleSet, out configuredCount, out primaryIndex))
{
ControllerAppletUiArgs uiArgs = new ControllerAppletUiArgs
ControllerAppletUiArgs uiArgs = new()
{
PlayerCountMin = playerMin,
PlayerCountMax = playerMax,
SupportedStyles = (ControllerType)privateArg.NpadStyleSet,
SupportedPlayers = _system.Device.Hid.Npads.GetSupportedPlayers(),
IsDocked = _system.State.DockedMode
IsDocked = _system.State.DockedMode,
};
if (!_system.Device.UiHandler.DisplayMessageDialog(uiArgs))
@ -101,10 +101,10 @@ namespace Ryujinx.HLE.HOS.Applets
}
}
ControllerSupportResultInfo result = new ControllerSupportResultInfo
ControllerSupportResultInfo result = new()
{
PlayerCount = (sbyte)configuredCount,
SelectedId = (uint)GetNpadIdTypeFromIndex(primaryIndex)
SelectedId = (uint)GetNpadIdTypeFromIndex(primaryIndex),
};
Logger.Stub?.PrintStub(LogClass.ServiceHid, $"ControllerApplet ReturnResult {result.PlayerCount} {result.SelectedId}");
@ -122,26 +122,24 @@ namespace Ryujinx.HLE.HOS.Applets
return ResultCode.Success;
}
private byte[] BuildResponse(ControllerSupportResultInfo result)
private static byte[] BuildResponse(ControllerSupportResultInfo result)
{
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref result, Unsafe.SizeOf<ControllerSupportResultInfo>())));
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
writer.Write(MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref result, Unsafe.SizeOf<ControllerSupportResultInfo>())));
return stream.ToArray();
}
private byte[] BuildResponse()
private static byte[] BuildResponse()
{
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write((ulong)ResultCode.Success);
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
writer.Write((ulong)ResultCode.Success);
return stream.ToArray();
}
}
}

View file

@ -11,4 +11,4 @@ namespace Ryujinx.HLE.HOS.Applets
public IEnumerable<PlayerIndex> SupportedPlayers;
public bool IsDocked;
}
}
}

View file

@ -2,7 +2,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Applets
{
#pragma warning disable CS0649
#pragma warning disable CS0649 // Field is never assigned to
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ControllerSupportArgHeader
{
@ -15,4 +15,4 @@ namespace Ryujinx.HLE.HOS.Applets
public byte EnableIdentificationColor;
}
#pragma warning restore CS0649
}
}

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Applets
{
#pragma warning disable CS0649
#pragma warning disable CS0649 // Field is never assigned to
struct ControllerSupportArgPrivate
{
public uint PrivateSize;
@ -13,4 +13,4 @@ namespace Ryujinx.HLE.HOS.Applets
public uint NpadJoyHoldType;
}
#pragma warning restore CS0649
}
}

View file

@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Applets
{
#pragma warning disable CS0649
#pragma warning disable CS0649 // Field is never assigned to
// (8.0.0+ version)
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ControllerSupportArgV7
@ -23,4 +23,4 @@ namespace Ryujinx.HLE.HOS.Applets
}
}
#pragma warning restore CS0649
}
}

View file

@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Applets
{
#pragma warning disable CS0649
#pragma warning disable CS0649 // Field is never assigned to
// (1.0.0+ version)
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ControllerSupportArgVPre7
@ -23,4 +23,4 @@ namespace Ryujinx.HLE.HOS.Applets
}
}
#pragma warning restore CS0649
}
}

View file

@ -4,6 +4,6 @@ namespace Ryujinx.HLE.HOS.Applets
{
ShowControllerSupport = 0,
ShowControllerStrapGuide = 1,
ShowControllerFirmwareUpdate = 2
ShowControllerFirmwareUpdate = 2,
}
}
}

View file

@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Applets
{
#pragma warning disable CS0649
#pragma warning disable CS0649 // Field is never assigned to
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ControllerSupportResultInfo
{
@ -13,4 +13,4 @@ namespace Ryujinx.HLE.HOS.Applets
public uint Result;
}
#pragma warning restore CS0649
}
}

View file

@ -6,9 +6,9 @@ namespace Ryujinx.HLE.HOS.Applets.Error
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ApplicationErrorArg
{
public uint ErrorNumber;
public ulong LanguageCode;
public uint ErrorNumber;
public ulong LanguageCode;
public ByteArray2048 MessageText;
public ByteArray2048 DetailsText;
}
}
}

View file

@ -22,11 +22,11 @@ namespace Ryujinx.HLE.HOS.Applets.Error
{
private const long ErrorMessageBinaryTitleId = 0x0100000000000801;
private Horizon _horizon;
private AppletSession _normalSession;
private CommonArguments _commonArguments;
private readonly Horizon _horizon;
private AppletSession _normalSession;
private CommonArguments _commonArguments;
private ErrorCommonHeader _errorCommonHeader;
private byte[] _errorStorage;
private byte[] _errorStorage;
public event EventHandler AppletStateChanged;
@ -40,14 +40,14 @@ namespace Ryujinx.HLE.HOS.Applets.Error
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
{
_normalSession = normalSession;
_normalSession = normalSession;
_commonArguments = IApplet.ReadStruct<CommonArguments>(_normalSession.Pop());
Logger.Info?.PrintMsg(LogClass.ServiceAm, $"ErrorApplet version: 0x{_commonArguments.AppletVersion:x8}");
_errorStorage = _normalSession.Pop();
_errorStorage = _normalSession.Pop();
_errorCommonHeader = IApplet.ReadStruct<ErrorCommonHeader>(_errorStorage);
_errorStorage = _errorStorage.Skip(Marshal.SizeOf<ErrorCommonHeader>()).ToArray();
_errorStorage = _errorStorage.Skip(Marshal.SizeOf<ErrorCommonHeader>()).ToArray();
switch (_errorCommonHeader.Type)
{
@ -63,7 +63,8 @@ namespace Ryujinx.HLE.HOS.Applets.Error
break;
}
default: throw new NotImplementedException($"ErrorApplet type {_errorCommonHeader.Type} is not implemented.");
default:
throw new NotImplementedException($"ErrorApplet type {_errorCommonHeader.Type} is not implemented.");
}
AppletStateChanged?.Invoke(this, null);
@ -71,15 +72,16 @@ namespace Ryujinx.HLE.HOS.Applets.Error
return ResultCode.Success;
}
private (uint module, uint description) HexToResultCode(uint resultCode)
private static (uint module, uint description) HexToResultCode(uint resultCode)
{
return ((resultCode & 0x1FF) + 2000, (resultCode >> 9) & 0x3FFF);
}
private string SystemLanguageToLanguageKey(SystemLanguage systemLanguage)
private static string SystemLanguageToLanguageKey(SystemLanguage systemLanguage)
{
return systemLanguage switch
{
#pragma warning disable IDE0055 // Disable formatting
SystemLanguage.Japanese => "ja",
SystemLanguage.AmericanEnglish => "en-US",
SystemLanguage.French => "fr",
@ -98,7 +100,8 @@ namespace Ryujinx.HLE.HOS.Applets.Error
SystemLanguage.SimplifiedChinese => "zh-Hans",
SystemLanguage.TraditionalChinese => "zh-Hant",
SystemLanguage.BrazilianPortuguese => "pt-BR",
_ => "en-US"
_ => "en-US",
#pragma warning restore IDE0055
};
}
@ -111,26 +114,24 @@ namespace Ryujinx.HLE.HOS.Applets.Error
{
string binaryTitleContentPath = _horizon.ContentManager.GetInstalledContentPath(ErrorMessageBinaryTitleId, StorageId.BuiltInSystem, NcaContentType.Data);
using (LibHac.Fs.IStorage ncaFileStream = new LocalStorage(_horizon.Device.FileSystem.SwitchPathToSystemPath(binaryTitleContentPath), FileAccess.Read, FileMode.Open))
using LibHac.Fs.IStorage ncaFileStream = new LocalStorage(FileSystem.VirtualFileSystem.SwitchPathToSystemPath(binaryTitleContentPath), FileAccess.Read, FileMode.Open);
Nca nca = new(_horizon.Device.FileSystem.KeySet, ncaFileStream);
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _horizon.FsIntegrityCheckLevel);
string languageCode = SystemLanguageToLanguageKey(_horizon.State.DesiredSystemLanguage);
string filePath = $"/{module}/{description:0000}/{languageCode}_{key}";
if (romfs.FileExists(filePath))
{
Nca nca = new Nca(_horizon.Device.FileSystem.KeySet, ncaFileStream);
IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _horizon.FsIntegrityCheckLevel);
string languageCode = SystemLanguageToLanguageKey(_horizon.State.DesiredSystemLanguage);
string filePath = $"/{module}/{description:0000}/{languageCode}_{key}";
using var binaryFile = new UniqueRef<IFile>();
if (romfs.FileExists(filePath))
{
using var binaryFile = new UniqueRef<IFile>();
romfs.OpenFile(ref binaryFile.Ref, filePath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
StreamReader reader = new(binaryFile.Get.AsStream(), Encoding.Unicode);
romfs.OpenFile(ref binaryFile.Ref, filePath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
StreamReader reader = new StreamReader(binaryFile.Get.AsStream(), Encoding.Unicode);
return CleanText(reader.ReadToEnd());
}
else
{
return "";
}
return CleanText(reader.ReadToEnd());
}
else
{
return "";
}
}
@ -145,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
{
ErrorCommonArg errorCommonArg = IApplet.ReadStruct<ErrorCommonArg>(_errorStorage);
uint module = errorCommonArg.Module;
uint module = errorCommonArg.Module;
uint description = errorCommonArg.Description;
if (_errorCommonHeader.MessageFlag == 0)
@ -188,7 +189,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
string messageText = Encoding.ASCII.GetString(messageTextBuffer.TakeWhile(b => !b.Equals(0)).ToArray());
string detailsText = Encoding.ASCII.GetString(detailsTextBuffer.TakeWhile(b => !b.Equals(0)).ToArray());
List<string> buttons = new List<string>();
List<string> buttons = new();
// TODO: Handle the LanguageCode to return the translated "OK" and "Details".
@ -213,4 +214,4 @@ namespace Ryujinx.HLE.HOS.Applets.Error
return ResultCode.Success;
}
}
}
}

View file

@ -9,4 +9,4 @@ namespace Ryujinx.HLE.HOS.Applets.Error
public uint Description;
public uint ResultCode;
}
}
}

View file

@ -6,12 +6,12 @@ namespace Ryujinx.HLE.HOS.Applets.Error
struct ErrorCommonHeader
{
public ErrorType Type;
public byte JumpFlag;
public byte ReservedFlag1;
public byte ReservedFlag2;
public byte ReservedFlag3;
public byte ContextFlag;
public byte MessageFlag;
public byte ContextFlag2;
public byte JumpFlag;
public byte ReservedFlag1;
public byte ReservedFlag2;
public byte ReservedFlag3;
public byte ContextFlag;
public byte MessageFlag;
public byte ContextFlag2;
}
}
}

View file

@ -8,6 +8,6 @@
ErrorEulaArg,
ErrorPctlArg,
ErrorRecordArg,
SystemUpdateEulaArg = 8
SystemUpdateEulaArg = 8,
}
}
}

View file

@ -8,10 +8,12 @@ namespace Ryujinx.HLE.HOS.Applets
{
internal class PlayerSelectApplet : IApplet
{
private Horizon _system;
private readonly Horizon _system;
private AppletSession _normalSession;
#pragma warning disable IDE0052 // Remove unread private member
private AppletSession _interactiveSession;
#pragma warning restore IDE0052
public event EventHandler AppletStateChanged;
@ -22,7 +24,7 @@ namespace Ryujinx.HLE.HOS.Applets
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
{
_normalSession = normalSession;
_normalSession = normalSession;
_interactiveSession = interactiveSession;
// TODO(jduncanator): Parse PlayerSelectConfig from input data
@ -44,15 +46,14 @@ namespace Ryujinx.HLE.HOS.Applets
{
UserProfile currentUser = _system.AccountManager.LastOpenedUser;
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write((ulong)PlayerSelectResult.Success);
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
using BinaryWriter writer = new(stream);
currentUser.UserId.Write(writer);
writer.Write((ulong)PlayerSelectResult.Success);
return stream.ToArray();
}
currentUser.UserId.Write(writer);
return stream.ToArray();
}
}
}

View file

@ -3,6 +3,6 @@
enum PlayerSelectResult : ulong
{
Success = 0,
Failure = 2
Failure = 2,
}
}

View file

@ -14,4 +14,4 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
[GeneratedRegex("\\p{IsHangulJamo}|\\p{IsCJKRadicalsSupplement}|\\p{IsCJKSymbolsandPunctuation}|\\p{IsEnclosedCJKLettersandMonths}|\\p{IsCJKCompatibility}|\\p{IsCJKUnifiedIdeographsExtensionA}|\\p{IsCJKUnifiedIdeographs}|\\p{IsHangulSyllables}|\\p{IsCJKCompatibilityForms}")]
private static partial Regex CJKRegex();
}
}
}

View file

@ -13,6 +13,6 @@
/// <summary>
/// Position the cursor at the end of the text
/// </summary>
End
End,
}
}

View file

@ -43,6 +43,6 @@
/// <summary>
/// [8.0.0+] Request the keyboard applet to use the MovedCursorV2 response when notifying changes in cursor position.
/// </summary>
UseMovedCursorV2 = 0xE
UseMovedCursorV2 = 0xE,
}
}

View file

@ -88,6 +88,6 @@
/// <summary>
/// Same as MovedCursorUtf8, but with additional fields.
/// </summary>
MovedCursorUtf8V2 = 0x10
MovedCursorUtf8V2 = 0x10,
}
}

View file

@ -28,6 +28,6 @@
/// <summary>
/// software keyboard is transitioning to a hidden state because the user pressed either OK or Cancel.
/// </summary>
Disappearing = 0x4
Disappearing = 0x4,
}
}

View file

@ -60,55 +60,51 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
{
uint resSize = 2 * sizeof(uint) + 0x1;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.FinishedInitialize, writer);
writer.Write((byte)1); // Data (ignored by the program)
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.FinishedInitialize, writer);
writer.Write((byte)1); // Data (ignored by the program)
return stream.ToArray();
}
public static byte[] Default(InlineKeyboardState state)
{
uint resSize = 2 * sizeof(uint);
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.Default, writer);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.Default, writer);
return stream.ToArray();
}
public static byte[] ChangedString(string text, uint cursor, InlineKeyboardState state)
{
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF16;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.ChangedString, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, true);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.ChangedString, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, true);
return stream.ToArray();
}
public static byte[] MovedCursor(string text, uint cursor, InlineKeyboardState state)
{
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.MovedCursor, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.MovedCursor, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
return stream.ToArray();
}
public static byte[] MovedTab(string text, uint cursor, InlineKeyboardState state)
@ -117,182 +113,169 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.MovedTab, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.MovedTab, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
return stream.ToArray();
}
public static byte[] DecidedEnter(string text, InlineKeyboardState state)
{
uint resSize = 3 * sizeof(uint) + MaxStrLenUTF16;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.DecidedEnter, writer);
WriteString(text, writer, MaxStrLenUTF16, Encoding.Unicode);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.DecidedEnter, writer);
WriteString(text, writer, MaxStrLenUTF16, Encoding.Unicode);
return stream.ToArray();
}
public static byte[] DecidedCancel(InlineKeyboardState state)
{
uint resSize = 2 * sizeof(uint);
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.DecidedCancel, writer);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.DecidedCancel, writer);
return stream.ToArray();
}
public static byte[] ChangedStringUtf8(string text, uint cursor, InlineKeyboardState state)
{
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF8;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.ChangedStringUtf8, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, true);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.ChangedStringUtf8, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, true);
return stream.ToArray();
}
public static byte[] MovedCursorUtf8(string text, uint cursor, InlineKeyboardState state)
{
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF8;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.MovedCursorUtf8, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, false);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.MovedCursorUtf8, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, false);
return stream.ToArray();
}
public static byte[] DecidedEnterUtf8(string text, InlineKeyboardState state)
{
uint resSize = 3 * sizeof(uint) + MaxStrLenUTF8;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.DecidedEnterUtf8, writer);
WriteString(text, writer, MaxStrLenUTF8, Encoding.UTF8);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.DecidedEnterUtf8, writer);
WriteString(text, writer, MaxStrLenUTF8, Encoding.UTF8);
return stream.ToArray();
}
public static byte[] UnsetCustomizeDic(InlineKeyboardState state)
{
uint resSize = 2 * sizeof(uint);
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.UnsetCustomizeDic, writer);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.UnsetCustomizeDic, writer);
return stream.ToArray();
}
public static byte[] ReleasedUserWordInfo(InlineKeyboardState state)
{
uint resSize = 2 * sizeof(uint);
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.ReleasedUserWordInfo, writer);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.ReleasedUserWordInfo, writer);
return stream.ToArray();
}
public static byte[] UnsetCustomizedDictionaries(InlineKeyboardState state)
{
uint resSize = 2 * sizeof(uint);
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.UnsetCustomizedDictionaries, writer);
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.UnsetCustomizedDictionaries, writer);
return stream.ToArray();
}
public static byte[] ChangedStringV2(string text, uint cursor, InlineKeyboardState state)
{
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF16 + 0x1;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.ChangedStringV2, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, true);
writer.Write((byte)0); // Flag == 0
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.ChangedStringV2, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, true);
writer.Write((byte)0); // Flag == 0
return stream.ToArray();
}
public static byte[] MovedCursorV2(string text, uint cursor, InlineKeyboardState state)
{
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF16 + 0x1;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.MovedCursorV2, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
writer.Write((byte)0); // Flag == 0
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.MovedCursorV2, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF16, Encoding.Unicode, false);
writer.Write((byte)0); // Flag == 0
return stream.ToArray();
}
public static byte[] ChangedStringUtf8V2(string text, uint cursor, InlineKeyboardState state)
{
uint resSize = 6 * sizeof(uint) + MaxStrLenUTF8 + 0x1;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.ChangedStringUtf8V2, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, true);
writer.Write((byte)0); // Flag == 0
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.ChangedStringUtf8V2, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, true);
writer.Write((byte)0); // Flag == 0
return stream.ToArray();
}
public static byte[] MovedCursorUtf8V2(string text, uint cursor, InlineKeyboardState state)
{
uint resSize = 4 * sizeof(uint) + MaxStrLenUTF8 + 0x1;
using (MemoryStream stream = new MemoryStream(new byte[resSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
{
BeginResponse(state, InlineKeyboardResponse.MovedCursorUtf8V2, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, false);
writer.Write((byte)0); // Flag == 0
using MemoryStream stream = new(new byte[resSize]);
using BinaryWriter writer = new(stream);
return stream.ToArray();
}
BeginResponse(state, InlineKeyboardResponse.MovedCursorUtf8V2, writer);
WriteStringWithCursor(text, cursor, writer, MaxStrLenUTF8, Encoding.UTF8, false);
writer.Write((byte)0); // Flag == 0
return stream.ToArray();
}
}
}

View file

@ -13,6 +13,6 @@
/// <summary>
/// Displays the text entry area as a multi-line field.
/// </summary>
MultiLine
MultiLine,
}
}

View file

@ -8,10 +8,10 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
[Flags]
enum InvalidButtonFlags : uint
{
None = 0,
None = 0,
AnalogStickL = 1 << 1,
AnalogStickR = 1 << 2,
ZL = 1 << 3,
ZR = 1 << 4,
ZL = 1 << 3,
ZR = 1 << 4,
}
}

View file

@ -51,6 +51,6 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
/// <summary>
/// Prohibits characters outside of those allowed in Mii Nicknames.
/// </summary>
Username = 1 << 8
Username = 1 << 8,
}
}

View file

@ -8,19 +8,19 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
[Flags]
enum KeyboardCalcFlags : ulong
{
Initialize = 0x1,
SetVolume = 0x2,
Appear = 0x4,
SetInputText = 0x8,
SetCursorPos = 0x10,
SetUtf8Mode = 0x20,
Initialize = 0x1,
SetVolume = 0x2,
Appear = 0x4,
SetInputText = 0x8,
SetCursorPos = 0x10,
SetUtf8Mode = 0x20,
SetKeyboardBackground = 0x100,
SetKeyboardOptions1 = 0x200,
SetKeyboardOptions2 = 0x800,
EnableSeGroup = 0x2000,
DisableSeGroup = 0x4000,
SetBackspaceEnabled = 0x8000,
AppearTrigger = 0x10000,
MustShow = Appear | SetInputText | AppearTrigger
SetKeyboardOptions1 = 0x200,
SetKeyboardOptions2 = 0x800,
EnableSeGroup = 0x2000,
DisableSeGroup = 0x4000,
SetBackspaceEnabled = 0x8000,
AppearTrigger = 0x10000,
MustShow = Appear | SetInputText | AppearTrigger,
}
}

View file

@ -5,8 +5,8 @@
/// </summary>
enum KeyboardMiniaturizationMode : byte
{
None = 0,
Auto = 1,
Forced = 2
None = 0,
Auto = 1,
Forced = 2,
}
}

View file

@ -24,16 +24,16 @@
/// Synonymous with default.
/// </summary>
FullLatin = 3,
/// <summary>
/// All UTF-16 characters except CJK characters allowed.
/// </summary>
Alphabet = 4,
SimplifiedChinese = 5,
SimplifiedChinese = 5,
TraditionalChinese = 6,
Korean = 7,
LanguageSet2 = 8,
LanguageSet2Latin = 9,
Korean = 7,
LanguageSet2 = 8,
LanguageSet2Latin = 9,
}
}

View file

@ -9,4 +9,4 @@
Accept = 1,
Cancel = 2,
}
}
}

View file

@ -13,6 +13,6 @@
/// <summary>
/// Hide input characters.
/// </summary>
Enabled
Enabled,
}
}

View file

@ -77,41 +77,42 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
[MarshalAs(UnmanagedType.I1)]
public bool UseSaveData;
public uint Reserved3;
public uint Reserved3;
public ushort Reserved4;
public byte Reserved5;
public ulong Reserved6;
public ulong Reserved7;
public byte Reserved5;
public ulong Reserved6;
public ulong Reserved7;
public SoftwareKeyboardAppearEx ToExtended()
{
SoftwareKeyboardAppearEx appear = new SoftwareKeyboardAppearEx();
appear.KeyboardMode = KeyboardMode;
appear.OkText = OkText;
appear.LeftOptionalSymbolKey = LeftOptionalSymbolKey;
appear.RightOptionalSymbolKey = RightOptionalSymbolKey;
appear.PredictionEnabled = PredictionEnabled;
appear.CancelButtonDisabled = CancelButtonDisabled;
appear.InvalidChars = InvalidChars;
appear.TextMaxLength = TextMaxLength;
appear.TextMinLength = TextMinLength;
appear.UseNewLine = UseNewLine;
appear.MiniaturizationMode = MiniaturizationMode;
appear.Reserved1 = Reserved1;
appear.Reserved2 = Reserved2;
appear.InvalidButtons = InvalidButtons;
appear.UseSaveData = UseSaveData;
appear.Reserved3 = Reserved3;
appear.Reserved4 = Reserved4;
appear.Reserved5 = Reserved5;
appear.Uid0 = Reserved6;
appear.Uid1 = Reserved7;
appear.SamplingNumber = 0;
appear.Reserved6 = 0;
appear.Reserved7 = 0;
appear.Reserved8 = 0;
appear.Reserved9 = 0;
SoftwareKeyboardAppearEx appear = new()
{
KeyboardMode = KeyboardMode,
OkText = OkText,
LeftOptionalSymbolKey = LeftOptionalSymbolKey,
RightOptionalSymbolKey = RightOptionalSymbolKey,
PredictionEnabled = PredictionEnabled,
CancelButtonDisabled = CancelButtonDisabled,
InvalidChars = InvalidChars,
TextMaxLength = TextMaxLength,
TextMinLength = TextMinLength,
UseNewLine = UseNewLine,
MiniaturizationMode = MiniaturizationMode,
Reserved1 = Reserved1,
Reserved2 = Reserved2,
InvalidButtons = InvalidButtons,
UseSaveData = UseSaveData,
Reserved3 = Reserved3,
Reserved4 = Reserved4,
Reserved5 = Reserved5,
Uid0 = Reserved6,
Uid1 = Reserved7,
SamplingNumber = 0,
Reserved6 = 0,
Reserved7 = 0,
Reserved8 = 0,
Reserved9 = 0,
};
return appear;
}

View file

@ -77,9 +77,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
[MarshalAs(UnmanagedType.I1)]
public bool UseSaveData;
public uint Reserved3;
public uint Reserved3;
public ushort Reserved4;
public byte Reserved5;
public byte Reserved5;
/// <summary>
/// The id of the user associated with the appear request.

View file

@ -21,16 +21,16 @@ namespace Ryujinx.HLE.HOS.Applets
{
private const string DefaultInputText = "Ryujinx";
private const int StandardBufferSize = 0x7D8;
private const int StandardBufferSize = 0x7D8;
private const int InteractiveBufferSize = 0x7D4;
private const int MaxUserWords = 0x1388;
private const int MaxUiTextSize = 100;
private const int MaxUserWords = 0x1388;
private const int MaxUiTextSize = 100;
private const Key CycleInputModesKey = Key.F6;
private readonly Switch _device;
private SoftwareKeyboardState _foregroundState = SoftwareKeyboardState.Uninitialized;
private SoftwareKeyboardState _foregroundState = SoftwareKeyboardState.Uninitialized;
private volatile InlineKeyboardState _backgroundState = InlineKeyboardState.Uninitialized;
private bool _isBackground = false;
@ -42,23 +42,25 @@ namespace Ryujinx.HLE.HOS.Applets
private SoftwareKeyboardConfig _keyboardForegroundConfig;
// Configuration for background (inline) mode.
private SoftwareKeyboardInitialize _keyboardBackgroundInitialize;
#pragma warning disable IDE0052 // Remove unread private member
private SoftwareKeyboardInitialize _keyboardBackgroundInitialize;
private SoftwareKeyboardCustomizeDic _keyboardBackgroundDic;
private SoftwareKeyboardDictSet _keyboardBackgroundDictSet;
private SoftwareKeyboardUserWord[] _keyboardBackgroundUserWords;
private SoftwareKeyboardDictSet _keyboardBackgroundDictSet;
#pragma warning restore IDE0052
private SoftwareKeyboardUserWord[] _keyboardBackgroundUserWords;
private byte[] _transferMemory;
private string _textValue = "";
private int _cursorBegin = 0;
private Encoding _encoding = Encoding.Unicode;
private KeyboardResult _lastResult = KeyboardResult.NotSet;
private string _textValue = "";
private int _cursorBegin = 0;
private Encoding _encoding = Encoding.Unicode;
private KeyboardResult _lastResult = KeyboardResult.NotSet;
private IDynamicTextInputHandler _dynamicTextInputHandler = null;
private SoftwareKeyboardRenderer _keyboardRenderer = null;
private NpadReader _npads = null;
private bool _canAcceptController = false;
private KeyboardInputMode _inputMode = KeyboardInputMode.ControllerAndKeyboard;
private SoftwareKeyboardRenderer _keyboardRenderer = null;
private NpadReader _npads = null;
private bool _canAcceptController = false;
private KeyboardInputMode _inputMode = KeyboardInputMode.ControllerAndKeyboard;
private readonly object _lock = new();
@ -73,12 +75,12 @@ namespace Ryujinx.HLE.HOS.Applets
{
lock (_lock)
{
_normalSession = normalSession;
_normalSession = normalSession;
_interactiveSession = interactiveSession;
_interactiveSession.DataAvailable += OnInteractiveData;
var launchParams = _normalSession.Pop();
var launchParams = _normalSession.Pop();
var keyboardConfig = _normalSession.Pop();
_isBackground = keyboardConfig.Length == Unsafe.SizeOf<SoftwareKeyboardInitialize>();
@ -88,7 +90,7 @@ namespace Ryujinx.HLE.HOS.Applets
// Initialize the keyboard applet in background mode.
_keyboardBackgroundInitialize = MemoryMarshal.Read<SoftwareKeyboardInitialize>(keyboardConfig);
_backgroundState = InlineKeyboardState.Uninitialized;
_backgroundState = InlineKeyboardState.Uninitialized;
if (_device.UiHandler == null)
{
@ -99,11 +101,11 @@ namespace Ryujinx.HLE.HOS.Applets
// Create a text handler that converts keyboard strokes to strings.
_dynamicTextInputHandler = _device.UiHandler.CreateDynamicTextInputHandler();
_dynamicTextInputHandler.TextChangedEvent += HandleTextChangedEvent;
_dynamicTextInputHandler.KeyPressedEvent += HandleKeyPressedEvent;
_dynamicTextInputHandler.KeyPressedEvent += HandleKeyPressedEvent;
_npads = new NpadReader(_device);
_npads.NpadButtonDownEvent += HandleNpadButtonDownEvent;
_npads.NpadButtonUpEvent += HandleNpadButtonUpEvent;
_npads.NpadButtonUpEvent += HandleNpadButtonUpEvent;
_keyboardRenderer = new SoftwareKeyboardRenderer(_device.UiHandler.HostUiTheme);
}
@ -217,7 +219,7 @@ namespace Ryujinx.HLE.HOS.Applets
_keyboardForegroundConfig.SubmitText : "OK"),
StringLengthMin = _keyboardForegroundConfig.StringLengthMin,
StringLengthMax = _keyboardForegroundConfig.StringLengthMax,
InitialText = initialText
InitialText = initialText,
};
_lastResult = _device.UiHandler.DisplayInputDialog(args, out _textValue) ? KeyboardResult.Accept : KeyboardResult.Cancel;
@ -237,7 +239,7 @@ namespace Ryujinx.HLE.HOS.Applets
// we truncate it.
if (_textValue.Length > _keyboardForegroundConfig.StringLengthMax)
{
_textValue = _textValue.Substring(0, _keyboardForegroundConfig.StringLengthMax);
_textValue = _textValue[.._keyboardForegroundConfig.StringLengthMax];
}
// Does the application want to validate the text itself?
@ -319,178 +321,177 @@ namespace Ryujinx.HLE.HOS.Applets
// request from the game, this is because the inline keyboard is expected to
// keep running in the background sending data by itself.
using (MemoryStream stream = new MemoryStream(data))
using (BinaryReader reader = new BinaryReader(stream))
using MemoryStream stream = new(data);
using BinaryReader reader = new(stream);
var request = (InlineKeyboardRequest)reader.ReadUInt32();
long remaining;
Logger.Debug?.Print(LogClass.ServiceAm, $"Keyboard received command {request} in state {_backgroundState}");
switch (request)
{
var request = (InlineKeyboardRequest)reader.ReadUInt32();
long remaining;
Logger.Debug?.Print(LogClass.ServiceAm, $"Keyboard received command {request} in state {_backgroundState}");
switch (request)
{
case InlineKeyboardRequest.UseChangedStringV2:
Logger.Stub?.Print(LogClass.ServiceAm, "Inline keyboard request UseChangedStringV2");
break;
case InlineKeyboardRequest.UseMovedCursorV2:
Logger.Stub?.Print(LogClass.ServiceAm, "Inline keyboard request UseMovedCursorV2");
break;
case InlineKeyboardRequest.SetUserWordInfo:
// Read the user word info data.
case InlineKeyboardRequest.UseChangedStringV2:
Logger.Stub?.Print(LogClass.ServiceAm, "Inline keyboard request UseChangedStringV2");
break;
case InlineKeyboardRequest.UseMovedCursorV2:
Logger.Stub?.Print(LogClass.ServiceAm, "Inline keyboard request UseMovedCursorV2");
break;
case InlineKeyboardRequest.SetUserWordInfo:
// Read the user word info data.
remaining = stream.Length - stream.Position;
if (remaining < sizeof(int))
{
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard User Word Info of {remaining} bytes");
}
else
{
int wordsCount = reader.ReadInt32();
int wordSize = Unsafe.SizeOf<SoftwareKeyboardUserWord>();
remaining = stream.Length - stream.Position;
if (remaining < sizeof(int))
if (wordsCount > MaxUserWords)
{
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard User Word Info of {remaining} bytes");
Logger.Warning?.Print(LogClass.ServiceAm, $"Received {wordsCount} User Words but the maximum is {MaxUserWords}");
}
else if (wordsCount * wordSize != remaining)
{
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard User Word Info data of {remaining} bytes for {wordsCount} words");
}
else
{
int wordsCount = reader.ReadInt32();
int wordSize = Unsafe.SizeOf<SoftwareKeyboardUserWord>();
remaining = stream.Length - stream.Position;
_keyboardBackgroundUserWords = new SoftwareKeyboardUserWord[wordsCount];
if (wordsCount > MaxUserWords)
for (int word = 0; word < wordsCount; word++)
{
Logger.Warning?.Print(LogClass.ServiceAm, $"Received {wordsCount} User Words but the maximum is {MaxUserWords}");
}
else if (wordsCount * wordSize != remaining)
{
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard User Word Info data of {remaining} bytes for {wordsCount} words");
}
else
{
_keyboardBackgroundUserWords = new SoftwareKeyboardUserWord[wordsCount];
for (int word = 0; word < wordsCount; word++)
{
_keyboardBackgroundUserWords[word] = reader.ReadStruct<SoftwareKeyboardUserWord>();
}
_keyboardBackgroundUserWords[word] = reader.ReadStruct<SoftwareKeyboardUserWord>();
}
}
_interactiveSession.Push(InlineResponses.ReleasedUserWordInfo(_backgroundState));
break;
case InlineKeyboardRequest.SetCustomizeDic:
// Read the custom dic data.
remaining = stream.Length - stream.Position;
if (remaining != Unsafe.SizeOf<SoftwareKeyboardCustomizeDic>())
{
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard Customize Dic of {remaining} bytes");
}
else
{
_keyboardBackgroundDic = reader.ReadStruct<SoftwareKeyboardCustomizeDic>();
}
break;
case InlineKeyboardRequest.SetCustomizedDictionaries:
// Read the custom dictionaries data.
remaining = stream.Length - stream.Position;
if (remaining != Unsafe.SizeOf<SoftwareKeyboardDictSet>())
{
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard DictSet of {remaining} bytes");
}
else
{
_keyboardBackgroundDictSet = reader.ReadStruct<SoftwareKeyboardDictSet>();
}
break;
case InlineKeyboardRequest.Calc:
// The Calc request is used to communicate configuration changes and commands to the keyboard.
// Fields in the Calc struct and operations are masked by the Flags field.
}
_interactiveSession.Push(InlineResponses.ReleasedUserWordInfo(_backgroundState));
break;
case InlineKeyboardRequest.SetCustomizeDic:
// Read the custom dic data.
remaining = stream.Length - stream.Position;
if (remaining != Unsafe.SizeOf<SoftwareKeyboardCustomizeDic>())
{
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard Customize Dic of {remaining} bytes");
}
else
{
_keyboardBackgroundDic = reader.ReadStruct<SoftwareKeyboardCustomizeDic>();
}
break;
case InlineKeyboardRequest.SetCustomizedDictionaries:
// Read the custom dictionaries data.
remaining = stream.Length - stream.Position;
if (remaining != Unsafe.SizeOf<SoftwareKeyboardDictSet>())
{
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard DictSet of {remaining} bytes");
}
else
{
_keyboardBackgroundDictSet = reader.ReadStruct<SoftwareKeyboardDictSet>();
}
break;
case InlineKeyboardRequest.Calc:
// The Calc request is used to communicate configuration changes and commands to the keyboard.
// Fields in the Calc struct and operations are masked by the Flags field.
// Read the Calc data.
SoftwareKeyboardCalcEx newCalc;
remaining = stream.Length - stream.Position;
if (remaining == Marshal.SizeOf<SoftwareKeyboardCalc>())
{
var keyboardCalcData = reader.ReadBytes((int)remaining);
var keyboardCalc = ReadStruct<SoftwareKeyboardCalc>(keyboardCalcData);
// Read the Calc data.
SoftwareKeyboardCalcEx newCalc;
remaining = stream.Length - stream.Position;
if (remaining == Marshal.SizeOf<SoftwareKeyboardCalc>())
{
var keyboardCalcData = reader.ReadBytes((int)remaining);
var keyboardCalc = ReadStruct<SoftwareKeyboardCalc>(keyboardCalcData);
newCalc = keyboardCalc.ToExtended();
}
else if (remaining == Marshal.SizeOf<SoftwareKeyboardCalcEx>() || remaining == SoftwareKeyboardCalcEx.AlternativeSize)
{
var keyboardCalcData = reader.ReadBytes((int)remaining);
newCalc = keyboardCalc.ToExtended();
}
else if (remaining == Marshal.SizeOf<SoftwareKeyboardCalcEx>() || remaining == SoftwareKeyboardCalcEx.AlternativeSize)
{
var keyboardCalcData = reader.ReadBytes((int)remaining);
newCalc = ReadStruct<SoftwareKeyboardCalcEx>(keyboardCalcData);
}
else
{
Logger.Error?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard Calc of {remaining} bytes");
newCalc = ReadStruct<SoftwareKeyboardCalcEx>(keyboardCalcData);
}
else
{
Logger.Error?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard Calc of {remaining} bytes");
newCalc = new SoftwareKeyboardCalcEx();
}
newCalc = new SoftwareKeyboardCalcEx();
}
// Process each individual operation specified in the flags.
// Process each individual operation specified in the flags.
bool updateText = false;
bool updateText = false;
if ((newCalc.Flags & KeyboardCalcFlags.Initialize) != 0)
{
_interactiveSession.Push(InlineResponses.FinishedInitialize(_backgroundState));
if ((newCalc.Flags & KeyboardCalcFlags.Initialize) != 0)
{
_interactiveSession.Push(InlineResponses.FinishedInitialize(_backgroundState));
_backgroundState = InlineKeyboardState.Initialized;
}
_backgroundState = InlineKeyboardState.Initialized;
}
if ((newCalc.Flags & KeyboardCalcFlags.SetCursorPos) != 0)
{
_cursorBegin = newCalc.CursorPos;
updateText = true;
if ((newCalc.Flags & KeyboardCalcFlags.SetCursorPos) != 0)
{
_cursorBegin = newCalc.CursorPos;
updateText = true;
Logger.Debug?.Print(LogClass.ServiceAm, $"Cursor position set to {_cursorBegin}");
}
Logger.Debug?.Print(LogClass.ServiceAm, $"Cursor position set to {_cursorBegin}");
}
if ((newCalc.Flags & KeyboardCalcFlags.SetInputText) != 0)
{
_textValue = newCalc.InputText;
updateText = true;
if ((newCalc.Flags & KeyboardCalcFlags.SetInputText) != 0)
{
_textValue = newCalc.InputText;
updateText = true;
Logger.Debug?.Print(LogClass.ServiceAm, $"Input text set to {_textValue}");
}
Logger.Debug?.Print(LogClass.ServiceAm, $"Input text set to {_textValue}");
}
if ((newCalc.Flags & KeyboardCalcFlags.SetUtf8Mode) != 0)
{
_encoding = newCalc.UseUtf8 ? Encoding.UTF8 : Encoding.Default;
if ((newCalc.Flags & KeyboardCalcFlags.SetUtf8Mode) != 0)
{
_encoding = newCalc.UseUtf8 ? Encoding.UTF8 : Encoding.Default;
Logger.Debug?.Print(LogClass.ServiceAm, $"Encoding set to {_encoding}");
}
Logger.Debug?.Print(LogClass.ServiceAm, $"Encoding set to {_encoding}");
}
if (updateText)
{
_dynamicTextInputHandler.SetText(_textValue, _cursorBegin);
_keyboardRenderer.UpdateTextState(_textValue, _cursorBegin, _cursorBegin, null, null);
}
if (updateText)
{
_dynamicTextInputHandler.SetText(_textValue, _cursorBegin);
_keyboardRenderer.UpdateTextState(_textValue, _cursorBegin, _cursorBegin, null, null);
}
if ((newCalc.Flags & KeyboardCalcFlags.MustShow) != 0)
{
ActivateFrontend();
if ((newCalc.Flags & KeyboardCalcFlags.MustShow) != 0)
{
ActivateFrontend();
_backgroundState = InlineKeyboardState.Shown;
_backgroundState = InlineKeyboardState.Shown;
PushChangedString(_textValue, (uint)_cursorBegin, _backgroundState);
}
PushChangedString(_textValue, (uint)_cursorBegin, _backgroundState);
}
// Send the response to the Calc
_interactiveSession.Push(InlineResponses.Default(_backgroundState));
break;
case InlineKeyboardRequest.Finalize:
// Destroy the frontend.
DestroyFrontend();
// The calling application wants to close the keyboard applet and will wait for a state change.
_backgroundState = InlineKeyboardState.Uninitialized;
AppletStateChanged?.Invoke(this, null);
break;
default:
// We shouldn't be able to get here through standard swkbd execution.
Logger.Warning?.Print(LogClass.ServiceAm, $"Invalid Software Keyboard request {request} during state {_backgroundState}");
_interactiveSession.Push(InlineResponses.Default(_backgroundState));
break;
}
// Send the response to the Calc
_interactiveSession.Push(InlineResponses.Default(_backgroundState));
break;
case InlineKeyboardRequest.Finalize:
// Destroy the frontend.
DestroyFrontend();
// The calling application wants to close the keyboard applet and will wait for a state change.
_backgroundState = InlineKeyboardState.Uninitialized;
AppletStateChanged?.Invoke(this, null);
break;
default:
// We shouldn't be able to get here through standard swkbd execution.
Logger.Warning?.Print(LogClass.ServiceAm, $"Invalid Software Keyboard request {request} during state {_backgroundState}");
_interactiveSession.Push(InlineResponses.Default(_backgroundState));
break;
}
}
private void ActivateFrontend()
{
Logger.Debug?.Print(LogClass.ServiceAm, $"Activating software keyboard frontend");
Logger.Debug?.Print(LogClass.ServiceAm, "Activating software keyboard frontend");
_inputMode = KeyboardInputMode.ControllerAndKeyboard;
@ -509,9 +510,9 @@ namespace Ryujinx.HLE.HOS.Applets
private void DeactivateFrontend()
{
Logger.Debug?.Print(LogClass.ServiceAm, $"Deactivating software keyboard frontend");
Logger.Debug?.Print(LogClass.ServiceAm, "Deactivating software keyboard frontend");
_inputMode = KeyboardInputMode.ControllerAndKeyboard;
_inputMode = KeyboardInputMode.ControllerAndKeyboard;
_canAcceptController = false;
_dynamicTextInputHandler.TextProcessingEnabled = false;
@ -520,7 +521,7 @@ namespace Ryujinx.HLE.HOS.Applets
private void DestroyFrontend()
{
Logger.Debug?.Print(LogClass.ServiceAm, $"Destroying software keyboard frontend");
Logger.Debug?.Print(LogClass.ServiceAm, "Destroying software keyboard frontend");
_keyboardRenderer?.Dispose();
_keyboardRenderer = null;
@ -528,7 +529,7 @@ namespace Ryujinx.HLE.HOS.Applets
if (_dynamicTextInputHandler != null)
{
_dynamicTextInputHandler.TextChangedEvent -= HandleTextChangedEvent;
_dynamicTextInputHandler.KeyPressedEvent -= HandleKeyPressedEvent;
_dynamicTextInputHandler.KeyPressedEvent -= HandleKeyPressedEvent;
_dynamicTextInputHandler.Dispose();
_dynamicTextInputHandler = null;
}
@ -536,7 +537,7 @@ namespace Ryujinx.HLE.HOS.Applets
if (_npads != null)
{
_npads.NpadButtonDownEvent -= HandleNpadButtonDownEvent;
_npads.NpadButtonUpEvent -= HandleNpadButtonUpEvent;
_npads.NpadButtonUpEvent -= HandleNpadButtonUpEvent;
_npads = null;
}
}
@ -551,7 +552,7 @@ namespace Ryujinx.HLE.HOS.Applets
{
AdvanceInputMode();
bool typingEnabled = InputModeTypingEnabled();
bool typingEnabled = InputModeTypingEnabled();
bool controllerEnabled = InputModeControllerEnabled();
_dynamicTextInputHandler.TextProcessingEnabled = typingEnabled;
@ -575,14 +576,14 @@ namespace Ryujinx.HLE.HOS.Applets
if (text.Length > MaxUiTextSize)
{
// Limit the text size and change it back.
text = text.Substring(0, MaxUiTextSize);
text = text[..MaxUiTextSize];
cursorBegin = Math.Min(cursorBegin, MaxUiTextSize);
cursorEnd = Math.Min(cursorEnd, MaxUiTextSize);
cursorEnd = Math.Min(cursorEnd, MaxUiTextSize);
_dynamicTextInputHandler.SetText(text, cursorBegin, cursorEnd);
}
_textValue = text;
_textValue = text;
_cursorBegin = cursorBegin;
_keyboardRenderer.UpdateTextState(text, cursorBegin, cursorEnd, overwriteMode, null);
@ -646,7 +647,7 @@ namespace Ryujinx.HLE.HOS.Applets
private void PushUpdatedState(string text, int cursorBegin, KeyboardResult result)
{
_lastResult = result;
_textValue = text;
_textValue = text;
bool cancel = result == KeyboardResult.Cancel;
bool accept = result == KeyboardResult.Accept;
@ -734,33 +735,31 @@ namespace Ryujinx.HLE.HOS.Applets
{
int bufferSize = interactive ? InteractiveBufferSize : StandardBufferSize;
using (MemoryStream stream = new MemoryStream(new byte[bufferSize]))
using (BinaryWriter writer = new BinaryWriter(stream))
using MemoryStream stream = new(new byte[bufferSize]);
using BinaryWriter writer = new(stream);
byte[] output = _encoding.GetBytes(_textValue);
if (!interactive)
{
byte[] output = _encoding.GetBytes(_textValue);
// Result Code.
writer.Write(_lastResult == KeyboardResult.Accept ? 0U : 1U);
}
else
{
// In interactive mode, we write the length of the text as a long, rather than
// a result code. This field is inclusive of the 64-bit size.
writer.Write((long)output.Length + 8);
}
if (!interactive)
{
// Result Code.
writer.Write(_lastResult == KeyboardResult.Accept ? 0U : 1U);
}
else
{
// In interactive mode, we write the length of the text as a long, rather than
// a result code. This field is inclusive of the 64-bit size.
writer.Write((long)output.Length + 8);
}
writer.Write(output);
writer.Write(output);
if (!interactive)
{
_normalSession.Push(stream.ToArray());
}
else
{
_interactiveSession.Push(stream.ToArray());
}
if (!interactive)
{
_normalSession.Push(stream.ToArray());
}
else
{
_interactiveSession.Push(stream.ToArray());
}
}
@ -787,7 +786,7 @@ namespace Ryujinx.HLE.HOS.Applets
return string.Empty;
}
StringBuilder sb = new StringBuilder(capacity: input.Length);
StringBuilder sb = new(capacity: input.Length);
foreach (char c in input)
{
if (!char.IsControl(c))

View file

@ -174,45 +174,46 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
public SoftwareKeyboardCalcEx ToExtended()
{
SoftwareKeyboardCalcEx calc = new SoftwareKeyboardCalcEx();
calc.Unknown = Unknown;
calc.Size = Size;
calc.Unknown1 = Unknown1;
calc.Unknown2 = Unknown2;
calc.Flags = Flags;
calc.Initialize = Initialize;
calc.Volume = Volume;
calc.CursorPos = CursorPos;
calc.Appear = Appear.ToExtended();
calc.InputText = InputText;
calc.UseUtf8 = UseUtf8;
calc.Unknown3 = Unknown3;
calc.BackspaceEnabled = BackspaceEnabled;
calc.Unknown4 = Unknown4;
calc.Unknown5 = Unknown5;
calc.KeytopAsFloating = KeytopAsFloating;
calc.FooterScalable = FooterScalable;
calc.AlphaEnabledInInputMode = AlphaEnabledInInputMode;
calc.InputModeFadeType = InputModeFadeType;
calc.TouchDisabled = TouchDisabled;
calc.HardwareKeyboardDisabled = HardwareKeyboardDisabled;
calc.Unknown6 = Unknown6;
calc.Unknown7 = Unknown7;
calc.KeytopScale0 = KeytopScale0;
calc.KeytopScale1 = KeytopScale1;
calc.KeytopTranslate0 = KeytopTranslate0;
calc.KeytopTranslate1 = KeytopTranslate1;
calc.KeytopBgAlpha = KeytopBgAlpha;
calc.FooterBgAlpha = FooterBgAlpha;
calc.BalloonScale = BalloonScale;
calc.Unknown8 = Unknown8;
calc.Unknown9 = Unknown9;
calc.Unknown10 = Unknown10;
calc.Unknown11 = Unknown11;
calc.SeGroup = SeGroup;
calc.TriggerFlag = TriggerFlag;
calc.Trigger = Trigger;
SoftwareKeyboardCalcEx calc = new()
{
Unknown = Unknown,
Size = Size,
Unknown1 = Unknown1,
Unknown2 = Unknown2,
Flags = Flags,
Initialize = Initialize,
Volume = Volume,
CursorPos = CursorPos,
Appear = Appear.ToExtended(),
InputText = InputText,
UseUtf8 = UseUtf8,
Unknown3 = Unknown3,
BackspaceEnabled = BackspaceEnabled,
Unknown4 = Unknown4,
Unknown5 = Unknown5,
KeytopAsFloating = KeytopAsFloating,
FooterScalable = FooterScalable,
AlphaEnabledInInputMode = AlphaEnabledInInputMode,
InputModeFadeType = InputModeFadeType,
TouchDisabled = TouchDisabled,
HardwareKeyboardDisabled = HardwareKeyboardDisabled,
Unknown6 = Unknown6,
Unknown7 = Unknown7,
KeytopScale0 = KeytopScale0,
KeytopScale1 = KeytopScale1,
KeytopTranslate0 = KeytopTranslate0,
KeytopTranslate1 = KeytopTranslate1,
KeytopBgAlpha = KeytopBgAlpha,
FooterBgAlpha = FooterBgAlpha,
BalloonScale = BalloonScale,
Unknown8 = Unknown8,
Unknown9 = Unknown9,
Unknown10 = Unknown10,
Unknown11 = Unknown11,
SeGroup = SeGroup,
TriggerFlag = TriggerFlag,
Trigger = Trigger,
};
return calc;
}

View file

@ -8,10 +8,10 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct SoftwareKeyboardConfig
{
private const int SubmitTextLength = 8;
private const int HeaderTextLength = 64;
private const int SubmitTextLength = 8;
private const int HeaderTextLength = 64;
private const int SubtitleTextLength = 128;
private const int GuideTextLength = 256;
private const int GuideTextLength = 256;
/// <summary>
/// Type of keyboard.

View file

@ -10,16 +10,16 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
/// </summary>
internal class SoftwareKeyboardRenderer : IDisposable
{
private const int TextBoxBlinkSleepMilliseconds = 100;
private const int TextBoxBlinkSleepMilliseconds = 100;
private const int RendererWaitTimeoutMilliseconds = 100;
private readonly object _stateLock = new();
private readonly object _stateLock = new();
private SoftwareKeyboardUiState _state = new SoftwareKeyboardUiState();
private SoftwareKeyboardRendererBase _renderer;
private readonly SoftwareKeyboardUiState _state = new();
private readonly SoftwareKeyboardRendererBase _renderer;
private TimedAction _textBoxBlinkTimedAction = new TimedAction();
private TimedAction _renderAction = new TimedAction();
private readonly TimedAction _textBoxBlinkTimedAction = new();
private readonly TimedAction _renderAction = new();
public SoftwareKeyboardRenderer(IHostUiTheme uiTheme)
{
@ -47,10 +47,10 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
private static void StartRenderer(TimedAction timedAction, SoftwareKeyboardRendererBase renderer, SoftwareKeyboardUiState state, object stateLock)
{
SoftwareKeyboardUiState internalState = new SoftwareKeyboardUiState();
SoftwareKeyboardUiState internalState = new();
bool canCreateSurface = false;
bool needsUpdate = true;
bool needsUpdate = true;
timedAction.Reset(() =>
{
@ -61,6 +61,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
return;
}
#pragma warning disable IDE0055 // Disable formatting
needsUpdate = UpdateStateField(ref state.InputText, ref internalState.InputText);
needsUpdate |= UpdateStateField(ref state.CursorBegin, ref internalState.CursorBegin);
needsUpdate |= UpdateStateField(ref state.CursorEnd, ref internalState.CursorEnd);
@ -70,6 +71,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
needsUpdate |= UpdateStateField(ref state.TypingEnabled, ref internalState.TypingEnabled);
needsUpdate |= UpdateStateField(ref state.ControllerEnabled, ref internalState.ControllerEnabled);
needsUpdate |= UpdateStateField(ref state.TextBoxBlinkCounter, ref internalState.TextBoxBlinkCounter);
#pragma warning restore IDE0055
canCreateSurface = state.SurfaceInfo != null && internalState.SurfaceInfo == null;
@ -104,16 +106,14 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
return false;
}
#pragma warning disable CS8632
public void UpdateTextState(string? inputText, int? cursorBegin, int? cursorEnd, bool? overwriteMode, bool? typingEnabled)
#pragma warning restore CS8632
public void UpdateTextState(string inputText, int? cursorBegin, int? cursorEnd, bool? overwriteMode, bool? typingEnabled)
{
lock (_stateLock)
{
// Update the parameters that were provided.
_state.InputText = inputText != null ? inputText : _state.InputText;
_state.CursorBegin = cursorBegin.GetValueOrDefault(_state.CursorBegin);
_state.CursorEnd = cursorEnd.GetValueOrDefault(_state.CursorEnd);
_state.InputText = inputText ?? _state.InputText;
_state.CursorBegin = cursorBegin.GetValueOrDefault(_state.CursorBegin);
_state.CursorEnd = cursorEnd.GetValueOrDefault(_state.CursorEnd);
_state.OverwriteMode = overwriteMode.GetValueOrDefault(_state.OverwriteMode);
_state.TypingEnabled = typingEnabled.GetValueOrDefault(_state.TypingEnabled);
@ -130,8 +130,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
lock (_stateLock)
{
// Update the parameters that were provided.
_state.AcceptPressed = acceptPressed.GetValueOrDefault(_state.AcceptPressed);
_state.CancelPressed = cancelPressed.GetValueOrDefault(_state.CancelPressed);
_state.AcceptPressed = acceptPressed.GetValueOrDefault(_state.AcceptPressed);
_state.CancelPressed = cancelPressed.GetValueOrDefault(_state.CancelPressed);
_state.ControllerEnabled = controllerEnabled.GetValueOrDefault(_state.ControllerEnabled);
// Tell the render thread there is something new to render.

View file

@ -21,47 +21,47 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
{
public const int TextBoxBlinkThreshold = 8;
const string MessageText = "Please use the keyboard to input text";
const string AcceptText = "Accept";
const string CancelText = "Cancel";
const string MessageText = "Please use the keyboard to input text";
const string AcceptText = "Accept";
const string CancelText = "Cancel";
const string ControllerToggleText = "Toggle input";
private readonly object _bufferLock = new();
private RenderingSurfaceInfo _surfaceInfo = null;
private Image<Argb32> _surface = null;
private byte[] _bufferData = null;
private Image<Argb32> _surface = null;
private byte[] _bufferData = null;
private Image _ryujinxLogo = null;
private Image _padAcceptIcon = null;
private Image _padCancelIcon = null;
private Image _keyModeIcon = null;
private readonly Image _ryujinxLogo = null;
private readonly Image _padAcceptIcon = null;
private readonly Image _padCancelIcon = null;
private readonly Image _keyModeIcon = null;
private float _textBoxOutlineWidth;
private float _padPressedPenWidth;
private readonly float _textBoxOutlineWidth;
private readonly float _padPressedPenWidth;
private Color _textNormalColor;
private Color _textSelectedColor;
private Color _textOverCursorColor;
private readonly Color _textNormalColor;
private readonly Color _textSelectedColor;
private readonly Color _textOverCursorColor;
private IBrush _panelBrush;
private IBrush _disabledBrush;
private IBrush _cursorBrush;
private IBrush _selectionBoxBrush;
private readonly IBrush _panelBrush;
private readonly IBrush _disabledBrush;
private readonly IBrush _cursorBrush;
private readonly IBrush _selectionBoxBrush;
private Pen _textBoxOutlinePen;
private Pen _cursorPen;
private Pen _selectionBoxPen;
private Pen _padPressedPen;
private readonly Pen _textBoxOutlinePen;
private readonly Pen _cursorPen;
private readonly Pen _selectionBoxPen;
private readonly Pen _padPressedPen;
private int _inputTextFontSize;
private readonly int _inputTextFontSize;
private Font _messageFont;
private Font _inputTextFont;
private Font _labelsTextFont;
private RectangleF _panelRectangle;
private Point _logoPosition;
private float _messagePositionY;
private Point _logoPosition;
private float _messagePositionY;
public SoftwareKeyboardRendererBase(IHostUiTheme uiTheme)
{
@ -72,35 +72,35 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
string padAcceptIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnA.png";
string padCancelIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_BtnB.png";
string keyModeIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_KeyF6.png";
string keyModeIconPath = "Ryujinx.HLE.HOS.Applets.SoftwareKeyboard.Resources.Icon_KeyF6.png";
_padAcceptIcon = LoadResource(Assembly.GetExecutingAssembly(), padAcceptIconPath , 0, 0);
_padCancelIcon = LoadResource(Assembly.GetExecutingAssembly(), padCancelIconPath , 0, 0);
_keyModeIcon = LoadResource(Assembly.GetExecutingAssembly(), keyModeIconPath , 0, 0);
_padAcceptIcon = LoadResource(Assembly.GetExecutingAssembly(), padAcceptIconPath, 0, 0);
_padCancelIcon = LoadResource(Assembly.GetExecutingAssembly(), padCancelIconPath, 0, 0);
_keyModeIcon = LoadResource(Assembly.GetExecutingAssembly(), keyModeIconPath, 0, 0);
Color panelColor = ToColor(uiTheme.DefaultBackgroundColor, 255);
Color panelTransparentColor = ToColor(uiTheme.DefaultBackgroundColor, 150);
Color borderColor = ToColor(uiTheme.DefaultBorderColor);
Color panelColor = ToColor(uiTheme.DefaultBackgroundColor, 255);
Color panelTransparentColor = ToColor(uiTheme.DefaultBackgroundColor, 150);
Color borderColor = ToColor(uiTheme.DefaultBorderColor);
Color selectionBackgroundColor = ToColor(uiTheme.SelectionBackgroundColor);
_textNormalColor = ToColor(uiTheme.DefaultForegroundColor);
_textSelectedColor = ToColor(uiTheme.SelectionForegroundColor);
_textNormalColor = ToColor(uiTheme.DefaultForegroundColor);
_textSelectedColor = ToColor(uiTheme.SelectionForegroundColor);
_textOverCursorColor = ToColor(uiTheme.DefaultForegroundColor, null, true);
float cursorWidth = 2;
_textBoxOutlineWidth = 2;
_padPressedPenWidth = 2;
_padPressedPenWidth = 2;
_panelBrush = new SolidBrush(panelColor);
_disabledBrush = new SolidBrush(panelTransparentColor);
_cursorBrush = new SolidBrush(_textNormalColor);
_panelBrush = new SolidBrush(panelColor);
_disabledBrush = new SolidBrush(panelTransparentColor);
_cursorBrush = new SolidBrush(_textNormalColor);
_selectionBoxBrush = new SolidBrush(selectionBackgroundColor);
_textBoxOutlinePen = new Pen(borderColor, _textBoxOutlineWidth);
_cursorPen = new Pen(_textNormalColor, cursorWidth);
_selectionBoxPen = new Pen(selectionBackgroundColor, cursorWidth);
_padPressedPen = new Pen(borderColor, _padPressedPenWidth);
_cursorPen = new Pen(_textNormalColor, cursorWidth);
_selectionBoxPen = new Pen(selectionBackgroundColor, cursorWidth);
_padPressedPen = new Pen(borderColor, _padPressedPenWidth);
_inputTextFontSize = 20;
@ -111,22 +111,21 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
{
// Try a list of fonts in case any of them is not available in the system.
string[] availableFonts = new string[]
{
string[] availableFonts = {
uiThemeFontFamily,
"Liberation Sans",
"FreeSans",
"DejaVu Sans",
"Lucida Grande"
"Lucida Grande",
};
foreach (string fontFamily in availableFonts)
{
try
{
_messageFont = SystemFonts.CreateFont(fontFamily, 26, FontStyle.Regular);
_inputTextFont = SystemFonts.CreateFont(fontFamily, _inputTextFontSize, FontStyle.Regular);
_labelsTextFont = SystemFonts.CreateFont(fontFamily, 24, FontStyle.Regular);
_messageFont = SystemFonts.CreateFont(fontFamily, 26, FontStyle.Regular);
_inputTextFont = SystemFonts.CreateFont(fontFamily, _inputTextFontSize, FontStyle.Regular);
_labelsTextFont = SystemFonts.CreateFont(fontFamily, 24, FontStyle.Regular);
return;
}
@ -138,7 +137,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
throw new Exception($"None of these fonts were found in the system: {String.Join(", ", availableFonts)}!");
}
private Color ToColor(ThemeColor color, byte? overrideAlpha = null, bool flipRgb = false)
private static Color ToColor(ThemeColor color, byte? overrideAlpha = null, bool flipRgb = false)
{
var a = (byte)(color.A * 255);
var r = (byte)(color.R * 255);
@ -155,14 +154,14 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
return Color.FromRgba(r, g, b, overrideAlpha.GetValueOrDefault(a));
}
private Image LoadResource(Assembly assembly, string resourcePath, int newWidth, int newHeight)
private static Image LoadResource(Assembly assembly, string resourcePath, int newWidth, int newHeight)
{
Stream resourceStream = assembly.GetManifestResourceStream(resourcePath);
return LoadResource(resourceStream, newWidth, newHeight);
}
private Image LoadResource(Stream resourceStream, int newWidth, int newHeight)
private static Image LoadResource(Stream resourceStream, int newWidth, int newHeight)
{
Debug.Assert(resourceStream != null);
@ -176,7 +175,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
return image;
}
private void SetGraphicsOptions(IImageProcessingContext context)
private static void SetGraphicsOptions(IImageProcessingContext context)
{
context.GetGraphicsOptions().Antialias = true;
context.GetShapeGraphicsOptions().GraphicsOptions.Antialias = true;
@ -198,9 +197,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
context.DrawImage(_ryujinxLogo, _logoPosition, 1);
float halfWidth = _panelRectangle.Width / 2;
float buttonsY = _panelRectangle.Y + 185;
float buttonsY = _panelRectangle.Y + 185;
PointF disableButtonPosition = new PointF(halfWidth + 180, buttonsY);
PointF disableButtonPosition = new(halfWidth + 180, buttonsY);
DrawControllerToggle(context, disableButtonPosition);
});
@ -215,11 +214,11 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
_surface.Mutate(context =>
{
var messageRectangle = MeasureString(MessageText, _messageFont);
float messagePositionX = (_panelRectangle.Width - messageRectangle.Width) / 2 - messageRectangle.X;
float messagePositionY = _messagePositionY - messageRectangle.Y;
var messagePosition = new PointF(messagePositionX, messagePositionY);
var messageBoundRectangle = new RectangleF(messagePositionX, messagePositionY, messageRectangle.Width, messageRectangle.Height);
var messageRectangle = MeasureString(MessageText, _messageFont);
float messagePositionX = (_panelRectangle.Width - messageRectangle.Width) / 2 - messageRectangle.X;
float messagePositionY = _messagePositionY - messageRectangle.Y;
var messagePosition = new PointF(messagePositionX, messagePositionY);
var messageBoundRectangle = new RectangleF(messagePositionX, messagePositionY, messageRectangle.Width, messageRectangle.Height);
SetGraphicsOptions(context);
@ -238,11 +237,11 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
DrawTextBox(context, state);
float halfWidth = _panelRectangle.Width / 2;
float buttonsY = _panelRectangle.Y + 185;
float buttonsY = _panelRectangle.Y + 185;
PointF acceptButtonPosition = new PointF(halfWidth - 180, buttonsY);
PointF cancelButtonPosition = new PointF(halfWidth , buttonsY);
PointF disableButtonPosition = new PointF(halfWidth + 180, buttonsY);
PointF acceptButtonPosition = new(halfWidth - 180, buttonsY);
PointF cancelButtonPosition = new(halfWidth, buttonsY);
PointF disableButtonPosition = new(halfWidth + 180, buttonsY);
DrawPadButton(context, acceptButtonPosition, _padAcceptIcon, AcceptText, state.AcceptPressed, state.ControllerEnabled);
DrawPadButton(context, cancelButtonPosition, _padCancelIcon, CancelText, state.CancelPressed, state.ControllerEnabled);
@ -262,7 +261,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
// Use the whole area of the image to draw, even the alignment, otherwise it may shear the final
// image if the pitch is different.
uint totalWidth = _surfaceInfo.Pitch / 4;
uint totalWidth = _surfaceInfo.Pitch / 4;
uint totalHeight = _surfaceInfo.Size / _surfaceInfo.Pitch;
Debug.Assert(_surfaceInfo.Width <= totalWidth);
@ -277,10 +276,10 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
private void ComputeConstants()
{
int totalWidth = (int)_surfaceInfo.Width;
int totalWidth = (int)_surfaceInfo.Width;
int totalHeight = (int)_surfaceInfo.Height;
int panelHeight = 240;
int panelHeight = 240;
int panelPositionY = totalHeight - panelHeight;
_panelRectangle = new RectangleF(0, panelPositionY, totalWidth, panelHeight);
@ -294,7 +293,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
}
private static RectangleF MeasureString(string text, Font font)
{
RendererOptions options = new RendererOptions(font);
RendererOptions options = new(font);
if (text == "")
{
@ -310,7 +309,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
private static RectangleF MeasureString(ReadOnlySpan<char> text, Font font)
{
RendererOptions options = new RendererOptions(font);
RendererOptions options = new(font);
if (text == "")
{
@ -327,14 +326,14 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
{
var inputTextRectangle = MeasureString(state.InputText, _inputTextFont);
float boxWidth = (int)(Math.Max(300, inputTextRectangle.Width + inputTextRectangle.X + 8));
float boxWidth = (int)(Math.Max(300, inputTextRectangle.Width + inputTextRectangle.X + 8));
float boxHeight = 32;
float boxY = _panelRectangle.Y + 110;
float boxX = (int)((_panelRectangle.Width - boxWidth) / 2);
float boxY = _panelRectangle.Y + 110;
float boxX = (int)((_panelRectangle.Width - boxWidth) / 2);
RectangleF boxRectangle = new RectangleF(boxX, boxY, boxWidth, boxHeight);
RectangleF boxRectangle = new(boxX, boxY, boxWidth, boxHeight);
RectangleF boundRectangle = new RectangleF(_panelRectangle.X, boxY - _textBoxOutlineWidth,
RectangleF boundRectangle = new(_panelRectangle.X, boxY - _textBoxOutlineWidth,
_panelRectangle.Width, boxHeight + 2 * _textBoxOutlineWidth);
context.Fill(_panelBrush, boundRectangle);
@ -350,11 +349,11 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
// Draw the cursor on top of the text and redraw the text with a different color if necessary.
Color cursorTextColor;
Color cursorTextColor;
IBrush cursorBrush;
Pen cursorPen;
Pen cursorPen;
float cursorPositionYTop = inputTextY + 1;
float cursorPositionYTop = inputTextY + 1;
float cursorPositionYBottom = cursorPositionYTop + _inputTextFontSize + 1;
float cursorPositionXLeft;
float cursorPositionXRight;
@ -366,34 +365,34 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
Debug.Assert(state.InputText.Length > 0);
cursorTextColor = _textSelectedColor;
cursorBrush = _selectionBoxBrush;
cursorPen = _selectionBoxPen;
cursorBrush = _selectionBoxBrush;
cursorPen = _selectionBoxPen;
ReadOnlySpan<char> textUntilBegin = state.InputText.AsSpan(0, state.CursorBegin);
ReadOnlySpan<char> textUntilEnd = state.InputText.AsSpan(0, state.CursorEnd);
ReadOnlySpan<char> textUntilEnd = state.InputText.AsSpan(0, state.CursorEnd);
var selectionBeginRectangle = MeasureString(textUntilBegin, _inputTextFont);
var selectionEndRectangle = MeasureString(textUntilEnd , _inputTextFont);
var selectionEndRectangle = MeasureString(textUntilEnd, _inputTextFont);
cursorVisible = true;
cursorPositionXLeft = inputTextX + selectionBeginRectangle.Width + selectionBeginRectangle.X;
cursorPositionXRight = inputTextX + selectionEndRectangle.Width + selectionEndRectangle.X;
cursorVisible = true;
cursorPositionXLeft = inputTextX + selectionBeginRectangle.Width + selectionBeginRectangle.X;
cursorPositionXRight = inputTextX + selectionEndRectangle.Width + selectionEndRectangle.X;
}
else
{
cursorTextColor = _textOverCursorColor;
cursorBrush = _cursorBrush;
cursorPen = _cursorPen;
cursorBrush = _cursorBrush;
cursorPen = _cursorPen;
if (state.TextBoxBlinkCounter < TextBoxBlinkThreshold)
{
// Show the blinking cursor.
int cursorBegin = Math.Min(state.InputText.Length, state.CursorBegin);
ReadOnlySpan<char> textUntilCursor = state.InputText.AsSpan(0, cursorBegin);
var cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont);
int cursorBegin = Math.Min(state.InputText.Length, state.CursorBegin);
ReadOnlySpan<char> textUntilCursor = state.InputText.AsSpan(0, cursorBegin);
var cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont);
cursorVisible = true;
cursorVisible = true;
cursorPositionXLeft = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X;
if (state.OverwriteMode)
@ -402,8 +401,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
if (state.CursorBegin < state.InputText.Length)
{
textUntilCursor = state.InputText.AsSpan(0, cursorBegin + 1);
cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont);
textUntilCursor = state.InputText.AsSpan(0, cursorBegin + 1);
cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont);
cursorPositionXRight = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X;
}
else
@ -419,20 +418,19 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
}
else
{
cursorPositionXLeft = inputTextX;
cursorPositionXLeft = inputTextX;
cursorPositionXRight = inputTextX;
}
}
if (state.TypingEnabled && cursorVisible)
{
float cursorWidth = cursorPositionXRight - cursorPositionXLeft;
float cursorWidth = cursorPositionXRight - cursorPositionXLeft;
float cursorHeight = cursorPositionYBottom - cursorPositionYTop;
if (cursorWidth == 0)
{
PointF[] points = new PointF[]
{
PointF[] points = {
new PointF(cursorPositionXLeft, cursorPositionYTop),
new PointF(cursorPositionXLeft, cursorPositionYBottom),
};
@ -443,10 +441,10 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
{
var cursorRectangle = new RectangleF(cursorPositionXLeft, cursorPositionYTop, cursorWidth, cursorHeight);
context.Draw(cursorPen , cursorRectangle);
context.Draw(cursorPen, cursorRectangle);
context.Fill(cursorBrush, cursorRectangle);
Image<Argb32> textOverCursor = new Image<Argb32>((int)cursorRectangle.Width, (int)cursorRectangle.Height);
Image<Argb32> textOverCursor = new((int)cursorRectangle.Width, (int)cursorRectangle.Height);
textOverCursor.Mutate(context =>
{
var textRelativePosition = new PointF(inputTextPosition.X - cursorRectangle.X, inputTextPosition.Y - cursorRectangle.Y);
@ -470,9 +468,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
{
// Use relative positions so we can center the the entire drawing later.
float iconX = 0;
float iconY = 0;
float iconWidth = icon.Width;
float iconX = 0;
float iconY = 0;
float iconWidth = icon.Width;
float iconHeight = icon.Height;
var labelRectangle = MeasureString(label, _labelsTextFont);
@ -480,18 +478,18 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
float labelPositionX = iconWidth + 8 - labelRectangle.X;
float labelPositionY = 3;
float fullWidth = labelPositionX + labelRectangle.Width + labelRectangle.X;
float fullWidth = labelPositionX + labelRectangle.Width + labelRectangle.X;
float fullHeight = iconHeight;
// Convert all relative positions into absolute.
float originX = (int)(point.X - fullWidth / 2);
float originX = (int)(point.X - fullWidth / 2);
float originY = (int)(point.Y - fullHeight / 2);
iconX += originX;
iconY += originY;
var iconPosition = new Point((int)iconX, (int)iconY);
var iconPosition = new Point((int)iconX, (int)iconY);
var labelPosition = new PointF(labelPositionX + originX, labelPositionY + originY);
var selectedRectangle = new RectangleF(originX - 2 * _padPressedPenWidth, originY - 2 * _padPressedPenWidth,
@ -526,7 +524,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
// Use relative positions so we can center the the entire drawing later.
float keyWidth = _keyModeIcon.Width;
float keyWidth = _keyModeIcon.Width;
float keyHeight = _keyModeIcon.Height;
float labelPositionX = keyWidth + 8 - labelRectangle.X;
@ -535,18 +533,18 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
float keyX = 0;
float keyY = (int)((labelPositionY + labelRectangle.Height - keyHeight) / 2);
float fullWidth = labelPositionX + labelRectangle.Width;
float fullWidth = labelPositionX + labelRectangle.Width;
float fullHeight = Math.Max(labelPositionY + labelRectangle.Height, keyHeight);
// Convert all relative positions into absolute.
float originX = (int)(point.X - fullWidth / 2);
float originX = (int)(point.X - fullWidth / 2);
float originY = (int)(point.Y - fullHeight / 2);
keyX += originX;
keyY += originY;
var labelPosition = new PointF(labelPositionX + originX, labelPositionY + originY);
var labelPosition = new PointF(labelPositionX + originX, labelPositionY + originY);
var overlayPosition = new Point((int)keyX, (int)keyY);
context.DrawImage(_keyModeIcon, overlayPosition, 1);

View file

@ -23,6 +23,6 @@
/// <summary>
/// swkbd has completed.
/// </summary>
Complete
Complete,
}
}
}

View file

@ -13,4 +13,4 @@ namespace Ryujinx.HLE.HOS.Applets
public int StringLengthMin;
public int StringLengthMax;
}
}
}

View file

@ -7,15 +7,15 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
/// </summary>
internal class SoftwareKeyboardUiState
{
public string InputText = "";
public int CursorBegin = 0;
public int CursorEnd = 0;
public bool AcceptPressed = false;
public bool CancelPressed = false;
public bool OverwriteMode = false;
public bool TypingEnabled = true;
public bool ControllerEnabled = true;
public int TextBoxBlinkCounter = 0;
public string InputText = "";
public int CursorBegin = 0;
public int CursorEnd = 0;
public bool AcceptPressed = false;
public bool CancelPressed = false;
public bool OverwriteMode = false;
public bool TypingEnabled = true;
public bool ControllerEnabled = true;
public int TextBoxBlinkCounter = 0;
public RenderingSurfaceInfo SurfaceInfo = null;
}

View file

@ -19,8 +19,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
public SleepSubstepData(int sleepMilliseconds)
{
SleepMilliseconds = Math.Min(sleepMilliseconds, MaxThreadSleep);
SleepCount = sleepMilliseconds / SleepMilliseconds;
SleepMilliseconds = Math.Min(sleepMilliseconds, MaxThreadSleep);
SleepCount = sleepMilliseconds / SleepMilliseconds;
SleepRemainderMilliseconds = sleepMilliseconds - SleepCount * SleepMilliseconds;
}
}