JsonInputConfigConverter.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. using Ryujinx.Common.Configuration.Hid.Controller;
  2. using Ryujinx.Common.Configuration.Hid.Keyboard;
  3. using Ryujinx.Common.Utilities;
  4. using System;
  5. using System.Text.Json;
  6. using System.Text.Json.Serialization;
  7. namespace Ryujinx.Common.Configuration.Hid
  8. {
  9. public class JsonInputConfigConverter : JsonConverter<InputConfig>
  10. {
  11. private static readonly InputConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
  12. private static InputBackendType GetInputBackendType(ref Utf8JsonReader reader)
  13. {
  14. // Temporary reader to get the backend type
  15. Utf8JsonReader tempReader = reader;
  16. InputBackendType result = InputBackendType.Invalid;
  17. while (tempReader.Read())
  18. {
  19. // NOTE: We scan all properties ignoring the depth entirely on purpose.
  20. // The reason behind this is that we cannot track in a reliable way the depth of the object because Utf8JsonReader never emit the first TokenType == StartObject if the json start with an object.
  21. // As such, this code will try to parse very field named "backend" to the correct enum.
  22. if (tempReader.TokenType == JsonTokenType.PropertyName)
  23. {
  24. string propertyName = tempReader.GetString();
  25. if (propertyName.Equals("backend"))
  26. {
  27. tempReader.Read();
  28. if (tempReader.TokenType == JsonTokenType.String)
  29. {
  30. string backendTypeRaw = tempReader.GetString();
  31. if (!Enum.TryParse(backendTypeRaw, out result))
  32. {
  33. result = InputBackendType.Invalid;
  34. }
  35. else
  36. {
  37. break;
  38. }
  39. }
  40. }
  41. }
  42. }
  43. return result;
  44. }
  45. public override InputConfig Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
  46. {
  47. InputBackendType backendType = GetInputBackendType(ref reader);
  48. return backendType switch
  49. {
  50. InputBackendType.WindowKeyboard => JsonSerializer.Deserialize(ref reader, SerializerContext.StandardKeyboardInputConfig),
  51. InputBackendType.GamepadSDL2 => JsonSerializer.Deserialize(ref reader, SerializerContext.StandardControllerInputConfig),
  52. _ => throw new InvalidOperationException($"Unknown backend type {backendType}"),
  53. };
  54. }
  55. public override void Write(Utf8JsonWriter writer, InputConfig value, JsonSerializerOptions options)
  56. {
  57. switch (value.Backend)
  58. {
  59. case InputBackendType.WindowKeyboard:
  60. JsonSerializer.Serialize(writer, value as StandardKeyboardInputConfig, SerializerContext.StandardKeyboardInputConfig);
  61. break;
  62. case InputBackendType.GamepadSDL2:
  63. JsonSerializer.Serialize(writer, value as StandardControllerInputConfig, SerializerContext.StandardControllerInputConfig);
  64. break;
  65. default:
  66. throw new ArgumentException($"Unknown backend type {value.Backend}");
  67. }
  68. }
  69. }
  70. }