aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONFIG.md208
-rw-r--r--README.md2
-rw-r--r--Ryujinx.Common/Extensions/BinaryReaderExtensions.cs (renamed from Ryujinx.Common/StructIOExtension.cs)10
-rw-r--r--Ryujinx.Common/Extensions/EnumExtensions.cs12
-rw-r--r--Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs53
-rw-r--r--Ryujinx.Common/Logging/Formatters/ILogFormatter.cs7
-rw-r--r--Ryujinx.Common/Logging/LogClass.cs1
-rw-r--r--Ryujinx.Common/Logging/Logger.cs28
-rw-r--r--Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs76
-rw-r--r--Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs48
-rw-r--r--Ryujinx.Common/Logging/Targets/FileLogTarget.cs36
-rw-r--r--Ryujinx.Common/Logging/Targets/ILogTarget.cs9
-rw-r--r--Ryujinx.Common/Logging/Targets/JsonLogTarget.cs35
-rw-r--r--Ryujinx.Common/Pools/ObjectPool.cs75
-rw-r--r--Ryujinx.Common/Pools/SharedPools.cs17
-rw-r--r--Ryujinx.Common/Ryujinx.Common.csproj4
-rw-r--r--Ryujinx.Common/Utilities/BitUtils.cs (renamed from Ryujinx.Common/BitUtils.cs)0
-rw-r--r--Ryujinx.Common/Utilities/HexUtils.cs (renamed from Ryujinx.Common/HexUtils.cs)0
-rw-r--r--Ryujinx.HLE/Switch.cs1
-rw-r--r--Ryujinx.sln6
-rw-r--r--Ryujinx/Config.cs203
-rw-r--r--Ryujinx/Config.jsonc124
-rw-r--r--Ryujinx/Configuration.cs239
-rw-r--r--Ryujinx/Program.cs25
-rw-r--r--Ryujinx/Ryujinx.conf107
-rw-r--r--Ryujinx/Ryujinx.csproj2
-rw-r--r--Ryujinx/Ui/GLScreen.cs12
-rw-r--r--Ryujinx/Ui/Log.cs140
-rw-r--r--Ryujinx/Ui/NpadController.cs121
-rw-r--r--Ryujinx/Ui/NpadKeyboard.cs113
-rw-r--r--Ryujinx/_schema.json823
31 files changed, 1845 insertions, 692 deletions
diff --git a/CONFIG.md b/CONFIG.md
index eef7b68d..b63f5e83 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -1,123 +1,124 @@
## Config File
-`Ryujinx.conf` should be present in executable folder (It's an *.ini file) following this format:
+`Config.jsonc` should be present in executable folder. The available settings follow:
-- `Logging_Enable_Info` *(bool)*
+- `graphics_shaders_dump_path` *(string)*
- Enable the Informations Logging.
-
-- `Logging_Enable_Trace` *(bool)*
+ Dump shaders in local directory (e.g. `C:\ShaderDumps`)
- Enable the Trace Logging (Enabled in Debug recommended).
-
-- `Logging_Enable_Debug` *(bool)*
+- `logging_enable_debug` *(bool)*
- Enable the Debug Logging (Enabled in Debug recommended).
+ Enable the Debug Logging.
-- `Logging_Enable_Warn` *(bool)*
+- `logging_enable_stub` *(bool)*
- Enable the Warning Logging (Enabled in Debug recommended).
+ Enable the Trace Logging.
-- `Logging_Enable_Error` *(bool)*
+- `logging_enable_info` *(bool)*
- Enable the Error Logging (Enabled in Debug recommended).
+ Enable the Informations Logging.
-- `Logging_Enable_Fatal` *(bool)*
+- `logging_enable_warn` *(bool)*
- Enable the Fatal Logging (Enabled in Debug recommended).
+ Enable the Warning Logging.
-- `Logging_Enable_Ipc` *(bool)*
+- `logging_enable_error` *(bool)*
- Enable the Ipc Message Logging.
+ Enable the Error Logging.
-- `Logging_Enable_LogFile` *(bool)*
+- `enable_file_log` *(bool)*
Enable writing the logging inside a Ryujinx.log file.
-
-- `GamePad_Index` *(int)*
- The index of the Controller Device.
-
-- `GamePad_Deadzone` *(float)*
-
- The deadzone of both analog sticks on the Controller.
-
-- `GamePad_Enable` *(bool)*
-
- Whether or not to enable Controller Support.
+- `system_language` *(string)*
+
+ Change System Language, [System Language list](https://gist.github.com/HorrorTroll/b6e4a88d774c3c9b3bdf54d79a7ca43b)
+
+- `docked_mode` *(bool)*
+
+ Enable or Disable Docked Mode
+
+- `enable_vsync` *(bool)*
+
+ Enable or Disable Game Vsync
+
+- `enable_multicore_scheduling` *(bool)*
+
+ Enable or Disable Multi-core scheduling of threads
+
+- `enable_fs_integrity_checks` *(bool)*
+
+ Enable integrity checks on Switch content files
+
+- `controller_type` *(string)*
+
+ The primary controller's type.
+ Supported Values: `Handheld`, `ProController`, `NpadPair`, `NpadLeft`, `NpadRight`
+
+- `keyboard_controls` *(object)* :
+ - `left_joycon` *(object)* :
+ Left JoyCon Keyboard Bindings
+ - `stick_up` *(string)*
+ - `stick_down` *(string)*
+ - `stick_left` *(string)*
+ - `stick_right` *(string)*
+ - `stick_button` *(string)*
+ - `dpad_up` *(string)*
+ - `dpad_down` *(string)*
+ - `dpad_left` *(string)*
+ - `dpad_right` *(string)*
+ - `button_minus` *(string)*
+ - `button_l` *(string)*
+ - `button_zl` *(string)*
+ - `right_joycon` *(object)* :
+ Right JoyCon Keyboard Bindings
+ - `stick_up` *(string)*
+ - `stick_down` *(string)*
+ - `stick_left` *(string)*
+ - `stick_right` *(string)*
+ - `stick_button` *(string)*
+ - `button_a` *(string)*
+ - `button_b` *(string)*
+ - `button_x` *(string)*
+ - `button_y` *(string)*
+ - `button_plus` *(string)*
+ - `button_r` *(string)*
+ - `button_zr` *(string)*
+
+- `gamepad_controls` *(object)* :
+ - `enabled` *(bool)*
+ Whether or not to enable Controller Support.
+ - `index` *(int)*
+ The index of the Controller Device.
+ - `deadzone` *(number)*
+ The deadzone of both analog sticks on the Controller.
+ - `trigger_threshold` *(number)*
+ The value of how pressed down each trigger has to be in order to register a button press
+ - `left_joycon` *(object)* :
+ Left JoyCon Controller Bindings
+ - `stick` *(string)*
+ - `stick_button` *(string)*
+ - `dpad_up` *(string)*
+ - `dpad_down` *(string)*
+ - `dpad_left` *(string)*
+ - `dpad_right` *(string)*
+ - `button_minus` *(string)*
+ - `button_l` *(string)*
+ - `button_zl` *(string)*
+ - `right_joycon` *(object)* :
+ Right JoyCon Controller Bindings
+ - `stick` *(string)*
+ - `stick_button` *(string)*
+ - `button_a` *(string)*
+ - `button_b` *(string)*
+ - `button_x` *(string)*
+ - `button_y` *(string)*
+ - `button_plus` *(string)*
+ - `button_r` *(string)*
+ - `button_zr` *(string)*
-- `Controls_Left_JoyConKeyboard_XX` *(int)*
- ```
- Controls_Left_JoyConKeyboard_Stick_Up (int)
- Controls_Left_JoyConKeyboard_Stick_Down (int)
- Controls_Left_JoyConKeyboard_Stick_Left (int)
- Controls_Left_JoyConKeyboard_Stick_Right (int)
- Controls_Left_JoyConKeyboard_Stick_Button (int)
- Controls_Left_JoyConKeyboard_DPad_Up (int)
- Controls_Left_JoyConKeyboard_DPad_Down (int)
- Controls_Left_JoyConKeyboard_DPad_Left (int)
- Controls_Left_JoyConKeyboard_DPad_Right (int)
- Controls_Left_JoyConKeyboard_Button_Minus (int)
- Controls_Left_JoyConKeyboard_Button_L (int)
- Controls_Left_JoyConKeyboard_Button_ZL (int)
- ```
-
- Keys of the Left Emulated Joycon, the values depend of the [OpenTK Enum Keys](https://github.com/opentk/opentk/blob/develop/src/OpenTK/Input/Key.cs).
-
- OpenTK use a QWERTY layout, so pay attention if you use another Keyboard Layout.
-
- Ex: `Controls_Left_JoyConKeyboard_Button_Minus = 52` > Tab key (All Layout).
-
-- `Controls_Right_JoyConKeyboard_XX` *(int)*
- ```
- Controls_Right_JoyConKeyboard_Stick_Up (int)
- Controls_Right_JoyConKeyboard_Stick_Down (int)
- Controls_Right_JoyConKeyboard_Stick_Left (int)
- Controls_Right_JoyConKeyboard_Stick_Right (int)
- Controls_Right_JoyConKeyboard_Stick_Button (int)
- Controls_Right_JoyConKeyboard_Button_A (int)
- Controls_Right_JoyConKeyboard_Button_B (int)
- Controls_Right_JoyConKeyboard_Button_X (int)
- Controls_Right_JoyConKeyboard_Button_Y (int)
- Controls_Right_JoyConKeyboard_Button_Plus (int)
- Controls_Right_JoyConKeyboard_Button_R (int)
- Controls_Right_JoyConKeyboard_Button_ZR (int)
- ```
-
- Keys of the right Emulated Joycon, the values depend of the [OpenTK Enum Keys](https://github.com/opentk/opentk/blob/develop/src/OpenTK/Input/Key.cs).
-
- OpenTK use a QWERTY layout, so pay attention if you use another Keyboard Layout.
-
- Ex: `Controls_Right_JoyConKeyboard_Button_A = 83` > A key (QWERTY Layout) / Q key (AZERTY Layout).
-
-- `Controls_Left_JoyConController_XX` *(String)*
- ```
- Controls_Left_JoyConController_Stick (String)
- Controls_Left_JoyConController_Stick_Button (String)
- Controls_Left_JoyConController_DPad_Up (String)
- Controls_Left_JoyConController_DPad_Down (String)
- Controls_Left_JoyConController_DPad_Left (String)
- Controls_Left_JoyConController_DPad_Right (String)
- Controls_Left_JoyConController_Button_Minus (String)
- Controls_Left_JoyConController_Button_L (String)
- Controls_Left_JoyConController_Button_ZL (String)
- ```
-
-- `Controls_Right_JoyConController_XX` *(String)*
- ```
- Controls_Right_JoyConController_Stick (String)
- Controls_Right_JoyConController_Stick_Button (String)
- Controls_Right_JoyConController_Button_A (String)
- Controls_Right_JoyConController_Button_B (String)
- Controls_Right_JoyConController_Button_X (String)
- Controls_Right_JoyConController_Button_Y (String)
- Controls_Right_JoyConController_Button_Plus (String)
- Controls_Right_JoyConController_Button_R (String)
- Controls_Right_JoyConController_Button_ZR (String)
- ```
-
-- Default Mapping
- - Controller
+### Default Mapping
+ #### Controller
- Left Joycon:
- Analog Stick = Left Analog Stick
- DPad Up = DPad Up
@@ -137,7 +138,8 @@
- Plus = Start / Options
- R = Right Shoulder Button
- ZR = Right Trigger
- - Keyboard
+
+ #### Keyboard
- Left Joycon:
- Stick Up = W
- Stick Down = S
@@ -166,7 +168,7 @@
- R = U
- ZR = O
-- Valid Button Mappings
+### Valid Button Mappings
- A = The A / Cross Button
- B = The B / Circle Button
- X = The X / Square Button
diff --git a/README.md b/README.md
index bdf8588a..10279b50 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ or just drag'n'drop the homebrew *.NRO / *.NSO or the game *.NSP / *.XCI on the
- Controller Input is supported, see [CONFIG.md](CONFIG.md)
- - Config File: `Ryujinx.conf` should be present in executable folder.
+ - Config File: `Config.jsonc` should be present in executable folder.
For more information [you can go here](CONFIG.md).
**Help**
diff --git a/Ryujinx.Common/StructIOExtension.cs b/Ryujinx.Common/Extensions/BinaryReaderExtensions.cs
index 8671b192..49af946f 100644
--- a/Ryujinx.Common/StructIOExtension.cs
+++ b/Ryujinx.Common/Extensions/BinaryReaderExtensions.cs
@@ -1,14 +1,13 @@
using System;
-using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
-using System.Text;
namespace Ryujinx.Common
{
- public static class StructIOExtension
+ public static class BinaryReaderExtensions
{
- public unsafe static T ReadStruct<T>(this BinaryReader reader) where T : struct
+ public unsafe static T ReadStruct<T>(this BinaryReader reader)
+ where T : struct
{
int size = Marshal.SizeOf<T>();
@@ -20,7 +19,8 @@ namespace Ryujinx.Common
}
}
- public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value) where T : struct
+ public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
+ where T : struct
{
long size = Marshal.SizeOf<T>();
diff --git a/Ryujinx.Common/Extensions/EnumExtensions.cs b/Ryujinx.Common/Extensions/EnumExtensions.cs
new file mode 100644
index 00000000..560af882
--- /dev/null
+++ b/Ryujinx.Common/Extensions/EnumExtensions.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Ryujinx.Common
+{
+ public static class EnumExtensions
+ {
+ public static T[] GetValues<T>()
+ {
+ return (T[])Enum.GetValues(typeof(T));
+ }
+ }
+}
diff --git a/Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs b/Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs
new file mode 100644
index 00000000..0c4396e7
--- /dev/null
+++ b/Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs
@@ -0,0 +1,53 @@
+using System.Reflection;
+using System.Text;
+
+namespace Ryujinx.Common.Logging
+{
+ internal class DefaultLogFormatter : ILogFormatter
+ {
+ private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
+
+ public string Format(LogEventArgs args)
+ {
+ StringBuilder sb = _stringBuilderPool.Allocate();
+
+ try
+ {
+ sb.Clear();
+
+ sb.AppendFormat(@"{0:hh\:mm\:ss\.fff}", args.Time);
+ sb.Append(" | ");
+ sb.AppendFormat("{0:d4}", args.ThreadId);
+ sb.Append(' ');
+ sb.Append(args.Message);
+
+ if (args.Data != null)
+ {
+ PropertyInfo[] props = args.Data.GetType().GetProperties();
+
+ sb.Append(' ');
+
+ foreach (var prop in props)
+ {
+ sb.Append(prop.Name);
+ sb.Append(": ");
+ sb.Append(prop.GetValue(args.Data));
+ sb.Append(" - ");
+ }
+
+ // We remove the final '-' from the string
+ if (props.Length > 0)
+ {
+ sb.Remove(sb.Length - 3, 3);
+ }
+ }
+
+ return sb.ToString();
+ }
+ finally
+ {
+ _stringBuilderPool.Release(sb);
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Common/Logging/Formatters/ILogFormatter.cs b/Ryujinx.Common/Logging/Formatters/ILogFormatter.cs
new file mode 100644
index 00000000..9a55bc6b
--- /dev/null
+++ b/Ryujinx.Common/Logging/Formatters/ILogFormatter.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.Common.Logging
+{
+ interface ILogFormatter
+ {
+ string Format(LogEventArgs args);
+ }
+}
diff --git a/Ryujinx.Common/Logging/LogClass.cs b/Ryujinx.Common/Logging/LogClass.cs
index f20347b6..66a83b37 100644
--- a/Ryujinx.Common/Logging/LogClass.cs
+++ b/Ryujinx.Common/Logging/LogClass.cs
@@ -2,6 +2,7 @@ namespace Ryujinx.Common.Logging
{
public enum LogClass
{
+ Application,
Audio,
Cpu,
Font,
diff --git a/Ryujinx.Common/Logging/Logger.cs b/Ryujinx.Common/Logging/Logger.cs
index 35ca416b..88ebe473 100644
--- a/Ryujinx.Common/Logging/Logger.cs
+++ b/Ryujinx.Common/Logging/Logger.cs
@@ -1,8 +1,7 @@
using System;
+using System.Collections.Generic;
using System.Diagnostics;
-using System.Reflection;
using System.Runtime.CompilerServices;
-using System.Text;
using System.Threading;
namespace Ryujinx.Common.Logging
@@ -14,9 +13,9 @@ namespace Ryujinx.Common.Logging
private static readonly bool[] m_EnabledLevels;
private static readonly bool[] m_EnabledClasses;
- public static event EventHandler<LogEventArgs> Updated;
+ private static readonly List<ILogTarget> m_LogTargets;
- public static bool EnableFileLog { get; set; }
+ public static event EventHandler<LogEventArgs> Updated;
static Logger()
{
@@ -33,9 +32,30 @@ namespace Ryujinx.Common.Logging
m_EnabledClasses[index] = true;
}
+ m_LogTargets = new List<ILogTarget>();
+
m_Time = Stopwatch.StartNew();
}
+ public static void AddTarget(ILogTarget target)
+ {
+ m_LogTargets.Add(target);
+
+ Updated += target.Log;
+ }
+
+ public static void Shutdown()
+ {
+ Updated = null;
+
+ foreach(var target in m_LogTargets)
+ {
+ target.Dispose();
+ }
+
+ m_LogTargets.Clear();
+ }
+
public static void SetEnable(LogLevel logLevel, bool enabled)
{
m_EnabledLevels[(int)logLevel] = enabled;
diff --git a/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs b/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs
new file mode 100644
index 00000000..a805a83b
--- /dev/null
+++ b/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Concurrent;
+using System.Threading;
+
+namespace Ryujinx.Common.Logging
+{
+ public enum AsyncLogTargetOverflowAction
+ {
+ /// <summary>
+ /// Block until there's more room in the queue
+ /// </summary>
+ Block = 0,
+
+ /// <summary>
+ /// Discard the overflowing item
+ /// </summary>
+ Discard = 1
+ }
+
+ public class AsyncLogTargetWrapper : ILogTarget
+ {
+ private ILogTarget _target;
+
+ private Thread _messageThread;
+
+ private BlockingCollection<LogEventArgs> _messageQueue;
+
+ private readonly int _overflowTimeout;
+
+ public AsyncLogTargetWrapper(ILogTarget target)
+ : this(target, -1, AsyncLogTargetOverflowAction.Block)
+ { }
+
+ public AsyncLogTargetWrapper(ILogTarget target, int queueLimit, AsyncLogTargetOverflowAction overflowAction)
+ {
+ _target = target;
+ _messageQueue = new BlockingCollection<LogEventArgs>(queueLimit);
+ _overflowTimeout = overflowAction == AsyncLogTargetOverflowAction.Block ? -1 : 0;
+
+ _messageThread = new Thread(() => {
+ while (!_messageQueue.IsCompleted)
+ {
+ try
+ {
+ _target.Log(this, _messageQueue.Take());
+ }
+ catch (InvalidOperationException)
+ {
+ // IOE means that Take() was called on a completed collection.
+ // Some other thread can call CompleteAdding after we pass the
+ // IsCompleted check but before we call Take.
+ // We can simply catch the exception since the loop will break
+ // on the next iteration.
+ }
+ }
+ });
+
+ _messageThread.IsBackground = true;
+ _messageThread.Start();
+ }
+
+ public void Log(object sender, LogEventArgs e)
+ {
+ if (!_messageQueue.IsAddingCompleted)
+ {
+ _messageQueue.TryAdd(e, _overflowTimeout);
+ }
+ }
+
+ public void Dispose()
+ {
+ _messageQueue.CompleteAdding();
+ _messageThread.Join();
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs b/Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs
new file mode 100644
index 00000000..871076a4
--- /dev/null
+++ b/Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Concurrent;
+
+namespace Ryujinx.Common.Logging
+{
+ public class ConsoleLogTarget : ILogTarget
+ {
+ private static readonly ConcurrentDictionary<LogLevel, ConsoleColor> _logColors;
+
+ private readonly ILogFormatter _formatter;
+
+ static ConsoleLogTarget()
+ {
+ _logColors = new ConcurrentDictionary<LogLevel, ConsoleColor> {
+ [ LogLevel.Stub ] = ConsoleColor.DarkGray,
+ [ LogLevel.Info ] = ConsoleColor.White,
+ [ LogLevel.Warning ] = ConsoleColor.Yellow,
+ [ LogLevel.Error ] = ConsoleColor.Red
+ };
+ }
+
+ public ConsoleLogTarget()
+ {
+ _formatter = new DefaultLogFormatter();
+ }
+
+ public void Log(object sender, LogEventArgs args)
+ {
+ if (_logColors.TryGetValue(args.Level, out ConsoleColor color))
+ {
+ Console.ForegroundColor = color;
+
+ Console.WriteLine(_formatter.Format(args));
+
+ Console.ResetColor();
+ }
+ else
+ {
+ Console.WriteLine(_formatter.Format(args));
+ }
+ }
+
+ public void Dispose()
+ {
+ Console.ResetColor();
+ }
+ }
+}
diff --git a/Ryujinx.Common/Logging/Targets/FileLogTarget.cs b/Ryujinx.Common/Logging/Targets/FileLogTarget.cs
new file mode 100644
index 00000000..85dc8249
--- /dev/null
+++ b/Ryujinx.Common/Logging/Targets/FileLogTarget.cs
@@ -0,0 +1,36 @@
+using System.IO;
+using System.Text;
+
+namespace Ryujinx.Common.Logging
+{
+ public class FileLogTarget : ILogTarget
+ {
+ private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
+
+ private readonly StreamWriter _logWriter;
+ private readonly ILogFormatter _formatter;
+
+ public FileLogTarget(string path)
+ : this(path, FileShare.Read, FileMode.Append)
+ { }
+
+ public FileLogTarget(string path, FileShare fileShare, FileMode fileMode)
+ {
+ _logWriter = new StreamWriter(File.Open(path, fileMode, FileAccess.Write, fileShare));
+ _formatter = new DefaultLogFormatter();
+ }
+
+ public void Log(object sender, LogEventArgs args)
+ {
+ _logWriter.WriteLine(_formatter.Format(args));
+ _logWriter.Flush();
+ }
+
+ public void Dispose()
+ {
+ _logWriter.WriteLine("---- End of Log ----");
+ _logWriter.Flush();
+ _logWriter.Dispose();
+ }
+ }
+}
diff --git a/Ryujinx.Common/Logging/Targets/ILogTarget.cs b/Ryujinx.Common/Logging/Targets/ILogTarget.cs
new file mode 100644
index 00000000..261c5e64
--- /dev/null
+++ b/Ryujinx.Common/Logging/Targets/ILogTarget.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Ryujinx.Common.Logging
+{
+ public interface ILogTarget : IDisposable
+ {
+ void Log(object sender, LogEventArgs args);
+ }
+}
diff --git a/Ryujinx.Common/Logging/Targets/JsonLogTarget.cs b/Ryujinx.Common/Logging/Targets/JsonLogTarget.cs
new file mode 100644
index 00000000..410394aa
--- /dev/null
+++ b/Ryujinx.Common/Logging/Targets/JsonLogTarget.cs
@@ -0,0 +1,35 @@
+using System.IO;
+using Utf8Json;
+
+namespace Ryujinx.Common.Logging
+{
+ public class JsonLogTarget : ILogTarget
+ {
+ private Stream _stream;
+ private bool _leaveOpen;
+
+ public JsonLogTarget(Stream stream)
+ {
+ _stream = stream;
+ }
+
+ public JsonLogTarget(Stream stream, bool leaveOpen)
+ {
+ _stream = stream;
+ _leaveOpen = leaveOpen;
+ }
+
+ public void Log(object sender, LogEventArgs e)
+ {
+ JsonSerializer.Serialize(_stream, e);
+ }
+
+ public void Dispose()
+ {
+ if (!_leaveOpen)
+ {
+ _stream.Dispose();
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Common/Pools/ObjectPool.cs b/Ryujinx.Common/Pools/ObjectPool.cs
new file mode 100644
index 00000000..dba671bb
--- /dev/null
+++ b/Ryujinx.Common/Pools/ObjectPool.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Threading;
+
+namespace Ryujinx.Common
+{
+ public class ObjectPool<T>
+ where T : class
+ {
+ private T _firstItem;
+ private readonly T[] _items;
+
+ private readonly Func<T> _factory;
+
+ public ObjectPool(Func<T> factory, int size)
+ {
+ _items = new T[size - 1];
+ _factory = factory;
+ }
+
+ public T Allocate()
+ {
+ var instance = _firstItem;
+
+ if (instance == null || instance != Interlocked.CompareExchange(ref _firstItem, null, instance))
+ {
+ instance = AllocateInternal();
+ }
+
+ return instance;
+ }
+
+ private T AllocateInternal()
+ {
+ var items = _items;
+
+ for (int i = 0; i < items.Length; i++)
+ {
+ var instance = items[i];
+
+ if (instance != null && instance == Interlocked.CompareExchange(ref items[i], null, instance))
+ {
+ return instance;
+ }
+ }
+
+ return _factory();
+ }
+
+ public void Release(T obj)
+ {
+ if (_firstItem == null)
+ {
+ _firstItem = obj;
+ }
+ else
+ {
+ ReleaseInternal(obj);
+ }
+ }
+
+ private void ReleaseInternal(T obj)
+ {
+ var items = _items;
+
+ for (int i = 0; i < items.Length; i++)
+ {
+ if (items[i] == null)
+ {
+ items[i] = obj;
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Common/Pools/SharedPools.cs b/Ryujinx.Common/Pools/SharedPools.cs
new file mode 100644
index 00000000..b4860b85
--- /dev/null
+++ b/Ryujinx.Common/Pools/SharedPools.cs
@@ -0,0 +1,17 @@
+namespace Ryujinx.Common
+{
+ public static class SharedPools
+ {
+ private static class DefaultPool<T>
+ where T : class, new()
+ {
+ public static readonly ObjectPool<T> Instance = new ObjectPool<T>(() => new T(), 20);
+ }
+
+ public static ObjectPool<T> Default<T>()
+ where T : class, new()
+ {
+ return DefaultPool<T>.Instance;
+ }
+ }
+}
diff --git a/Ryujinx.Common/Ryujinx.Common.csproj b/Ryujinx.Common/Ryujinx.Common.csproj
index 5c9293b7..bba481e6 100644
--- a/Ryujinx.Common/Ryujinx.Common.csproj
+++ b/Ryujinx.Common/Ryujinx.Common.csproj
@@ -13,4 +13,8 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="Utf8Json" Version="1.3.7" />
+ </ItemGroup>
+
</Project>
diff --git a/Ryujinx.Common/BitUtils.cs b/Ryujinx.Common/Utilities/BitUtils.cs
index 135b397d..135b397d 100644
--- a/Ryujinx.Common/BitUtils.cs
+++ b/Ryujinx.Common/Utilities/BitUtils.cs
diff --git a/Ryujinx.Common/HexUtils.cs b/Ryujinx.Common/Utilities/HexUtils.cs
index 63587cea..63587cea 100644
--- a/Ryujinx.Common/HexUtils.cs
+++ b/Ryujinx.Common/Utilities/HexUtils.cs
diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs
index d661b273..4a15f616 100644
--- a/Ryujinx.HLE/Switch.cs
+++ b/Ryujinx.HLE/Switch.cs
@@ -112,7 +112,6 @@ namespace Ryujinx.HLE
if (disposing)
{
System.Dispose();
-
VsyncEvent.Dispose();
}
}
diff --git a/Ryujinx.sln b/Ryujinx.sln
index 148224fa..990a89a2 100644
--- a/Ryujinx.sln
+++ b/Ryujinx.sln
@@ -23,6 +23,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luea", "Ryujinx.LLE\Luea.cs
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Common", "Ryujinx.Common\Ryujinx.Common.csproj", "{5FD4E4F6-8928-4B3C-BE07-28A675C17226}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{464D8AB7-B056-4A99-B207-B8DCFB47AAA9}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -73,6 +75,10 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9} = {464D8AB7-B056-4A99-B207-B8DCFB47AAA9}
+ {D8F72938-78EF-4E8C-BAFE-531C9C3C8F15} = {464D8AB7-B056-4A99-B207-B8DCFB47AAA9}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {110169B3-3328-4730-8AB0-BA05BEF75C1A}
EndGlobalSection
diff --git a/Ryujinx/Config.cs b/Ryujinx/Config.cs
deleted file mode 100644
index a1d8cddf..00000000
--- a/Ryujinx/Config.cs
+++ /dev/null
@@ -1,203 +0,0 @@
-using LibHac.IO;
-using Ryujinx.Common.Logging;
-using Ryujinx.HLE;
-using Ryujinx.HLE.HOS.SystemState;
-using Ryujinx.HLE.Input;
-using Ryujinx.UI.Input;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-
-namespace Ryujinx
-{
- public static class Config
- {
- public static NpadKeyboard NpadKeyboard { get; private set; }
- public static NpadController NpadController { get; private set; }
-
- public static void Read(Switch device)
- {
- string iniFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
-
- string iniPath = Path.Combine(iniFolder, "Ryujinx.conf");
-
- IniParser parser = new IniParser(iniPath);
-
- GraphicsConfig.ShadersDumpPath = parser.Value("Graphics_Shaders_Dump_Path");
-
- Logger.SetEnable(LogLevel.Debug, Convert.ToBoolean(parser.Value("Logging_Enable_Debug")));
- Logger.SetEnable(LogLevel.Stub, Convert.ToBoolean(parser.Value("Logging_Enable_Stub")));
- Logger.SetEnable(LogLevel.Info, Convert.ToBoolean(parser.Value("Logging_Enable_Info")));
- Logger.SetEnable(LogLevel.Warning, Convert.ToBoolean(parser.Value("Logging_Enable_Warn")));
- Logger.SetEnable(LogLevel.Error, Convert.ToBoolean(parser.Value("Logging_Enable_Error")));
-
- string[] filteredLogClasses = parser.Value("Logging_Filtered_Classes").Split(',', StringSplitOptions.RemoveEmptyEntries);
-
- //When the classes are specified on the list, we only
- //enable the classes that are on the list.
- //So, first disable everything, then enable
- //the classes that the user added to the list.
- if (filteredLogClasses.Length > 0)
- {
- foreach (LogClass Class in Enum.GetValues(typeof(LogClass)))
- {
- Logger.SetEnable(Class, false);
- }
- }
-
- foreach (string logClass in filteredLogClasses)
- {
- if (!string.IsNullOrEmpty(logClass.Trim()))
- {
- foreach (LogClass Class in Enum.GetValues(typeof(LogClass)))
- {
- if (Class.ToString().ToLower().Contains(logClass.Trim().ToLower()))
- {
- Logger.SetEnable(Class, true);
- }
- }
- }
- }
-
- Logger.EnableFileLog = Convert.ToBoolean(parser.Value("Enable_File_Log"));
-
- SystemLanguage SetLanguage = Enum.Parse<SystemLanguage>(parser.Value("System_Language"));
-
- device.System.State.SetLanguage(SetLanguage);
-
- device.System.State.DockedMode = Convert.ToBoolean(parser.Value("Docked_Mode"));
-
- device.EnableDeviceVsync = Convert.ToBoolean(parser.Value("Enable_Vsync"));
-
- if (Convert.ToBoolean(parser.Value("Enable_MultiCore_Scheduling")))
- {
- device.System.EnableMultiCoreScheduling();
- }
-
- device.System.FsIntegrityCheckLevel = Convert.ToBoolean(parser.Value("Enable_FS_Integrity_Checks"))
- ? IntegrityCheckLevel.ErrorOnInvalid
- : IntegrityCheckLevel.None;
-
- HidControllerType ControllerType = Enum.Parse<HidControllerType>(parser.Value("Controller_Type"));
-
- device.Hid.InitilizePrimaryController(ControllerType);
-
- NpadKeyboard = new NpadKeyboard(
-
- new NpadKeyboardLeft
- {
- StickUp = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Stick_Up")),
- StickDown = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Stick_Down")),
- StickLeft = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Stick_Left")),
- StickRight = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Stick_Right")),
- StickButton = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Stick_Button")),
- DPadUp = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_DPad_Up")),
- DPadDown = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_DPad_Down")),
- DPadLeft = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_DPad_Left")),
- DPadRight = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_DPad_Right")),
- ButtonMinus = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Button_Minus")),
- ButtonL = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Button_L")),
- ButtonZl = Convert.ToInt16(parser.Value("Controls_Left_JoyConKeyboard_Button_ZL"))
- },
-
- new NpadKeyboardRight
- {
- StickUp = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Stick_Up")),
- StickDown = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Stick_Down")),
- StickLeft = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Stick_Left")),
- StickRight = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Stick_Right")),
- StickButton = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Stick_Button")),
- ButtonA = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_A")),
- ButtonB = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_B")),
- ButtonX = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_X")),
- ButtonY = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_Y")),
- ButtonPlus = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_Plus")),
- ButtonR = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_R")),
- ButtonZr = Convert.ToInt16(parser.Value("Controls_Right_JoyConKeyboard_Button_ZR"))
- });
-
- NpadController = new NpadController(
- Convert.ToBoolean(parser.Value("GamePad_Enable")),
- Convert.ToInt32 (parser.Value("GamePad_Index")),
- (float)Convert.ToDouble (parser.Value("GamePad_Deadzone"), CultureInfo.InvariantCulture),
- (float)Convert.ToDouble (parser.Value("GamePad_Trigger_Threshold"), CultureInfo.InvariantCulture),
-
- new NpadControllerLeft
- {
- Stick = ToId(parser.Value("Controls_Left_JoyConController_Stick")),
- StickButton = ToId(parser.Value("Controls_Left_JoyConController_Stick_Button")),
- DPadUp = ToId(parser.Value("Controls_Left_JoyConController_DPad_Up")),
- DPadDown = ToId(parser.Value("Controls_Left_JoyConController_DPad_Down")),
- DPadLeft = ToId(parser.Value("Controls_Left_JoyConController_DPad_Left")),
- DPadRight = ToId(parser.Value("Controls_Left_JoyConController_DPad_Right")),
- ButtonMinus = ToId(parser.Value("Controls_Left_JoyConController_Button_Minus")),
- ButtonL = ToId(parser.Value("Controls_Left_JoyConController_Button_L")),
- ButtonZl = ToId(parser.Value("Controls_Left_JoyConController_Button_ZL"))
- },
-
- new NpadControllerRight
- {
- Stick = ToId(parser.Value("Controls_Right_JoyConController_Stick")),
- StickButton = ToId(parser.Value("Controls_Right_JoyConController_Stick_Button")),
- ButtonA = ToId(parser.Value("Controls_Right_JoyConController_Button_A")),
- ButtonB = ToId(parser.Value("Controls_Right_JoyConController_Button_B")),
- ButtonX = ToId(parser.Value("Controls_Right_JoyConController_Button_X")),
- ButtonY = ToId(parser.Value("Controls_Right_JoyConController_Button_Y")),
- ButtonPlus = ToId(parser.Value("Controls_Right_JoyConController_Button_Plus")),
- ButtonR = ToId(parser.Value("Controls_Right_JoyConController_Button_R")),
- ButtonZr = ToId(parser.Value("Controls_Right_JoyConController_Button_ZR"))
- });
- }
-
- private static ControllerInputId ToId(string key)
- {
- switch (key.ToUpper())
- {
- case "LSTICK": return ControllerInputId.LStick;
- case "DPADUP": return ControllerInputId.DPadUp;
- case "DPADDOWN": return ControllerInputId.DPadDown;
- case "DPADLEFT": return ControllerInputId.DPadLeft;
- case "DPADRIGHT": return ControllerInputId.DPadRight;
- case "BACK": return ControllerInputId.Back;
- case "LSHOULDER": return ControllerInputId.LShoulder;
- case "LTRIGGER": return ControllerInputId.LTrigger;
-
- case "RSTICK": return ControllerInputId.RStick;
- case "A": return ControllerInputId.A;
- case "B": return ControllerInputId.B;
- case "X": return ControllerInputId.X;
- case "Y": return ControllerInputId.Y;
- case "START": return ControllerInputId.Start;
- case "RSHOULDER": return ControllerInputId.RShoulder;
- case "RTRIGGER": return ControllerInputId.RTrigger;
-
- case "LJOYSTICK": return ControllerInputId.LJoystick;
- case "RJOYSTICK": return ControllerInputId.RJoystick;
-
- default: return ControllerInputId.Invalid;
- }
- }
- }
-
- //https://stackoverflow.com/a/37772571
- public class IniParser
- {
- private readonly Dictionary<string, string> _values;
-
- public IniParser(string path)
- {
- _values = File.ReadLines(path)
- .Where(line => !string.IsNullOrWhiteSpace(line) && !line.StartsWith('#'))
- .Select(line => line.Split('=', 2))
- .ToDictionary(parts => parts[0].Trim(), parts => parts.Length > 1 ? parts[1].Trim() : null);
- }
-
- public string Value(string name)
- {
- return _values.TryGetValue(name, out string value) ? value : null;
- }
- }
-} \ No newline at end of file
diff --git a/Ryujinx/Config.jsonc b/Ryujinx/Config.jsonc
new file mode 100644
index 00000000..1ba60164
--- /dev/null
+++ b/Ryujinx/Config.jsonc
@@ -0,0 +1,124 @@
+{
+ "$schema": "./_schema.json",
+
+ // Dump shaders in local directory (e.g. `C:\ShaderDumps`)
+ "graphics_shaders_dump_path": "",
+
+ // Enable print debug logs
+ "logging_enable_debug": false,
+
+ // Enable print stubbed calls logs
+ "logging_enable_stub": true,
+
+ // Enable print informations logs
+ "logging_enable_info": true,
+
+ // Enable print warning logs
+ "logging_enable_warn": true,
+
+ // Enable print error logs
+ "logging_enable_error": true,
+
+ // Filtered log classes, in a JSON array, eg. `[ "Loader", "ServiceFs" ]`
+ "logging_filtered_classes": [ ],
+
+ // Enable file logging
+ "enable_file_log": true,
+
+ // Change System Language
+ // System Language list: https://gist.github.com/HorrorTroll/b6e4a88d774c3c9b3bdf54d79a7ca43b
+ "system_language": "AmericanEnglish",
+
+ // Enable or Disable Docked Mode
+ "docked_mode": false,
+
+ // Enable or Disable Game Vsync
+ "enable_vsync": true,
+
+ // Enable or Disable Multi-core scheduling of threads
+ "enable_multicore_scheduling": false,
+
+ // Enable integrity checks on Switch content files
+ "enable_fs_integrity_checks": true,
+
+ // The primary controller's type
+ // Supported Values: Handheld, ProController, NpadPair, NpadLeft, NpadRight
+ "controller_type": "Handheld",
+
+ // Keyboard Controls
+ // https://github.com/opentk/opentk/blob/master/src/OpenTK/Input/Key.cs
+ "keyboard_controls": {
+ // Left JoyCon Keyboard Bindings
+ "left_joycon": {
+ "stick_up": "W",
+ "stick_down": "S",
+ "stick_left": "A",
+ "stick_right": "D",
+ "stick_button": "F",
+ "dpad_up": "Up",
+ "dpad_down": "Down",
+ "dpad_left": "Left",
+ "dpad_right": "Right",
+ "button_minus": "Minus",
+ "button_l": "E",
+ "button_zl": "Q"
+ },
+
+ // Right JoyCon Keyboard Bindings
+ "right_joycon": {
+ "stick_up": "I",
+ "stick_down": "K",
+ "stick_left": "J",
+ "stick_right": "L",
+ "stick_button": "H",
+ "button_a": "Z",
+ "button_b": "X",
+ "button_x": "C",
+ "button_y": "V",
+ "button_plus": "Plus",
+ "button_r": "U",
+ "button_zr": "O"
+ }
+ },
+
+ // Controller Controls
+ "gamepad_controls": {
+ // Whether or not to enable Controller support
+ "enabled": true,
+
+ // Controller Device Index
+ "index": 0,
+
+ // Controller Analog Stick Deadzone
+ "deadzone": 0.05,
+
+ // The value of how pressed down each trigger has to be in order to register a button press
+ "trigger_threshold": 0.5,
+
+ // Left JoyCon Controller Bindings
+ "left_joycon": {
+ "stick": "LJoystick",
+ "stick_button": "LStick",
+ "dpad_up": "DPadUp",
+ "dpad_down": "DPadDown",
+ "dpad_left": "DPadLeft",
+ "dpad_right": "DPadRight",
+ "button_minus": "Back",
+ "button_l": "LShoulder",
+ "button_zl": "LTrigger"
+ },
+
+ // Right JoyCon Controller Bindings
+ "right_joycon": {
+ "stick": "RJoystick",
+ "stick_button": "RStick",
+ "button_a": "B",
+ "button_b": "A",
+ "button_x": "Y",
+ "button_y": "X",
+ "button_plus": "Start",
+ "button_r": "RShoulder",
+ "button_zr": "RTrigger"
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Configuration.cs b/Ryujinx/Configuration.cs
new file mode 100644
index 00000000..5f1f8678
--- /dev/null
+++ b/Ryujinx/Configuration.cs
@@ -0,0 +1,239 @@
+using LibHac.IO;
+using OpenTK.Input;
+using Ryujinx.Common;
+using Ryujinx.Common.Logging;
+using Ryujinx.HLE;
+using Ryujinx.HLE.HOS.SystemState;
+using Ryujinx.HLE.Input;
+using Ryujinx.UI.Input;
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Utf8Json;
+using Utf8Json.Resolvers;
+
+namespace Ryujinx
+{
+ public class Configuration
+ {
+ /// <summary>
+ /// The default configuration instance
+ /// </summary>
+ public static Configuration Instance { get; private set; }
+
+ /// <summary>
+ /// Dumps shaders in this local directory
+ /// </summary>
+ public string GraphicsShadersDumpPath { get; private set; }
+
+ /// <summary>
+ /// Enables printing debug log messages
+ /// </summary>
+ public bool LoggingEnableDebug { get; private set; }
+
+ /// <summary>
+ /// Enables printing stub log messages
+ /// </summary>
+ public bool LoggingEnableStub { get; private set; }
+
+ /// <summary>
+ /// Enables printing info log messages
+ /// </summary>
+ public bool LoggingEnableInfo { get; private set; }
+
+ /// <summary>
+ /// Enables printing warning log messages
+ /// </summary>
+ public bool LoggingEnableWarn { get; private set; }
+
+ /// <summary>
+ /// Enables printing error log messages
+ /// </summary>
+ public bool LoggingEnableError { get; private set; }
+
+ /// <summary>
+ /// Controls which log messages are written to the log targets
+ /// </summary>
+ public LogClass[] LoggingFilteredClasses { get; private set; }
+
+ /// <summary>
+ /// Enables or disables logging to a file on disk
+ /// </summary>
+ public bool EnableFileLog { get; private set; }
+
+ /// <summary>
+ /// Change System Language
+ /// </summary>
+ public SystemLanguage SystemLanguage { get; private set; }
+
+ /// <summary>
+ /// Enables or disables Docked Mode
+ /// </summary>
+ public bool DockedMode { get; private set; }
+
+ /// <summary>
+ /// Enables or disables Vertical Sync
+ /// </summary>
+ public bool EnableVsync { get; private set; }
+
+ /// <summary>
+ /// Enables or disables multi-core scheduling of threads
+ /// </summary>
+ public bool EnableMultiCoreScheduling { get; private set; }
+
+ /// <summary>
+ /// Enables integrity checks on Game content files
+ /// </summary>
+ public bool EnableFsIntegrityChecks { get; private set; }
+
+ /// <summary>
+ /// The primary controller's type
+ /// </summary>
+ public HidControllerType ControllerType { get; private set; }
+
+ /// <summary>
+ /// Keyboard control bindings
+ /// </summary>
+ public NpadKeyboard KeyboardControls { get; private set; }
+
+ /// <summary>
+ /// Controller control bindings
+ /// </summary>
+ public NpadController GamepadControls { get; private set; }
+
+ /// <summary>
+ /// Loads a configuration file from disk
+ /// </summary>
+ /// <param name="path">The path to the JSON configuration file</param>
+ public static void Load(string path)
+ {
+ var resolver = CompositeResolver.Create(
+ new[] { new ConfigurationEnumFormatter<Key>() },
+ new[] { StandardResolver.AllowPrivateSnakeCase }
+ );
+
+ using (Stream stream = File.OpenRead(path))
+ {
+ Instance = JsonSerializer.Deserialize<Configuration>(stream, resolver);
+ }
+ }
+
+ /// <summary>
+ /// Loads a configuration file asynchronously from disk
+ /// </summary>
+ /// <param name="path">The path to the JSON configuration file</param>
+ public static async Task LoadAsync(string path)
+ {
+ var resolver = CompositeResolver.Create(
+ new[] { new ConfigurationEnumFormatter<Key>() },
+ new[] { StandardResolver.AllowPrivateSnakeCase }
+ );
+
+ using (Stream stream = File.OpenRead(path))
+ {
+ Instance = await JsonSerializer.DeserializeAsync<Configuration>(stream, resolver);
+ }
+ }
+
+ /// <summary>
+ /// Configures a <see cref="Switch"/> instance
+ /// </summary>
+ /// <param name="device">The instance to configure</param>
+ public static void Configure(Switch device)
+ {
+ if (Instance == null)
+ {
+ throw new InvalidOperationException("Configuration has not been loaded yet.");
+ }
+
+ GraphicsConfig.ShadersDumpPath = Instance.GraphicsShadersDumpPath;
+
+ Logger.AddTarget(new AsyncLogTargetWrapper(
+ new ConsoleLogTarget(),
+ 1000,
+ AsyncLogTargetOverflowAction.Block
+ ));
+
+ if (Instance.EnableFileLog)
+ {
+ Logger.AddTarget(new AsyncLogTargetWrapper(
+ new FileLogTarget("Ryujinx.log"),
+ 1000,
+ AsyncLogTargetOverflowAction.Block
+ ));
+ }
+
+ Logger.SetEnable(LogLevel.Debug, Instance.LoggingEnableDebug);
+ Logger.SetEnable(LogLevel.Stub, Instance.LoggingEnableStub);
+ Logger.SetEnable(LogLevel.Info, Instance.LoggingEnableInfo);
+ Logger.SetEnable(LogLevel.Warning, Instance.LoggingEnableWarn);
+ Logger.SetEnable(LogLevel.Error, Instance.LoggingEnableError);
+
+ if (Instance.LoggingFilteredClasses.Length > 0)
+ {
+ foreach (var logClass in EnumExtensions.GetValues<LogClass>())
+ {
+ Logger.SetEnable(logClass, false);
+ }
+
+ foreach (var logClass in Instance.LoggingFilteredClasses)
+ {
+ Logger.SetEnable(logClass, true);
+ }
+ }
+
+ device.EnableDeviceVsync = Instance.EnableVsync;
+
+ device.System.State.DockedMode = Instance.DockedMode;
+
+ device.System.State.SetLanguage(Instance.SystemLanguage);
+
+ if (Instance.EnableMultiCoreScheduling)
+ {
+ device.System.EnableMultiCoreScheduling();
+ }
+
+ device.System.FsIntegrityCheckLevel = Instance.EnableFsIntegrityChecks
+ ? IntegrityCheckLevel.ErrorOnInvalid
+ : IntegrityCheckLevel.None;
+
+ if(Instance.GamepadControls.Enabled)
+ {
+ if (GamePad.GetName(Instance.GamepadControls.Index) == "Unmapped Controller")
+ {
+ Instance.GamepadControls.SetEnabled(false);
+ }
+ }
+
+ device.Hid.InitilizePrimaryController(Instance.ControllerType);
+ }
+
+ private class ConfigurationEnumFormatter<T> : IJsonFormatter<T>
+ where T : struct
+ {
+ public void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver)
+ {
+ formatterResolver.GetFormatterWithVerify<string>()
+ .Serialize(ref writer, value.ToString(), formatterResolver);
+ }
+
+ public T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
+ {
+ if (reader.ReadIsNull())
+ {
+ return default(T);
+ }
+
+ var enumName = formatterResolver.GetFormatterWithVerify<string>()
+ .Deserialize(ref reader, formatterResolver);
+
+ if(Enum.TryParse<T>(enumName, out T result))
+ {
+ return result;
+ }
+
+ return default(T);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs
index 335aa0ea..19916fe9 100644
--- a/Ryujinx/Program.cs
+++ b/Ryujinx/Program.cs
@@ -20,9 +20,8 @@ namespace Ryujinx
Switch device = new Switch(renderer, audioOut);
- Config.Read(device);
-
- Logger.Updated += Log.LogMessage;
+ Configuration.Load("Config.jsonc");
+ Configuration.Configure(device);
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
@@ -40,13 +39,13 @@ namespace Ryujinx
if (romFsFiles.Length > 0)
{
- Console.WriteLine("Loading as cart with RomFS.");
+ Logger.PrintInfo(LogClass.Application, "Loading as cart with RomFS.");
device.LoadCart(args[0], romFsFiles[0]);
}
else
{
- Console.WriteLine("Loading as cart WITHOUT RomFS.");
+ Logger.PrintInfo(LogClass.Application, "Loading as cart WITHOUT RomFS.");
device.LoadCart(args[0]);
}
@@ -56,20 +55,20 @@ namespace Ryujinx
switch (Path.GetExtension(args[0]).ToLowerInvariant())
{
case ".xci":
- Console.WriteLine("Loading as XCI.");
+ Logger.PrintInfo(LogClass.Application, "Loading as XCI.");
device.LoadXci(args[0]);
break;
case ".nca":
- Console.WriteLine("Loading as NCA.");
+ Logger.PrintInfo(LogClass.Application, "Loading as NCA.");
device.LoadNca(args[0]);
break;
case ".nsp":
case ".pfs0":
- Console.WriteLine("Loading as NSP.");
+ Logger.PrintInfo(LogClass.Application, "Loading as NSP.");
device.LoadNsp(args[0]);
break;
default:
- Console.WriteLine("Loading as homebrew.");
+ Logger.PrintInfo(LogClass.Application, "Loading as homebrew.");
device.LoadProgram(args[0]);
break;
}
@@ -77,7 +76,7 @@ namespace Ryujinx
}
else
{
- Console.WriteLine("Please specify the folder with the NSOs/IStorage or a NSO/NRO.");
+ Logger.PrintInfo(LogClass.Application, "Please specify the folder with the NSOs/IStorage or a NSO/NRO.");
}
using (GlScreen screen = new GlScreen(device, renderer))
@@ -88,11 +87,13 @@ namespace Ryujinx
}
audioOut.Dispose();
+
+ Logger.Shutdown();
}
private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
- Log.Close();
+ Logger.Shutdown();
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
@@ -103,7 +104,7 @@ namespace Ryujinx
if (e.IsTerminating)
{
- Log.Close();
+ Logger.Shutdown();
}
}
diff --git a/Ryujinx/Ryujinx.conf b/Ryujinx/Ryujinx.conf
deleted file mode 100644
index 604b14ed..00000000
--- a/Ryujinx/Ryujinx.conf
+++ /dev/null
@@ -1,107 +0,0 @@
-#Enable cpu memory checks (slow)
-Enable_Memory_Checks = false
-
-#Dump shaders in local directory (e.g. `C:\ShaderDumps`)
-Graphics_Shaders_Dump_Path =
-
-#Enable print debug logs
-Logging_Enable_Debug = false
-
-#Enable print stubbed calls logs
-Logging_Enable_Stub = true
-
-#Enable print informations logs
-Logging_Enable_Info = true
-
-#Enable print warning logs
-Logging_Enable_Warn = true
-
-#Enable print error logs
-Logging_Enable_Error = true
-
-#Filtered log classes, seperated by ", ", eg. `Logging_Filtered_Classes = Loader, ServiceFS`
-Logging_Filtered_Classes =
-
-#Enable file logging
-Enable_File_Log = false
-
-#System Language list: https://gist.github.com/HorrorTroll/b6e4a88d774c3c9b3bdf54d79a7ca43b
-#Change System Language
-System_Language = AmericanEnglish
-
-#Enable or Disable Docked Mode
-Docked_Mode = false
-
-#Enable Game Vsync
-Enable_Vsync = true
-
-#Enable or Disable Multi-core scheduling of threads
-Enable_MultiCore_Scheduling = false
-
-#Enable integrity checks on Switch content files
-Enable_FS_Integrity_Checks = true
-
-#Controller Device Index
-GamePad_Index = 0
-
-#Controller Analog Stick Deadzone
-GamePad_Deadzone = 0.05
-
-#The value of how pressed down each trigger has to be in order to register a button press
-GamePad_Trigger_Threshold = 0.5
-
-#Whether or not to enable Controller support
-GamePad_Enable = true
-
-#The primary controller's type. Supported Values: ProController, Handheld, NpadPair, NpadLeft, NpadRight
-Controller_Type = Handheld
-
-#https://github.com/opentk/opentk/blob/develop/src/OpenTK/Input/Key.cs
-Controls_Left_JoyConKeyboard_Stick_Up = 105
-Controls_Left_JoyConKeyboard_Stick_Down = 101
-Controls_Left_JoyConKeyboard_Stick_Left = 83
-Controls_Left_JoyConKeyboard_Stick_Right = 86
-Controls_Left_JoyConKeyboard_Stick_Button = 88
-Controls_Left_JoyConKeyboard_DPad_Up = 45
-Controls_Left_JoyConKeyboard_DPad_Down = 46
-Controls_Left_JoyConKeyboard_DPad_Left = 47
-Controls_Left_JoyConKeyboard_DPad_Right = 48
-Controls_Left_JoyConKeyboard_Button_Minus = 120
-Controls_Left_JoyConKeyboard_Button_L = 87
-Controls_Left_JoyConKeyboard_Button_ZL = 99
-
-Controls_Right_JoyConKeyboard_Stick_Up = 91
-Controls_Right_JoyConKeyboard_Stick_Down = 93
-Controls_Right_JoyConKeyboard_Stick_Left = 92
-Controls_Right_JoyConKeyboard_Stick_Right = 94
-Controls_Right_JoyConKeyboard_Stick_Button = 90
-Controls_Right_JoyConKeyboard_Button_A = 108
-Controls_Right_JoyConKeyboard_Button_B = 106
-Controls_Right_JoyConKeyboard_Button_X = 85
-Controls_Right_JoyConKeyboard_Button_Y = 104
-Controls_Right_JoyConKeyboard_Button_Plus = 121
-Controls_Right_JoyConKeyboard_Button_R = 103
-Controls_Right_JoyConKeyboard_Button_ZR = 97
-
-#Controller Controls
-
-Controls_Left_JoyConController_Stick_Button = LStick
-Controls_Left_JoyConController_DPad_Up = DPadUp
-Controls_Left_JoyConController_DPad_Down = DPadDown
-Controls_Left_JoyConController_DPad_Left = DPadLeft
-Controls_Left_JoyConController_DPad_Right = DPadRight
-Controls_Left_JoyConController_Button_Minus = Back
-Controls_Left_JoyConController_Button_L = LShoulder
-Controls_Left_JoyConController_Button_ZL = LTrigger
-
-Controls_Right_JoyConController_Stick_Button = RStick
-Controls_Right_JoyConController_Button_A = B
-Controls_Right_JoyConController_Button_B = A
-Controls_Right_JoyConController_Button_X = Y
-Controls_Right_JoyConController_Button_Y = X
-Controls_Right_JoyConController_Button_Plus = Start
-Controls_Right_JoyConController_Button_R = RShoulder
-Controls_Right_JoyConController_Button_ZR = RTrigger
-
-Controls_Left_JoyConController_Stick = LJoystick
-Controls_Right_JoyConController_Stick = RJoystick
diff --git a/Ryujinx/Ryujinx.csproj b/Ryujinx/Ryujinx.csproj
index 1789ef2e..08725846 100644
--- a/Ryujinx/Ryujinx.csproj
+++ b/Ryujinx/Ryujinx.csproj
@@ -20,7 +20,7 @@
</ItemGroup>
<ItemGroup>
- <None Update="Ryujinx.conf">
+ <None Update="Config.jsonc">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs
index e3a6d299..c7aaea23 100644
--- a/Ryujinx/Ui/GLScreen.cs
+++ b/Ryujinx/Ui/GLScreen.cs
@@ -142,24 +142,24 @@ namespace Ryujinx
{
KeyboardState keyboard = _keyboard.Value;
- currentButton = Config.NpadKeyboard.GetButtons(keyboard);
+ currentButton = Configuration.Instance.KeyboardControls.GetButtons(keyboard);
- (leftJoystickDx, leftJoystickDy) = Config.NpadKeyboard.GetLeftStick(keyboard);
+ (leftJoystickDx, leftJoystickDy) = Configuration.Instance.KeyboardControls.GetLeftStick(keyboard);
- (rightJoystickDx, rightJoystickDy) = Config.NpadKeyboard.GetRightStick(keyboard);
+ (rightJoystickDx, rightJoystickDy) = Configuration.Instance.KeyboardControls.GetRightStick(keyboard);
}
- currentButton |= Config.NpadController.GetButtons();
+ currentButton |= Configuration.Instance.GamepadControls.GetButtons();
//Keyboard has priority stick-wise
if (leftJoystickDx == 0 && leftJoystickDy == 0)
{
- (leftJoystickDx, leftJoystickDy) = Config.NpadController.GetLeftStick();
+ (leftJoystickDx, leftJoystickDy) = Configuration.Instance.GamepadControls.GetLeftStick();
}
if (rightJoystickDx == 0 && rightJoystickDy == 0)
{
- (rightJoystickDx, rightJoystickDy) = Config.NpadController.GetRightStick();
+ (rightJoystickDx, rightJoystickDy) = Configuration.Instance.GamepadControls.GetRightStick();
}
leftJoystick = new HidJoystickPosition
diff --git a/Ryujinx/Ui/Log.cs b/Ryujinx/Ui/Log.cs
deleted file mode 100644
index 5daae140..00000000
--- a/Ryujinx/Ui/Log.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-using Ryujinx.Common.Logging;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Text;
-using System.Threading;
-
-namespace Ryujinx
-{
- static class Log
- {
- private static readonly string _path;
-
- private static StreamWriter _logWriter;
-
- private static Thread _messageThread;
-
- private static BlockingCollection<LogEventArgs> _messageQueue;
-
- private static Dictionary<LogLevel, ConsoleColor> _logColors;
-
- static Log()
- {
- _logColors = new Dictionary<LogLevel, ConsoleColor>()
- {
- { LogLevel.Stub, ConsoleColor.DarkGray },
- { LogLevel.Info, ConsoleColor.White },
- { LogLevel.Warning, ConsoleColor.Yellow },
- { LogLevel.Error, ConsoleColor.Red }
- };
-
- _messageQueue = new BlockingCollection<LogEventArgs>(10);
-
- _messageThread = new Thread(() =>
- {
- while (!_messageQueue.IsCompleted)
- {
- try
- {
- PrintLog(_messageQueue.Take());
- }
- catch (InvalidOperationException)
- {
- // IOE means that Take() was called on a completed collection.
- // Some other thread can call CompleteAdding after we pass the
- // IsCompleted check but before we call Take.
- // We can simply catch the exception since the loop will break
- // on the next iteration.
- }
- }
- });
-
- _path = Path.Combine(Environment.CurrentDirectory, "Ryujinx.log");
-
- if (Logger.EnableFileLog)
- {
- _logWriter = new StreamWriter(File.Open(_path,FileMode.Create, FileAccess.Write));
- }
-
- _messageThread.IsBackground = true;
- _messageThread.Start();
- }
-
- private static void PrintLog(LogEventArgs e)
- {
- StringBuilder sb = new StringBuilder();
-
- sb.AppendFormat(@"{0:hh\:mm\:ss\.fff}", e.Time);
- sb.Append(" | ");
- sb.AppendFormat("{0:d4}", e.ThreadId);
- sb.Append(' ');
- sb.Append(e.Message);
-
- if (e.Data != null)
- {
- PropertyInfo[] props = e.Data.GetType().GetProperties();
-
- sb.Append(' ');
-
- foreach (var prop in props)
- {
- sb.Append(prop.Name);
- sb.Append(": ");
- sb.Append(prop.GetValue(e.Data));
- sb.Append(" - ");
- }
-
- // We remove the final '-' from the string
- if (props.Length > 0)
- {
- sb.Remove(sb.Length - 3, 3);
- }
- }
-
- string message = sb.ToString();
-
- if (_logColors.TryGetValue(e.Level, out ConsoleColor color))
- {
- Console.ForegroundColor = color;
-
- Console.WriteLine(message);
-
- Console.ResetColor();
- }
- else
- {
- Console.WriteLine(message);
- }
-
- if (Logger.EnableFileLog)
- {
- _logWriter.WriteLine(message);
- }
- }
-
- public static void LogMessage(object sender, LogEventArgs e)
- {
- if (!_messageQueue.IsAddingCompleted)
- {
- _messageQueue.Add(e);
- }
- }
-
- public static void Close()
- {
- _messageQueue.CompleteAdding();
-
- _messageThread.Join();
-
- if (Logger.EnableFileLog)
- {
- _logWriter.Flush();
- _logWriter.Close();
- _logWriter.Dispose();
- }
- }
- }
-}
diff --git a/Ryujinx/Ui/NpadController.cs b/Ryujinx/Ui/NpadController.cs
index 58d2d46a..1b677c4f 100644
--- a/Ryujinx/Ui/NpadController.cs
+++ b/Ryujinx/Ui/NpadController.cs
@@ -8,28 +8,24 @@ namespace Ryujinx.UI.Input
public enum ControllerInputId
{
Invalid,
-
LStick,
+ RStick,
+ LShoulder,
+ RShoulder,
+ LTrigger,
+ RTrigger,
+ LJoystick,
+ RJoystick,
DPadUp,
DPadDown,
DPadLeft,
DPadRight,
+ Start,
Back,
- LShoulder,
-
- RStick,
A,
B,
X,
- Y,
- Start,
- RShoulder,
-
- LTrigger,
- RTrigger,
-
- LJoystick,
- RJoystick
+ Y
}
public struct NpadControllerLeft
@@ -60,34 +56,55 @@ namespace Ryujinx.UI.Input
public class NpadController
{
- public bool Enabled { private set; get; }
- public int Index { private set; get; }
- public float Deadzone { private set; get; }
- public float TriggerThreshold { private set; get; }
-
- public NpadControllerLeft Left { private set; get; }
- public NpadControllerRight Right { private set; get; }
+ /// <summary>
+ /// Enables or disables controller support
+ /// </summary>
+ public bool Enabled { get; private set; }
+
+ /// <summary>
+ /// Controller Device Index
+ /// </summary>
+ public int Index { get; private set; }
+
+ /// <summary>
+ /// Controller Analog Stick Deadzone
+ /// </summary>
+ public float Deadzone { get; private set; }
+
+ /// <summary>
+ /// Controller Trigger Threshold
+ /// </summary>
+ public float TriggerThreshold { get; private set; }
+
+ /// <summary>
+ /// Left JoyCon Controller Bindings
+ /// </summary>
+ public NpadControllerLeft LeftJoycon { get; private set; }
+
+ /// <summary>
+ /// Right JoyCon Controller Bindings
+ /// </summary>
+ public NpadControllerRight RightJoycon { get; private set; }
public NpadController(
- bool enabled,
- int index,
- float deadzone,
- float triggerThreshold,
- NpadControllerLeft left,
- NpadControllerRight right)
+ bool enabled,
+ int index,
+ float deadzone,
+ float triggerThreshold,
+ NpadControllerLeft leftJoycon,
+ NpadControllerRight rightJoycon)
{
Enabled = enabled;
Index = index;
Deadzone = deadzone;
TriggerThreshold = triggerThreshold;
- Left = left;
- Right = right;
+ LeftJoycon = leftJoycon;
+ RightJoycon = rightJoycon;
+ }
- //Unmapped controllers are problematic, skip them
- if (GamePad.GetName(index) == "Unmapped Controller")
- {
- Enabled = false;
- }
+ public void SetEnabled(bool enabled)
+ {
+ Enabled = enabled;
}
public HidControllerButtons GetButtons()
@@ -101,23 +118,23 @@ namespace Ryujinx.UI.Input
HidControllerButtons buttons = 0;
- if (IsPressed(gpState, Left.DPadUp)) buttons |= HidControllerButtons.DpadUp;
- if (IsPressed(gpState, Left.DPadDown)) buttons |= HidControllerButtons.DpadDown;
- if (IsPressed(gpState, Left.DPadLeft)) buttons |= HidControllerButtons.DpadLeft;
- if (IsPressed(gpState, Left.DPadRight)) buttons |= HidControllerButtons.DPadRight;
- if (IsPressed(gpState, Left.StickButton)) buttons |= HidControllerButtons.StickLeft;
- if (IsPressed(gpState, Left.ButtonMinus)) buttons |= HidControllerButtons.Minus;
- if (IsPressed(gpState, Left.ButtonL)) buttons |= HidControllerButtons.L;
- if (IsPressed(gpState, Left.ButtonZl)) buttons |= HidControllerButtons.Zl;
-
- if (IsPressed(gpState, Right.ButtonA)) buttons |= HidControllerButtons.A;
- if (IsPressed(gpState, Right.ButtonB)) buttons |= HidControllerButtons.B;
- if (IsPressed(gpState, Right.ButtonX)) buttons |= HidControllerButtons.X;
- if (IsPressed(gpState, Right.ButtonY)) buttons |= HidControllerButtons.Y;
- if (IsPressed(gpState, Right.StickButton)) buttons |= HidControllerButtons.StickRight;
- if (IsPressed(gpState, Right.ButtonPlus)) buttons |= HidControllerButtons.Plus;
- if (IsPressed(gpState, Right.ButtonR)) buttons |= HidControllerButtons.R;
- if (IsPressed(gpState, Right.ButtonZr)) buttons |= HidControllerButtons.Zr;
+ if (IsPressed(gpState, LeftJoycon.DPadUp)) buttons |= HidControllerButtons.DpadUp;
+ if (IsPressed(gpState, LeftJoycon.DPadDown)) buttons |= HidControllerButtons.DpadDown;
+ if (IsPressed(gpState, LeftJoycon.DPadLeft)) buttons |= HidControllerButtons.DpadLeft;
+ if (IsPressed(gpState, LeftJoycon.DPadRight)) buttons |= HidControllerButtons.DPadRight;
+ if (IsPressed(gpState, LeftJoycon.StickButton)) buttons |= HidControllerButtons.StickLeft;
+ if (IsPressed(gpState, LeftJoycon.ButtonMinus)) buttons |= HidControllerButtons.Minus;
+ if (IsPressed(gpState, LeftJoycon.ButtonL)) buttons |= HidControllerButtons.L;
+ if (IsPressed(gpState, LeftJoycon.ButtonZl)) buttons |= HidControllerButtons.Zl;
+
+ if (IsPressed(gpState, RightJoycon.ButtonA)) buttons |= HidControllerButtons.A;
+ if (IsPressed(gpState, RightJoycon.ButtonB)) buttons |= HidControllerButtons.B;
+ if (IsPressed(gpState, RightJoycon.ButtonX)) buttons |= HidControllerButtons.X;
+ if (IsPressed(gpState, RightJoycon.ButtonY)) buttons |= HidControllerButtons.Y;
+ if (IsPressed(gpState, RightJoycon.StickButton)) buttons |= HidControllerButtons.StickRight;
+ if (IsPressed(gpState, RightJoycon.ButtonPlus)) buttons |= HidControllerButtons.Plus;
+ if (IsPressed(gpState, RightJoycon.ButtonR)) buttons |= HidControllerButtons.R;
+ if (IsPressed(gpState, RightJoycon.ButtonZr)) buttons |= HidControllerButtons.Zr;
return buttons;
}
@@ -129,7 +146,7 @@ namespace Ryujinx.UI.Input
return (0, 0);
}
- return GetStick(Left.Stick);
+ return GetStick(LeftJoycon.Stick);
}
public (short, short) GetRightStick()
@@ -139,7 +156,7 @@ namespace Ryujinx.UI.Input
return (0, 0);
}
- return GetStick(Right.Stick);
+ return GetStick(RightJoycon.Stick);
}
private (short, short) GetStick(ControllerInputId joystick)
diff --git a/Ryujinx/Ui/NpadKeyboard.cs b/Ryujinx/Ui/NpadKeyboard.cs
index 704c61ab..1604da5b 100644
--- a/Ryujinx/Ui/NpadKeyboard.cs
+++ b/Ryujinx/Ui/NpadKeyboard.cs
@@ -5,70 +5,69 @@ namespace Ryujinx.UI.Input
{
public struct NpadKeyboardLeft
{
- public int StickUp;
- public int StickDown;
- public int StickLeft;
- public int StickRight;
- public int StickButton;
- public int DPadUp;
- public int DPadDown;
- public int DPadLeft;
- public int DPadRight;
- public int ButtonMinus;
- public int ButtonL;
- public int ButtonZl;
+ public Key StickUp;
+ public Key StickDown;
+ public Key StickLeft;
+ public Key StickRight;
+ public Key StickButton;
+ public Key DPadUp;
+ public Key DPadDown;
+ public Key DPadLeft;
+ public Key DPadRight;
+ public Key ButtonMinus;
+ public Key ButtonL;
+ public Key ButtonZl;
}
public struct NpadKeyboardRight
{
- public int StickUp;
- public int StickDown;
- public int StickLeft;
- public int StickRight;
- public int StickButton;
- public int ButtonA;
- public int ButtonB;
- public int ButtonX;
- public int ButtonY;
- public int ButtonPlus;
- public int ButtonR;
- public int ButtonZr;
+ public Key StickUp;
+ public Key StickDown;
+ public Key StickLeft;
+ public Key StickRight;
+ public Key StickButton;
+ public Key ButtonA;
+ public Key ButtonB;
+ public Key ButtonX;
+ public Key ButtonY;
+ public Key ButtonPlus;
+ public Key ButtonR;
+ public Key ButtonZr;
}
public class NpadKeyboard
{
- public NpadKeyboardLeft Left;
- public NpadKeyboardRight Right;
+ /// <summary>
+ /// Left JoyCon Keyboard Bindings
+ /// </summary>
+ public NpadKeyboardLeft LeftJoycon { get; private set; }
- public NpadKeyboard(
- NpadKeyboardLeft left,
- NpadKeyboardRight right)
- {
- Left = left;
- Right = right;
- }
+ /// <summary>
+ /// Right JoyCon Keyboard Bindings
+ /// </summary>
+ public NpadKeyboardRight RightJoycon { get; private set; }
public HidControllerButtons GetButtons(KeyboardState keyboard)
{
HidControllerButtons buttons = 0;
- if (keyboard[(Key)Left.StickButton]) buttons |= HidControllerButtons.StickLeft;
- if (keyboard[(Key)Left.DPadUp]) buttons |= HidControllerButtons.DpadUp;
- if (keyboard[(Key)Left.DPadDown]) buttons |= HidControllerButtons.DpadDown;
- if (keyboard[(Key)Left.DPadLeft]) buttons |= HidControllerButtons.DpadLeft;
- if (keyboard[(Key)Left.DPadRight]) buttons |= HidControllerButtons.DPadRight;
- if (keyboard[(Key)Left.ButtonMinus]) buttons |= HidControllerButtons.Minus;
- if (keyboard[(Key)Left.ButtonL]) buttons |= HidControllerButtons.L;
- if (keyboard[(Key)Left.ButtonZl]) buttons |= HidControllerButtons.Zl;
+ if (keyboard[(Key)LeftJoycon.StickButton]) buttons |= HidControllerButtons.StickLeft;
+ if (keyboard[(Key)LeftJoycon.DPadUp]) buttons |= HidControllerButtons.DpadUp;
+ if (keyboard[(Key)LeftJoycon.DPadDown]) buttons |= HidControllerButtons.DpadDown;
+ if (keyboard[(Key)LeftJoycon.DPadLeft]) buttons |= HidControllerButtons.DpadLeft;
+ if (keyboard[(Key)LeftJoycon.DPadRight]) buttons |= HidControllerButtons.DPadRight;
+ if (keyboard[(Key)LeftJoycon.ButtonMinus]) buttons |= HidControllerButtons.Minus;
+ if (keyboard[(Key)LeftJoycon.ButtonL]) buttons |= HidControllerButtons.L;
+ if (keyboard[(Key)LeftJoycon.ButtonZl]) buttons |= HidControllerButtons.Zl;
- if (keyboard[(Key)Right.StickButton]) buttons |= HidControllerButtons.StickRight;
- if (keyboard[(Key)Right.ButtonA]) buttons |= HidControllerButtons.A;
- if (keyboard[(Key)Right.ButtonB]) buttons |= HidControllerButtons.B;
- if (keyboard[(Key)Right.ButtonX]) buttons |= HidControllerButtons.X;
- if (keyboard[(Key)Right.ButtonY]) buttons |= HidControllerButtons.Y;
- if (keyboard[(Key)Right.ButtonPlus]) buttons |= HidControllerButtons.Plus;
- if (keyboard[(Key)Right.ButtonR]) buttons |= HidControllerButtons.R;
- if (keyboard[(Key)Right.ButtonZr]) buttons |= HidControllerButtons.Zr;
+ if (keyboard[(Key)RightJoycon.StickButton]) buttons |= HidControllerButtons.StickRight;
+ if (keyboard[(Key)RightJoycon.ButtonA]) buttons |= HidControllerButtons.A;
+ if (keyboard[(Key)RightJoycon.ButtonB]) buttons |= HidControllerButtons.B;
+ if (keyboard[(Key)RightJoycon.ButtonX]) buttons |= HidControllerButtons.X;
+ if (keyboard[(Key)RightJoycon.ButtonY]) buttons |= HidControllerButtons.Y;
+ if (keyboard[(Key)RightJoycon.ButtonPlus]) buttons |= HidControllerButtons.Plus;
+ if (keyboard[(Key)RightJoycon.ButtonR]) buttons |= HidControllerButtons.R;
+ if (keyboard[(Key)RightJoycon.ButtonZr]) buttons |= HidControllerButtons.Zr;
return buttons;
}
@@ -78,10 +77,10 @@ namespace Ryujinx.UI.Input
short dx = 0;
short dy = 0;
- if (keyboard[(Key)Left.StickUp]) dy = short.MaxValue;
- if (keyboard[(Key)Left.StickDown]) dy = -short.MaxValue;
- if (keyboard[(Key)Left.StickLeft]) dx = -short.MaxValue;
- if (keyboard[(Key)Left.StickRight]) dx = short.MaxValue;
+ if (keyboard[(Key)LeftJoycon.StickUp]) dy = short.MaxValue;
+ if (keyboard[(Key)LeftJoycon.StickDown]) dy = -short.MaxValue;
+ if (keyboard[(Key)LeftJoycon.StickLeft]) dx = -short.MaxValue;
+ if (keyboard[(Key)LeftJoycon.StickRight]) dx = short.MaxValue;
return (dx, dy);
}
@@ -91,10 +90,10 @@ namespace Ryujinx.UI.Input
short dx = 0;
short dy = 0;
- if (keyboard[(Key)Right.StickUp]) dy = short.MaxValue;
- if (keyboard[(Key)Right.StickDown]) dy = -short.MaxValue;
- if (keyboard[(Key)Right.StickLeft]) dx = -short.MaxValue;
- if (keyboard[(Key)Right.StickRight]) dx = short.MaxValue;
+ if (keyboard[(Key)RightJoycon.StickUp]) dy = short.MaxValue;
+ if (keyboard[(Key)RightJoycon.StickDown]) dy = -short.MaxValue;
+ if (keyboard[(Key)RightJoycon.StickLeft]) dx = -short.MaxValue;
+ if (keyboard[(Key)RightJoycon.StickRight]) dx = short.MaxValue;
return (dx, dy);
}
diff --git a/Ryujinx/_schema.json b/Ryujinx/_schema.json
new file mode 100644
index 00000000..28f35111
--- /dev/null
+++ b/Ryujinx/_schema.json
@@ -0,0 +1,823 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://ryujinx.org/_schema/config.json",
+ "type": "object",
+ "title": "Ryujinx Configuration Schema",
+ "required": [
+ "graphics_shaders_dump_path",
+ "logging_enable_debug",
+ "logging_enable_stub",
+ "logging_enable_info",
+ "logging_enable_warn",
+ "logging_enable_error",
+ "logging_filtered_classes",
+ "enable_file_log",
+ "system_language",
+ "docked_mode",
+ "enable_vsync",
+ "enable_multicore_scheduling",
+ "enable_fs_integrity_checks",
+ "controller_type",
+ "keyboard_controls",
+ "gamepad_controls"
+ ],
+ "definitions": {
+ "key": {
+ "type": "string",
+ "enum": [
+ "ShiftLeft",
+ "LShift",
+ "ShiftRight",
+ "RShift",
+ "ControlLeft",
+ "LControl",
+ "ControlRight",
+ "RControl",
+ "AltLeft",
+ "LAlt",
+ "AltRight",
+ "RAlt",
+ "WinLeft",
+ "LWin",
+ "WinRight",
+ "RWin",
+ "Menu",
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+ "F8",
+ "F9",
+ "F10",
+ "F11",
+ "F12",
+ "F13",
+ "F14",
+ "F15",
+ "F16",
+ "F17",
+ "F18",
+ "F19",
+ "F20",
+ "F21",
+ "F22",
+ "F23",
+ "F24",
+ "F25",
+ "F26",
+ "F27",
+ "F28",
+ "F29",
+ "F30",
+ "F31",
+ "F32",
+ "F33",
+ "F34",
+ "F35",
+ "Up",
+ "Down",
+ "Left",
+ "Right",
+ "Enter",
+ "Escape",
+ "Space",
+ "Tab",
+ "BackSpace",
+ "Back",
+ "Insert",
+ "Delete",
+ "PageUp",
+ "PageDown",
+ "Home",
+ "End",
+ "CapsLock",
+ "ScrollLock",
+ "PrintScreen",
+ "Pause",
+ "NumLock",
+ "Clear",
+ "Sleep",
+ "Keypad0",
+ "Keypad1",
+ "Keypad2",
+ "Keypad3",
+ "Keypad4",
+ "Keypad5",
+ "Keypad6",
+ "Keypad7",
+ "Keypad8",
+ "Keypad9",
+ "KeypadDivide",
+ "KeypadMultiply",
+ "KeypadSubtract",
+ "KeypadMinus",
+ "KeypadAdd",
+ "KeypadPlus",
+ "KeypadDecimal",
+ "KeypadPeriod",
+ "KeypadEnter",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "Number0",
+ "Number1",
+ "Number2",
+ "Number3",
+ "Number4",
+ "Number5",
+ "Number6",
+ "Number7",
+ "Number8",
+ "Number9",
+ "Tilde",
+ "Grave",
+ "Minus",
+ "Plus",
+ "BracketLeft",
+ "LBracket",
+ "BracketRight",
+ "RBracket",
+ "Semicolon",
+ "Quote",
+ "Comma",
+ "Period",
+ "Slash",
+ "BackSlash",
+ "NonUSBackSlash",
+ "LastKey"
+ ]
+ },
+ "input": {
+ "type": "string",
+ "enum": [
+ "DPadUp",
+ "DPadDown",
+ "DPadLeft",
+ "DPadRight",
+ "LStick",
+ "RStick",
+ "LShoulder",
+ "RShoulder",
+ "LTrigger",
+ "RTrigger",
+ "LJoystick",
+ "RJoystick",
+ "A",
+ "B",
+ "X",
+ "Y",
+ "Start",
+ "Back"
+ ]
+ }
+ },
+ "properties": {
+ "graphics_shaders_dump_path": {
+ "$id": "#/properties/graphics_shaders_dump_path",
+ "type": "string",
+ "title": "Graphics Shaders Dump Path",
+ "description": "Dumps shaders in this local directory",
+ "default": "",
+ "examples": [
+ "C:\\ShaderDumps"
+ ]
+ },
+ "logging_enable_debug": {
+ "$id": "#/properties/logging_enable_debug",
+ "type": "boolean",
+ "title": "Logging Enable Debug",
+ "description": "Enables printing debug log messages",
+ "default": false,
+ "examples": [
+ true,
+ false
+ ]
+ },
+ "logging_enable_stub": {
+ "$id": "#/properties/logging_enable_stub",
+ "type": "boolean",
+ "title": "Logging Enable Stub",
+ "description": "Enables printing stub log messages",
+ "default": true,
+ "examples": [
+ true,
+ false
+ ]
+ },
+ "logging_enable_info": {
+ "$id": "#/properties/logging_enable_info",
+ "type": "boolean",
+ "title": "Logging Enable Info",
+ "description": "Enables printing info log messages",
+ "default": true,
+ "examples": [
+ true,
+ false
+ ]
+ },
+ "logging_enable_warn": {
+ "$id": "#/properties/logging_enable_warn",
+ "type": "boolean",
+ "title": "Logging Enable Warn",
+ "description": "Enables printing warning log messages",
+ "default": true,
+ "examples": [
+ true,
+ false
+ ]
+ },
+ "logging_enable_error": {
+ "$id": "#/properties/logging_enable_error",
+ "type": "boolean",
+ "title": "Logging Enable Error",
+ "description": "Enables printing error log messages",
+ "default": true,
+ "examples": [
+ true,
+ false
+ ]
+ },
+ "logging_filtered_classes": {
+ "$id": "#/properties/logging_filtered_classes",
+ "type": "array",
+ "title": "Logging Filtered Classes",
+ "description": "Controls which log messages are written to the log targets",
+ "items": {
+ "type": "string",
+ "enum": [
+ "Application",
+ "Audio",
+ "Cpu",
+ "Font",
+ "Emulation",
+ "Gpu",
+ "Hid",
+ "Kernel",
+ "KernelIpc",
+ "KernelScheduler",
+ "KernelSvc",
+ "Loader",
+ "Service",
+ "ServiceAcc",
+ "ServiceAm",
+ "ServiceApm",
+ "ServiceAudio",
+ "ServiceBsd",
+ "ServiceCaps",
+ "ServiceFriend",
+ "ServiceFs",
+ "ServiceHid",
+ "ServiceIrs",
+ "ServiceLdr",
+ "ServiceLm",
+ "ServiceMm",
+ "ServiceNfp",
+ "ServiceNifm",
+ "ServiceNs",
+ "ServiceNv",
+ "ServicePctl",
+ "ServicePl",
+ "ServicePrepo",
+ "ServicePsm",
+ "ServiceSet",
+ "ServiceSfdnsres",
+ "ServiceSm",
+ "ServiceSsl",
+ "ServiceSss",
+ "ServiceTime",
+ "ServiceVi"
+ ]
+ }
+ },
+ "enable_file_log": {
+ "$id": "#/properties/enable_file_log",
+ "type": "boolean",
+ "title": "Enable File Log",
+ "description": "Enables logging to a file on disk",
+ "default": true,
+ "examples": [
+ true,
+ false
+ ]
+ },
+ "system_language": {
+ "$id": "#/properties/system_language",
+ "type": "string",
+ "title": "System Language",
+ "description": "Change System Language",
+ "default": "AmericanEnglish",
+ "enum": [
+ "Japanese",
+ "AmericanEnglish",
+ "French",
+ "German",
+ "Italian",
+ "Spanish",
+ "Chinese",
+ "Korean",
+ "Dutch",
+ "Portuguese",
+ "Russian",
+ "Taiwanese",
+ "BritishEnglish",
+ "CanadianFrench",
+ "LatinAmericanSpanish",
+ "SimplifiedChinese",
+ "TraditionalChinese"
+ ],
+ "examples": [
+ "AmericanEnglish"
+ ]
+ },
+ "docked_mode": {
+ "$id": "#/properties/docked_mode",
+ "type": "boolean",
+ "title": "Enable Docked Mode",
+ "description": "Enables or disables Docked Mode",
+ "default": false,
+ "examples": [
+ true,
+ false
+ ]
+ },
+ "enable_vsync": {
+ "$id": "#/properties/enable_vsync",
+ "type": "boolean",
+ "title": "Enable Vertical Sync",
+ "description": "Enables or disables Vertical Sync",
+ "default": true,
+ "examples": [
+ true,
+ false
+ ]
+ },
+ "enable_multicore_scheduling": {
+ "$id": "#/properties/enable_multicore_scheduling",
+ "type": "boolean",
+ "title": "Enable Multicore Scheduling",
+ "description": "Enables or disables multi-core scheduling of threads",
+ "default": false,
+ "examples": [
+ true,
+ false
+ ]
+ },
+ "enable_fs_integrity_checks": {
+ "$id": "#/properties/enable_fs_integrity_checks",
+ "type": "boolean",
+ "title": "Enable Filesystem Integrity Checks",
+ "description": "Enables integrity checks on Game content files. Only applies to ROMs loaded as XCI files",
+ "default": true,
+ "examples": [
+ true,
+ false
+ ]
+ },
+ "controller_type": {
+ "$id": "#/properties/controller_type",
+ "type": "string",
+ "title": "Controller Type",
+ "default": "Handheld",
+ "enum": [
+ "Handheld",
+ "ProController",
+ "NpadPair",
+ "NpadLeft",
+ "NpadRight"
+ ],
+ "examples": [
+ "Handheld",
+ "ProController",
+ "NpadPair",
+ "NpadLeft",
+ "NpadRight"
+ ]
+ },
+ "keyboard_controls": {
+ "$id": "#/properties/keyboard_controls",
+ "type": "object",
+ "title": "Keyboard Controls",
+ "required": [
+ "left_joycon",
+ "right_joycon"
+ ],
+ "properties": {
+ "left_joycon": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon",
+ "type": "object",
+ "title": "Left JoyCon Controls",
+ "required": [
+ "stick_up",
+ "stick_down",
+ "stick_left",
+ "stick_right",
+ "stick_button",
+ "dpad_up",
+ "dpad_down",
+ "dpad_left",
+ "dpad_right",
+ "button_minus",
+ "button_l",
+ "button_zl"
+ ],
+ "properties": {
+ "stick_up": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/stick_up",
+ "$ref": "#/definitions/key",
+ "title": "Stick Up",
+ "default": "w"
+ },
+ "stick_down": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/stick_down",
+ "$ref": "#/definitions/key",
+ "title": "Stick Down",
+ "default": "S"
+ },
+ "stick_left": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/stick_left",
+ "$ref": "#/definitions/key",
+ "title": "Stick Left",
+ "default": "A"
+ },
+ "stick_right": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/stick_right",
+ "$ref": "#/definitions/key",
+ "title": "Stick Right",
+ "default": "D"
+ },
+ "stick_button": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/stick_button",
+ "$ref": "#/definitions/key",
+ "title": "Stick Button",
+ "default": "F"
+ },
+ "dpad_up": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/dpad_up",
+ "$ref": "#/definitions/key",
+ "title": "Dpad Up",
+ "default": "Up"
+ },
+ "dpad_down": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/dpad_down",
+ "$ref": "#/definitions/key",
+ "title": "Dpad Down",
+ "default": "Down"
+ },
+ "dpad_left": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/dpad_left",
+ "$ref": "#/definitions/key",
+ "title": "Dpad Left",
+ "default": "Left"
+ },
+ "dpad_right": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/dpad_right",
+ "$ref": "#/definitions/key",
+ "title": "Dpad Right",
+ "default": "Right"
+ },
+ "button_minus": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/button_minus",
+ "$ref": "#/definitions/key",
+ "title": "Button Minus",
+ "default": "Minus"
+ },
+ "button_l": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/button_l",
+ "$ref": "#/definitions/key",
+ "title": "Button L",
+ "default": "E"
+ },
+ "button_zl": {
+ "$id": "#/properties/keyboard_controls/properties/left_joycon/properties/button_zl",
+ "$ref": "#/definitions/key",
+ "title": "Button ZL",
+ "default": "Q"
+ }
+ }
+ },
+ "right_joycon": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon",
+ "type": "object",
+ "title": "Right JoyCon Controls",
+ "required": [
+ "stick_up",
+ "stick_down",
+ "stick_left",
+ "stick_right",
+ "stick_button",
+ "button_a",
+ "button_b",
+ "button_x",
+ "button_y",
+ "button_plus",
+ "button_r",
+ "button_zr"
+ ],
+ "properties": {
+ "stick_up": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/stick_up",
+ "$ref": "#/definitions/key",
+ "title": "Stick Up",
+ "default": "I"
+ },
+ "stick_down": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/stick_down",
+ "$ref": "#/definitions/key",
+ "title": "Stick Down",
+ "default": "K"
+ },
+ "stick_left": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/stick_left",
+ "$ref": "#/definitions/key",
+ "title": "Stick Left",
+ "default": "J"
+ },
+ "stick_right": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/stick_right",
+ "$ref": "#/definitions/key",
+ "title": "Stick Right",
+ "default": "L"
+ },
+ "stick_button": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/stick_button",
+ "$ref": "#/definitions/key",
+ "title": "Stick Button",
+ "default": "H"
+ },
+ "button_a": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_a",
+ "$ref": "#/definitions/key",
+ "title": "Button A",
+ "default": "Z"
+ },
+ "button_b": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_b",
+ "$ref": "#/definitions/key",
+ "title": "Button B",
+ "default": "X"
+ },
+ "button_x": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_x",
+ "$ref": "#/definitions/key",
+ "title": "Button X",
+ "default": "C"
+ },
+ "button_y": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_y",
+ "$ref": "#/definitions/key",
+ "title": "Button Y",
+ "default": "V"
+ },
+ "button_plus": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_plus",
+ "$ref": "#/definitions/key",
+ "title": "Button Plus",
+ "default": "Plus"
+ },
+ "button_r": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_r",
+ "$ref": "#/definitions/key",
+ "title": "Button R",
+ "default": "U"
+ },
+ "button_zr": {
+ "$id": "#/properties/keyboard_controls/properties/right_joycon/properties/button_zr",
+ "$ref": "#/definitions/key",
+ "title": "Button Zr",
+ "default": "O"
+ }
+ }
+ }
+ }
+ },
+ "gamepad_controls": {
+ "$id": "#/properties/gamepad_controls",
+ "type": "object",
+ "title": "GamePad Controls",
+ "required": [
+ "left_joycon",
+ "right_joycon"
+ ],
+ "properties": {
+ "enable": {
+ "$id": "#/properties/gamepad_controls/properties/enable",
+ "type": "boolean",
+ "title": "Gamepad Enable",
+ "description": "Enables or disables controller support",
+ "default": true,
+ "examples": [
+ true,
+ false
+ ]
+ },
+ "index": {
+ "$id": "#/properties/gamepad_controls/properties/index",
+ "type": "integer",
+ "title": "Gamepad Index",
+ "description": "Controller Device Index",
+ "default": 0,
+ "minimum": 0,
+ "examples": [
+ 0,
+ 1,
+ 2
+ ]
+ },
+ "deadzone": {
+ "$id": "#/properties/gamepad_controls/properties/deadzone",
+ "type": "number",
+ "title": "Gamepad Deadzone",
+ "description": "Controller Analog Stick Deadzone",
+ "default": 0.05,
+ "minimum": -32768.0,
+ "maximum": 32767.0,
+ "examples": [
+ 0.05
+ ]
+ },
+ "trigger_threshold": {
+ "$id": "#/properties/gamepad_controls/properties/trigger_threshold",
+ "type": "number",
+ "title": "Controller Trigger Threshold",
+ "description": "The value of how pressed down each trigger has to be in order to register a button press",
+ "default": 0.5,
+ "minimum": 0.0,
+ "maximum": 1.0,
+ "examples": [
+ 0.5
+ ]
+ },
+ "left_joycon": {
+ "$id": "#/properties/gamepad_controls/properties/left_joycon",
+ "type": "object",
+ "title": "Left JoyCon Controls",
+ "required": [
+ "stick",
+ "stick_button",
+ "dpad_up",
+ "dpad_down",
+ "dpad_left",
+ "dpad_right",
+ "button_minus",
+ "button_l",
+ "button_zl"
+ ],
+ "properties": {
+ "stick": {
+ "$id": "#/properties/gamepad_controls/properties/left_joycon/properties/stick",
+ "$ref": "#/definitions/input",
+ "title": "Stick",
+ "default": "LJoystick"
+ },
+ "stick_button": {
+ "$id": "#/properties/gamepad_controls/properties/left_joycon/properties/stick_button",
+ "$ref": "#/definitions/input",
+ "title": "Stick Button",
+ "default": "LStick"
+ },
+ "dpad_up": {
+ "$id": "#/properties/gamepad_controls/properties/left_joycon/properties/dpad_up",
+ "$ref": "#/definitions/input",
+ "title": "Dpad Up",
+ "default": "DPadUp"
+ },
+ "dpad_down": {
+ "$id": "#/properties/gamepad_controls/properties/left_joycon/properties/dpad_down",
+ "$ref": "#/definitions/input",
+ "title": "Dpad Down",
+ "default": "DPadDown"
+ },
+ "dpad_left": {
+ "$id": "#/properties/gamepad_controls/properties/left_joycon/properties/dpad_left",
+ "$ref": "#/definitions/input",
+ "title": "Dpad Left",
+ "default": "DPadLeft"
+ },
+ "dpad_right": {
+ "$id": "#/properties/gamepad_controls/properties/left_joycon/properties/dpad_right",
+ "$ref": "#/definitions/input",
+ "title": "Dpad Right",
+ "default": "DPadRight"
+ },
+ "button_minus": {
+ "$id": "#/properties/gamepad_controls/properties/left_joycon/properties/button_minus",
+ "$ref": "#/definitions/input",
+ "title": "Button Minus",
+ "default": "Back"
+ },
+ "button_l": {
+ "$id": "#/properties/gamepad_controls/properties/left_joycon/properties/button_l",
+ "$ref": "#/definitions/input",
+ "title": "Button L",
+ "default": "LShoulder"
+ },
+ "button_zl": {
+ "$id": "#/properties/gamepad_controls/properties/left_joycon/properties/button_zl",
+ "$ref": "#/definitions/input",
+ "title": "Button ZL",
+ "default": "LTrigger"
+ }
+ }
+ },
+ "right_joycon": {
+ "$id": "#/properties/gamepad_controls/properties/right_joycon",
+ "type": "object",
+ "title": "Right JoyCon Controls",
+ "required": [
+ "stick",
+ "stick_button",
+ "button_a",
+ "button_b",
+ "button_x",
+ "button_y",
+ "button_plus",
+ "button_r",
+ "button_zr"
+ ],
+ "properties": {
+ "stick": {
+ "$id": "#/properties/gamepad_controls/properties/right_joycon/properties/stick",
+ "$ref": "#/definitions/input",
+ "title": "Stick",
+ "default": "RJoystick"
+ },
+ "stick_button": {
+ "$id": "#/properties/gamepad_controls/properties/right_joycon/properties/stick_button",
+ "$ref": "#/definitions/input",
+ "title": "Stick Button",
+ "default": "RStick"
+ },
+ "button_a": {
+ "$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_a",
+ "$ref": "#/definitions/input",
+ "title": "Button A",
+ "default": "B"
+ },
+ "button_b": {
+ "$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_b",
+ "$ref": "#/definitions/input",
+ "title": "Button B",
+ "default": "A"
+ },
+ "button_x": {
+ "$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_x",
+ "$ref": "#/definitions/input",
+ "title": "Button X",
+ "default": "Y"
+ },
+ "button_y": {
+ "$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_y",
+ "$ref": "#/definitions/input",
+ "title": "Button Y",
+ "default": "X"
+ },
+ "button_plus": {
+ "$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_plus",
+ "$ref": "#/definitions/input",
+ "title": "Button Plus",
+ "default": "Start"
+ },
+ "button_r": {
+ "$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_r",
+ "$ref": "#/definitions/input",
+ "title": "Button R",
+ "default": "RShoulder"
+ },
+ "button_zr": {
+ "$id": "#/properties/gamepad_controls/properties/right_joycon/properties/button_zr",
+ "$ref": "#/definitions/input",
+ "title": "Button ZR",
+ "default": "RTrigger"
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file