Merge 13d94afd39
into 51605fafc0
This commit is contained in:
commit
4dab29ffa4
41 changed files with 4893 additions and 118 deletions
|
@ -8,6 +8,7 @@ using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace ChocolArm64
|
namespace ChocolArm64
|
||||||
{
|
{
|
||||||
|
@ -21,6 +22,8 @@ namespace ChocolArm64
|
||||||
|
|
||||||
public bool EnableCpuTrace { get; set; }
|
public bool EnableCpuTrace { get; set; }
|
||||||
|
|
||||||
|
private ManualResetEvent PauseResetEvent = new ManualResetEvent(true);
|
||||||
|
|
||||||
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
|
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
|
||||||
{
|
{
|
||||||
CachedSubs = new ConcurrentDictionary<long, ATranslatedSub>();
|
CachedSubs = new ConcurrentDictionary<long, ATranslatedSub>();
|
||||||
|
@ -60,6 +63,8 @@ namespace ChocolArm64
|
||||||
AOpCode OpCode = ADecoder.DecodeOpCode(State, Memory, State.R15);
|
AOpCode OpCode = ADecoder.DecodeOpCode(State, Memory, State.R15);
|
||||||
|
|
||||||
OpCode.Interpreter(State, Memory, OpCode);
|
OpCode.Interpreter(State, Memory, OpCode);
|
||||||
|
|
||||||
|
PauseResetEvent.WaitOne();
|
||||||
}
|
}
|
||||||
while (State.R15 != 0 && State.Running);
|
while (State.R15 != 0 && State.Running);
|
||||||
}
|
}
|
||||||
|
@ -89,6 +94,8 @@ namespace ChocolArm64
|
||||||
}
|
}
|
||||||
|
|
||||||
Position = Sub.Execute(State, Memory);
|
Position = Sub.Execute(State, Memory);
|
||||||
|
|
||||||
|
PauseResetEvent.WaitOne();
|
||||||
}
|
}
|
||||||
while (Position != 0 && State.Running);
|
while (Position != 0 && State.Running);
|
||||||
}
|
}
|
||||||
|
@ -202,5 +209,15 @@ namespace ChocolArm64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Pause()
|
||||||
|
{
|
||||||
|
PauseResetEvent.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resume()
|
||||||
|
{
|
||||||
|
PauseResetEvent.Set();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Audio
|
namespace Ryujinx.Audio
|
||||||
{
|
{
|
||||||
public interface IAalOutput
|
public interface IAalOutput : IDisposable
|
||||||
{
|
{
|
||||||
int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback);
|
int OpenTrack(int SampleRate, int Channels, ReleaseCallback Callback);
|
||||||
|
|
||||||
|
|
|
@ -341,5 +341,30 @@ namespace Ryujinx.Audio.OpenAL
|
||||||
|
|
||||||
return PlaybackState.Stopped;
|
return PlaybackState.Stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool Disposing)
|
||||||
|
{
|
||||||
|
if (Disposing)
|
||||||
|
{
|
||||||
|
KeepPolling = false;
|
||||||
|
|
||||||
|
foreach (var Track in Tracks)
|
||||||
|
{
|
||||||
|
if (Track.Value.State == PlaybackState.Playing)
|
||||||
|
Stop(Track.Key);
|
||||||
|
|
||||||
|
Track.Value.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Tracks.Clear();
|
||||||
|
|
||||||
|
Context.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,7 +5,7 @@ using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx
|
namespace Ryujinx
|
||||||
{
|
{
|
||||||
static class ConsoleLog
|
public static class ConsoleLog
|
||||||
{
|
{
|
||||||
private static Dictionary<LogLevel, ConsoleColor> LogColors;
|
private static Dictionary<LogLevel, ConsoleColor> LogColors;
|
||||||
|
|
28
Ryujinx.Common/Input/GamePadButton.cs
Normal file
28
Ryujinx.Common/Input/GamePadButton.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
namespace Ryujinx.Common.Input
|
||||||
|
{
|
||||||
|
public enum GamePadButton
|
||||||
|
{
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
LStick,
|
||||||
|
RStick,
|
||||||
|
LShoulder,
|
||||||
|
RShoulder,
|
||||||
|
DPadUp,
|
||||||
|
DPadDown,
|
||||||
|
DPadLeft,
|
||||||
|
DPadRight,
|
||||||
|
Start,
|
||||||
|
Back,
|
||||||
|
LTrigger,
|
||||||
|
RTrigger,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum GamePadStick
|
||||||
|
{
|
||||||
|
LJoystick,
|
||||||
|
RJoystick
|
||||||
|
}
|
||||||
|
}
|
34
Ryujinx.Common/Input/JoyConController.cs
Normal file
34
Ryujinx.Common/Input/JoyConController.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
namespace Ryujinx.Common.Input
|
||||||
|
{
|
||||||
|
public struct JoyConControllerLeft
|
||||||
|
{
|
||||||
|
public GamePadStick Stick;
|
||||||
|
public GamePadButton StickButton;
|
||||||
|
public GamePadButton DPadUp;
|
||||||
|
public GamePadButton DPadDown;
|
||||||
|
public GamePadButton DPadLeft;
|
||||||
|
public GamePadButton DPadRight;
|
||||||
|
public GamePadButton ButtonMinus;
|
||||||
|
public GamePadButton ButtonL;
|
||||||
|
public GamePadButton ButtonZL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct JoyConControllerRight
|
||||||
|
{
|
||||||
|
public GamePadStick Stick;
|
||||||
|
public GamePadButton StickButton;
|
||||||
|
public GamePadButton ButtonA;
|
||||||
|
public GamePadButton ButtonB;
|
||||||
|
public GamePadButton ButtonX;
|
||||||
|
public GamePadButton ButtonY;
|
||||||
|
public GamePadButton ButtonPlus;
|
||||||
|
public GamePadButton ButtonR;
|
||||||
|
public GamePadButton ButtonZR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct JoyConController
|
||||||
|
{
|
||||||
|
public JoyConControllerLeft Left;
|
||||||
|
public JoyConControllerRight Right;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Ryujinx.UI.Input
|
namespace Ryujinx.Common.Input
|
||||||
{
|
{
|
||||||
public struct JoyConKeyboardLeft
|
public struct JoyConKeyboardLeft
|
||||||
{
|
{
|
11
Ryujinx.Common/Ryujinx.Common.csproj
Normal file
11
Ryujinx.Common/Ryujinx.Common.csproj
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gal
|
namespace Ryujinx.Graphics.Gal
|
||||||
{
|
{
|
||||||
public interface IGalRenderer
|
public interface IGalRenderer : IDisposable
|
||||||
{
|
{
|
||||||
void QueueAction(Action ActionMthd);
|
void QueueAction(Action ActionMthd);
|
||||||
|
|
||||||
|
|
|
@ -46,5 +46,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
RenderAction();
|
RenderAction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool Disposing)
|
||||||
|
{
|
||||||
|
if (Disposing)
|
||||||
|
{
|
||||||
|
ActionsQueue.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.HLE.Gpu.Engines;
|
using Ryujinx.HLE.Gpu.Engines;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Gpu
|
namespace Ryujinx.HLE.Gpu
|
||||||
{
|
{
|
||||||
class NvGpu
|
class NvGpu : IDisposable
|
||||||
{
|
{
|
||||||
public IGalRenderer Renderer { get; private set; }
|
public IGalRenderer Renderer { get; private set; }
|
||||||
|
|
||||||
|
@ -23,5 +24,10 @@ namespace Ryujinx.HLE.Gpu
|
||||||
Engine3d = new NvGpuEngine3d(this);
|
Engine3d = new NvGpuEngine3d(this);
|
||||||
EngineDma = new NvGpuEngineDma(this);
|
EngineDma = new NvGpuEngineDma(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Renderer.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@ using System.IO;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Loaders.Executables
|
namespace Ryujinx.HLE.Loaders.Executables
|
||||||
{
|
{
|
||||||
class Nro : IExecutable
|
public class Nro : IExecutable
|
||||||
{
|
{
|
||||||
public string FilePath { get; private set; }
|
public string FilePath { get; private set; }
|
||||||
|
|
||||||
|
@ -15,10 +15,11 @@ namespace Ryujinx.HLE.Loaders.Executables
|
||||||
public int ROOffset { get; private set; }
|
public int ROOffset { get; private set; }
|
||||||
public int DataOffset { get; private set; }
|
public int DataOffset { get; private set; }
|
||||||
public int BssSize { get; private set; }
|
public int BssSize { get; private set; }
|
||||||
|
public int FileSize { get; private set; }
|
||||||
|
|
||||||
public Nro(Stream Input, string FilePath)
|
public Nro(Stream Input, string FilePath)
|
||||||
{
|
{
|
||||||
this.FilePath = FilePath;
|
this.FilePath = this.FilePath;
|
||||||
|
|
||||||
BinaryReader Reader = new BinaryReader(Input);
|
BinaryReader Reader = new BinaryReader(Input);
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ namespace Ryujinx.HLE.Loaders.Executables
|
||||||
this.ROOffset = ROOffset;
|
this.ROOffset = ROOffset;
|
||||||
this.DataOffset = DataOffset;
|
this.DataOffset = DataOffset;
|
||||||
this.BssSize = BssSize;
|
this.BssSize = BssSize;
|
||||||
|
this.FileSize = FileSize;
|
||||||
|
|
||||||
byte[] Read(long Position, int Size)
|
byte[] Read(long Position, int Size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,6 +43,16 @@ namespace Ryujinx.HLE.Logging
|
||||||
EnabledClasses[(int)Class] = Enabled;
|
EnabledClasses[(int)Class] = Enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsEnabled(LogLevel LogLevel)
|
||||||
|
{
|
||||||
|
return EnabledLevels[(int)LogLevel];
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFiltered(LogClass LogClass)
|
||||||
|
{
|
||||||
|
return EnabledClasses[(int)LogClass];
|
||||||
|
}
|
||||||
|
|
||||||
internal void PrintDebug(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
internal void PrintDebug(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||||
{
|
{
|
||||||
Print(LogLevel.Debug, Class, GetFormattedMessage(Class, Message, Caller));
|
Print(LogLevel.Debug, Class, GetFormattedMessage(Class, Message, Caller));
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace Ryujinx.HLE.OsHle
|
||||||
|
|
||||||
private ConcurrentDictionary<int, Process> Processes;
|
private ConcurrentDictionary<int, Process> Processes;
|
||||||
|
|
||||||
|
private bool IsDisposing;
|
||||||
|
|
||||||
public SystemStateMgr SystemState { get; private set; }
|
public SystemStateMgr SystemState { get; private set; }
|
||||||
|
|
||||||
internal MemoryAllocator Allocator { get; private set; }
|
internal MemoryAllocator Allocator { get; private set; }
|
||||||
|
@ -147,6 +149,22 @@ namespace Ryujinx.HLE.OsHle
|
||||||
return Process;
|
return Process;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PauseAllProcesses()
|
||||||
|
{
|
||||||
|
foreach (Process Process in Processes.Values)
|
||||||
|
{
|
||||||
|
Process.Pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResumeAllProcesses()
|
||||||
|
{
|
||||||
|
foreach (Process Process in Processes.Values)
|
||||||
|
{
|
||||||
|
Process.Resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void InitializeProcess(Process Process)
|
private void InitializeProcess(Process Process)
|
||||||
{
|
{
|
||||||
Process.AppletState.SetFocus(true);
|
Process.AppletState.SetFocus(true);
|
||||||
|
@ -154,7 +172,7 @@ namespace Ryujinx.HLE.OsHle
|
||||||
|
|
||||||
internal void ExitProcess(int ProcessId)
|
internal void ExitProcess(int ProcessId)
|
||||||
{
|
{
|
||||||
if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi)
|
if (Processes.TryGetValue(ProcessId, out Process Process) && Process.NeedsHbAbi && !IsDisposing)
|
||||||
{
|
{
|
||||||
string NextNro = Homebrew.ReadHbAbiNextLoadPath(Process.Memory, Process.HbAbiDataPosition);
|
string NextNro = Homebrew.ReadHbAbiNextLoadPath(Process.Memory, Process.HbAbiDataPosition);
|
||||||
|
|
||||||
|
@ -178,7 +196,6 @@ namespace Ryujinx.HLE.OsHle
|
||||||
if (Processes.TryRemove(ProcessId, out Process))
|
if (Processes.TryRemove(ProcessId, out Process))
|
||||||
{
|
{
|
||||||
Process.StopAllThreadsAsync();
|
Process.StopAllThreadsAsync();
|
||||||
Process.Dispose();
|
|
||||||
|
|
||||||
if (Processes.Count == 0)
|
if (Processes.Count == 0)
|
||||||
{
|
{
|
||||||
|
@ -199,6 +216,8 @@ namespace Ryujinx.HLE.OsHle
|
||||||
|
|
||||||
protected virtual void Dispose(bool Disposing)
|
protected virtual void Dispose(bool Disposing)
|
||||||
{
|
{
|
||||||
|
IsDisposing = Disposing;
|
||||||
|
|
||||||
if (Disposing)
|
if (Disposing)
|
||||||
{
|
{
|
||||||
foreach (Process Process in Processes.Values)
|
foreach (Process Process in Processes.Values)
|
||||||
|
|
|
@ -169,6 +169,26 @@ namespace Ryujinx.HLE.OsHle
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Pause()
|
||||||
|
{
|
||||||
|
if (Disposed)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException(nameof(Process));
|
||||||
|
}
|
||||||
|
|
||||||
|
Translator.Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resume()
|
||||||
|
{
|
||||||
|
if (Disposed)
|
||||||
|
{
|
||||||
|
throw new ObjectDisposedException(nameof(Process));
|
||||||
|
}
|
||||||
|
|
||||||
|
Translator.Resume();
|
||||||
|
}
|
||||||
|
|
||||||
private void MapRWMemRegion(long Position, long Size, MemoryType Type)
|
private void MapRWMemRegion(long Position, long Size, MemoryType Type)
|
||||||
{
|
{
|
||||||
Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW);
|
Memory.Manager.Map(Position, Size, (int)Type, AMemoryPerm.RW);
|
||||||
|
@ -178,7 +198,7 @@ namespace Ryujinx.HLE.OsHle
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (Disposed)
|
||||||
{
|
{
|
||||||
throw new ObjectDisposedException(nameof(Process));
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MainThread != null)
|
if (MainThread != null)
|
||||||
|
@ -403,6 +423,8 @@ namespace Ryujinx.HLE.OsHle
|
||||||
{
|
{
|
||||||
if (Disposing && !Disposed)
|
if (Disposing && !Disposed)
|
||||||
{
|
{
|
||||||
|
Translator.Resume();
|
||||||
|
|
||||||
//If there is still some thread running, disposing the objects is not
|
//If there is still some thread running, disposing the objects is not
|
||||||
//safe as the thread may try to access those resources. Instead, we set
|
//safe as the thread may try to access those resources. Instead, we set
|
||||||
//the flag to have the Process disposed when all threads finishes.
|
//the flag to have the Process disposed when all threads finishes.
|
||||||
|
|
|
@ -98,6 +98,8 @@ namespace Ryujinx.HLE
|
||||||
{
|
{
|
||||||
Os.Dispose();
|
Os.Dispose();
|
||||||
VFs.Dispose();
|
VFs.Dispose();
|
||||||
|
Gpu.Dispose();
|
||||||
|
AudioOut.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System.IO;
|
||||||
|
|
||||||
namespace Ryujinx.HLE
|
namespace Ryujinx.HLE
|
||||||
{
|
{
|
||||||
class VirtualFileSystem : IDisposable
|
public class VirtualFileSystem : IDisposable
|
||||||
{
|
{
|
||||||
private const string BasePath = "RyuFs";
|
private const string BasePath = "RyuFs";
|
||||||
private const string NandPath = "nand";
|
private const string NandPath = "nand";
|
||||||
|
|
315
Ryujinx.UI/Config.cs
Normal file
315
Ryujinx.UI/Config.cs
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
using Ryujinx.Common.Input;
|
||||||
|
using Ryujinx.HLE;
|
||||||
|
using Ryujinx.HLE.Logging;
|
||||||
|
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 JoyConKeyboard JoyConKeyboard { get; set; }
|
||||||
|
public static JoyConController JoyConController { get; set; }
|
||||||
|
|
||||||
|
public static float GamePadDeadzone { get; set; }
|
||||||
|
public static bool GamePadEnable { get; set; }
|
||||||
|
public static int GamePadIndex { get; set; }
|
||||||
|
public static float GamePadTriggerThreshold { get; set; }
|
||||||
|
|
||||||
|
public static string IniPath { get; set; }
|
||||||
|
|
||||||
|
public static string DefaultGameDirectory { get; set; }
|
||||||
|
|
||||||
|
public static void Read(Logger Log)
|
||||||
|
{
|
||||||
|
string IniFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||||
|
|
||||||
|
IniPath = Path.Combine(IniFolder, "RyujinxUI.conf");
|
||||||
|
|
||||||
|
IniParser Parser = new IniParser(IniPath);
|
||||||
|
|
||||||
|
AOptimizations.DisableMemoryChecks = !Convert.ToBoolean(Parser.GetValue("Enable_Memory_Checks"));
|
||||||
|
|
||||||
|
Log.SetEnable(LogLevel.Debug, Convert.ToBoolean(Parser.GetValue("Logging_Enable_Debug")));
|
||||||
|
Log.SetEnable(LogLevel.Stub, Convert.ToBoolean(Parser.GetValue("Logging_Enable_Stub")));
|
||||||
|
Log.SetEnable(LogLevel.Info, Convert.ToBoolean(Parser.GetValue("Logging_Enable_Info")));
|
||||||
|
Log.SetEnable(LogLevel.Warning, Convert.ToBoolean(Parser.GetValue("Logging_Enable_Warn")));
|
||||||
|
Log.SetEnable(LogLevel.Error, Convert.ToBoolean(Parser.GetValue("Logging_Enable_Error")));
|
||||||
|
|
||||||
|
GamePadEnable = Convert.ToBoolean(Parser.GetValue("GamePad_Enable"));
|
||||||
|
GamePadIndex = Convert.ToInt32 (Parser.GetValue("GamePad_Index"));
|
||||||
|
GamePadDeadzone = (float)Convert.ToDouble (Parser.GetValue("GamePad_Deadzone"), CultureInfo.InvariantCulture);
|
||||||
|
GamePadTriggerThreshold = (float)Convert.ToDouble (Parser.GetValue("GamePad_Trigger_Threshold"), CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
string[] FilteredLogClasses = Parser.GetValue("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)))
|
||||||
|
{
|
||||||
|
Log.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()))
|
||||||
|
{
|
||||||
|
Log.SetEnable(Class, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JoyConKeyboard = new JoyConKeyboard
|
||||||
|
{
|
||||||
|
Left = new JoyConKeyboardLeft
|
||||||
|
{
|
||||||
|
StickUp = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Stick_Up")),
|
||||||
|
StickDown = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Stick_Down")),
|
||||||
|
StickLeft = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Stick_Left")),
|
||||||
|
StickRight = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Stick_Right")),
|
||||||
|
StickButton = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Stick_Button")),
|
||||||
|
DPadUp = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_DPad_Up")),
|
||||||
|
DPadDown = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_DPad_Down")),
|
||||||
|
DPadLeft = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_DPad_Left")),
|
||||||
|
DPadRight = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_DPad_Right")),
|
||||||
|
ButtonMinus = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Button_Minus")),
|
||||||
|
ButtonL = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Button_L")),
|
||||||
|
ButtonZL = Convert.ToInt16(Parser.GetValue("Controls_Left_JoyConKeyboard_Button_ZL"))
|
||||||
|
},
|
||||||
|
|
||||||
|
Right = new JoyConKeyboardRight
|
||||||
|
{
|
||||||
|
StickUp = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Stick_Up")),
|
||||||
|
StickDown = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Stick_Down")),
|
||||||
|
StickLeft = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Stick_Left")),
|
||||||
|
StickRight = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Stick_Right")),
|
||||||
|
StickButton = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Stick_Button")),
|
||||||
|
ButtonA = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_A")),
|
||||||
|
ButtonB = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_B")),
|
||||||
|
ButtonX = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_X")),
|
||||||
|
ButtonY = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_Y")),
|
||||||
|
ButtonPlus = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_Plus")),
|
||||||
|
ButtonR = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_R")),
|
||||||
|
ButtonZR = Convert.ToInt16(Parser.GetValue("Controls_Right_JoyConKeyboard_Button_ZR"))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JoyConController = new JoyConController
|
||||||
|
{
|
||||||
|
Left = new JoyConControllerLeft
|
||||||
|
{
|
||||||
|
Stick = Enum.Parse<GamePadStick>(Parser.GetValue("Controls_Left_JoyConController_Stick")),
|
||||||
|
StickButton = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_Stick_Button")),
|
||||||
|
DPadUp = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_DPad_Up")),
|
||||||
|
DPadDown = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_DPad_Down")),
|
||||||
|
DPadLeft = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_DPad_Left")),
|
||||||
|
DPadRight = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_DPad_Right")),
|
||||||
|
ButtonMinus = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_Button_Minus")),
|
||||||
|
ButtonL = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_Button_L")),
|
||||||
|
ButtonZL = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Left_JoyConController_Button_ZL"))
|
||||||
|
},
|
||||||
|
|
||||||
|
Right = new JoyConControllerRight
|
||||||
|
{
|
||||||
|
Stick = Enum.Parse<GamePadStick>(Parser.GetValue("Controls_Right_JoyConController_Stick")),
|
||||||
|
StickButton = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Stick_Button")),
|
||||||
|
ButtonA = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_A")),
|
||||||
|
ButtonB = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_B")),
|
||||||
|
ButtonX = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_X")),
|
||||||
|
ButtonY = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_Y")),
|
||||||
|
ButtonPlus = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_Plus")),
|
||||||
|
ButtonR = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_R")),
|
||||||
|
ButtonZR = Enum.Parse<GamePadButton>(Parser.GetValue("Controls_Right_JoyConController_Button_ZR"))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DefaultGameDirectory = Parser.GetValue("Default_Game_Directory");
|
||||||
|
|
||||||
|
VirtualFileSystem FS = new HLE.VirtualFileSystem();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(DefaultGameDirectory))
|
||||||
|
{
|
||||||
|
DefaultGameDirectory = Path.Combine(FS.GetSdCardPath(), "switch");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Directory.Exists(DefaultGameDirectory))
|
||||||
|
{
|
||||||
|
if (!Directory.CreateDirectory(DefaultGameDirectory).Exists)
|
||||||
|
{
|
||||||
|
DefaultGameDirectory = Path.Combine(FS.GetSdCardPath(), "switch");
|
||||||
|
Directory.CreateDirectory(DefaultGameDirectory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Save(Logger Log)
|
||||||
|
{
|
||||||
|
IniParser Parser = new IniParser(IniPath);
|
||||||
|
|
||||||
|
Parser.SetValue("Enable_Memory_Checks", (!AOptimizations.DisableMemoryChecks).ToString());
|
||||||
|
|
||||||
|
Parser.SetValue("Logging_Enable_Debug", Log.IsEnabled(LogLevel.Debug).ToString());
|
||||||
|
Parser.SetValue("Logging_Enable_Stub", Log.IsEnabled(LogLevel.Stub).ToString());
|
||||||
|
Parser.SetValue("Logging_Enable_Info", Log.IsEnabled(LogLevel.Info).ToString());
|
||||||
|
Parser.SetValue("Logging_Enable_Warn", Log.IsEnabled(LogLevel.Warning).ToString());
|
||||||
|
Parser.SetValue("Logging_Enable_Error", Log.IsEnabled(LogLevel.Error).ToString());
|
||||||
|
|
||||||
|
|
||||||
|
List<string> FilteredClasses = new List<string>();
|
||||||
|
|
||||||
|
foreach(LogClass LogClass in Enum.GetValues(typeof(LogClass)))
|
||||||
|
{
|
||||||
|
if (Log.IsFiltered(LogClass))
|
||||||
|
FilteredClasses.Add(LogClass.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
Parser.SetValue("Logging_Filtered_Classes", string.Join(',', FilteredClasses));
|
||||||
|
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_Stick_Up", JoyConKeyboard.Left.StickUp.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_Stick_Down", JoyConKeyboard.Left.StickDown.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_Stick_Left", JoyConKeyboard.Left.StickLeft.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_Stick_Right", JoyConKeyboard.Left.StickRight.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_Stick_Button", JoyConKeyboard.Left.StickButton.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_DPad_Up", JoyConKeyboard.Left.DPadUp.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_DPad_Down", JoyConKeyboard.Left.DPadDown.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_DPad_Left", JoyConKeyboard.Left.DPadLeft.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_DPad_Right", JoyConKeyboard.Left.DPadRight.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_Button_Minus", JoyConKeyboard.Left.ButtonMinus.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_Button_L", JoyConKeyboard.Left.ButtonL.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConKeyboard_Button_ZL", JoyConKeyboard.Left.ButtonZL.ToString());
|
||||||
|
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Stick_Up", JoyConKeyboard.Right.StickUp.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Stick_Down", JoyConKeyboard.Right.StickDown.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Stick_Left", JoyConKeyboard.Right.StickLeft.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Stick_Right", JoyConKeyboard.Right.StickRight.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Stick_Button", JoyConKeyboard.Right.StickButton.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_A", JoyConKeyboard.Right.ButtonA.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_B", JoyConKeyboard.Right.ButtonB.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_X", JoyConKeyboard.Right.ButtonX.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_Y", JoyConKeyboard.Right.ButtonY.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_Plus", JoyConKeyboard.Right.ButtonPlus.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_R", JoyConKeyboard.Right.ButtonR.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConKeyboard_Button_ZR", JoyConKeyboard.Right.ButtonZR.ToString());
|
||||||
|
|
||||||
|
Parser.SetValue("Controls_Left_JoyConController_Stick", JoyConController.Left.Stick.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConController_Stick_Button", JoyConController.Left.StickButton.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConController_DPad_Up", JoyConController.Left.DPadUp.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConController_DPad_Down", JoyConController.Left.DPadDown.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConController_DPad_Left", JoyConController.Left.DPadLeft.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConController_DPad_Right", JoyConController.Left.DPadRight.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConController_Button_Minus", JoyConController.Left.ButtonMinus.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConController_Button_L", JoyConController.Left.ButtonL.ToString());
|
||||||
|
Parser.SetValue("Controls_Left_JoyConController_Button_ZL", JoyConController.Left.ButtonZL.ToString());
|
||||||
|
|
||||||
|
Parser.SetValue("Controls_Right_JoyConController_Stick_Up", JoyConController.Right.Stick.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConController_Stick_Button", JoyConController.Right.StickButton.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConController_Button_A", JoyConController.Right.ButtonA.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConController_Button_B", JoyConController.Right.ButtonB.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConController_Button_X", JoyConController.Right.ButtonX.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConController_Button_Y", JoyConController.Right.ButtonY.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConController_Button_Plus", JoyConController.Right.ButtonPlus.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConController_Button_R", JoyConController.Right.ButtonR.ToString());
|
||||||
|
Parser.SetValue("Controls_Right_JoyConController_Button_ZR", JoyConController.Right.ButtonZR.ToString());
|
||||||
|
|
||||||
|
Parser.SetValue("GamePad_Enable", GamePadEnable.ToString());
|
||||||
|
Parser.SetValue("GamePad_Index", GamePadIndex.ToString());
|
||||||
|
Parser.SetValue("GamePad_Deadzone", Convert.ToString(GamePadDeadzone,CultureInfo.InvariantCulture));
|
||||||
|
Parser.SetValue("GamePad_Trigger_Threshold", GamePadTriggerThreshold.ToString());
|
||||||
|
|
||||||
|
Parser.SetValue("Default_Game_Directory", DefaultGameDirectory);
|
||||||
|
|
||||||
|
Parser.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/37772571
|
||||||
|
public class IniParser
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, string> Values;
|
||||||
|
private readonly Dictionary<string, string> Comments;
|
||||||
|
private readonly string Path;
|
||||||
|
|
||||||
|
public IniParser(string Path)
|
||||||
|
{
|
||||||
|
this.Path = Path;
|
||||||
|
string[] Lines = File.ReadAllLines(Path);
|
||||||
|
Values = Lines
|
||||||
|
.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);
|
||||||
|
|
||||||
|
string CurrentComment = string.Empty;
|
||||||
|
Comments = new Dictionary<string, string>();
|
||||||
|
foreach (string Line in Lines)
|
||||||
|
{
|
||||||
|
if (Line.StartsWith("#"))
|
||||||
|
CurrentComment += Line + Environment.NewLine;
|
||||||
|
else if (!string.IsNullOrWhiteSpace(Line))
|
||||||
|
{
|
||||||
|
string key = Line.Split("=", 2).First().Trim();
|
||||||
|
Comments.Add(key, CurrentComment.TrimEnd());
|
||||||
|
CurrentComment = string.Empty;
|
||||||
|
}
|
||||||
|
else CurrentComment = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetValue(string Name)
|
||||||
|
{
|
||||||
|
return Values.TryGetValue(Name, out string Value) ? Value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(string Name, string Value)
|
||||||
|
{
|
||||||
|
lock (Values)
|
||||||
|
if (Values.ContainsKey(Name))
|
||||||
|
{
|
||||||
|
Values[Name] = Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Values.Add(Name, Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Save()
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
List<string> Records = new List<string>();
|
||||||
|
|
||||||
|
foreach (var Record in Values)
|
||||||
|
{
|
||||||
|
if (Comments.ContainsKey(Record.Key))
|
||||||
|
{
|
||||||
|
string Comment = Comments[Record.Key];
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(Comment))
|
||||||
|
{
|
||||||
|
Records.Add(Environment.NewLine);
|
||||||
|
Records.Add(Comments[Record.Key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Records.Add(string.Format("{0} = {1}", Record.Key, Record.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllLines(Path, Records);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
Ryujinx.UI/EmulationController.cs
Normal file
73
Ryujinx.UI/EmulationController.cs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
using Ryujinx.HLE;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI
|
||||||
|
{
|
||||||
|
class EmulationController
|
||||||
|
{
|
||||||
|
public bool IsLoaded = false;
|
||||||
|
|
||||||
|
private Switch Ns;
|
||||||
|
|
||||||
|
public event EventHandler IsShutDown;
|
||||||
|
|
||||||
|
public EmulationController(Switch Ns)
|
||||||
|
{
|
||||||
|
this.Ns = Ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resume()
|
||||||
|
{
|
||||||
|
Ns.Os.ResumeAllProcesses();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Pause()
|
||||||
|
{
|
||||||
|
Ns.Os.PauseAllProcesses();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShutDown()
|
||||||
|
{
|
||||||
|
Ns.Dispose();
|
||||||
|
|
||||||
|
Ns = null;
|
||||||
|
IsLoaded = false;
|
||||||
|
|
||||||
|
IsShutDown.Invoke(null,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Load(string Path)
|
||||||
|
{
|
||||||
|
if (Directory.Exists(Path))
|
||||||
|
{
|
||||||
|
string[] RomFsFiles = Directory.GetFiles(Path, "*.istorage");
|
||||||
|
|
||||||
|
if (RomFsFiles.Length == 0)
|
||||||
|
{
|
||||||
|
RomFsFiles = Directory.GetFiles(Path, "*.romfs");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RomFsFiles.Length > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Loading as cart with RomFS.");
|
||||||
|
|
||||||
|
Ns.LoadCart(Path, RomFsFiles[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Loading as cart WITHOUT RomFS.");
|
||||||
|
|
||||||
|
Ns.LoadCart(Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (File.Exists(Path))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Loading as homebrew.");
|
||||||
|
|
||||||
|
Ns.LoadProgram(Path);
|
||||||
|
}
|
||||||
|
IsLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
Ryujinx.UI/Extensions/ControlArchive.cs
Normal file
54
Ryujinx.UI/Extensions/ControlArchive.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI
|
||||||
|
{
|
||||||
|
public class ControlArchive
|
||||||
|
{
|
||||||
|
public LanguageEntry[] LanguageEntries { get; set; }
|
||||||
|
|
||||||
|
public long ApplicationTitleID { get; set; }
|
||||||
|
public long BaseTitleID { get; set; }
|
||||||
|
public long ProductCode { get; set; }
|
||||||
|
public string ApplicationVersion { get; set; }
|
||||||
|
|
||||||
|
public ControlArchive(Stream Input)
|
||||||
|
{
|
||||||
|
BinaryReader Reader = new BinaryReader(Input);
|
||||||
|
|
||||||
|
byte[] LanguageEntryData = Reader.ReadBytes(0x3000);
|
||||||
|
|
||||||
|
Input.Seek(0x3060, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
ApplicationVersion = Encoding.ASCII.GetString(Reader.ReadBytes(0x10));
|
||||||
|
BaseTitleID = Reader.ReadInt64();
|
||||||
|
ApplicationTitleID = Reader.ReadInt64();
|
||||||
|
|
||||||
|
Input.Seek(0x30a8, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
ProductCode = Reader.ReadInt64();
|
||||||
|
|
||||||
|
LanguageEntries = new LanguageEntry[16];
|
||||||
|
|
||||||
|
using (MemoryStream LanguageStream = new MemoryStream(LanguageEntryData))
|
||||||
|
{
|
||||||
|
BinaryReader LanguageReader = new BinaryReader(LanguageStream);
|
||||||
|
|
||||||
|
for (int Index = 0; Index < 16; Index++)
|
||||||
|
{
|
||||||
|
LanguageEntries[Index] = new LanguageEntry()
|
||||||
|
{
|
||||||
|
AplicationName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x200)).Trim('\0'),
|
||||||
|
DeveloperName = Encoding.ASCII.GetString(LanguageReader.ReadBytes(0x100)).Trim('\0')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct LanguageEntry
|
||||||
|
{
|
||||||
|
public string AplicationName;
|
||||||
|
public string DeveloperName;
|
||||||
|
}
|
||||||
|
}
|
72
Ryujinx.UI/Extensions/Nro.cs
Normal file
72
Ryujinx.UI/Extensions/Nro.cs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI
|
||||||
|
{
|
||||||
|
class Nro : HLE.Loaders.Executables.Nro
|
||||||
|
{
|
||||||
|
public byte[] AssetRomfData { get; set; }
|
||||||
|
public byte[] IconData { get; set; }
|
||||||
|
public int AssetOffset { get; set; }
|
||||||
|
|
||||||
|
public ControlArchive ControlArchive { get; set; }
|
||||||
|
|
||||||
|
private byte[] NACPData { get; set; }
|
||||||
|
|
||||||
|
public Nro(Stream Input, string Name) : base(Input, Name)
|
||||||
|
{
|
||||||
|
BinaryReader Reader = new BinaryReader(Input);
|
||||||
|
|
||||||
|
byte[] Read(long Position, int Size)
|
||||||
|
{
|
||||||
|
Input.Seek(Position, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
return Reader.ReadBytes(Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Input.Length > FileSize)
|
||||||
|
{
|
||||||
|
AssetOffset = FileSize;
|
||||||
|
|
||||||
|
string AssetMagic = Encoding.ASCII.GetString(Read(AssetOffset, 4));
|
||||||
|
|
||||||
|
if (AssetMagic == "ASET")
|
||||||
|
{
|
||||||
|
Input.Seek(AssetOffset, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
int AssetMagic0 = Reader.ReadInt32();
|
||||||
|
int AssetFormat = Reader.ReadInt32();
|
||||||
|
byte[] IconSectionInfo = Reader.ReadBytes(0x10);
|
||||||
|
byte[] NACPSectionInfo = Reader.ReadBytes(0x10);
|
||||||
|
byte[] AssetRomfSectionInfo = Reader.ReadBytes(0x10);
|
||||||
|
|
||||||
|
long IconOffset = BitConverter.ToInt64(IconSectionInfo, 0);
|
||||||
|
long IconSize = BitConverter.ToInt64(IconSectionInfo, 8);
|
||||||
|
long NACPOffset = BitConverter.ToInt64(NACPSectionInfo, 0);
|
||||||
|
long NACPSize = BitConverter.ToInt64(NACPSectionInfo, 8);
|
||||||
|
long RomfOffset = BitConverter.ToInt64(AssetRomfSectionInfo, 0);
|
||||||
|
long RomfSize = BitConverter.ToInt64(AssetRomfSectionInfo, 8);
|
||||||
|
|
||||||
|
Input.Seek(AssetOffset + IconOffset, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
IconData = Reader.ReadBytes((int)IconSize);
|
||||||
|
|
||||||
|
Input.Seek(AssetOffset + NACPOffset, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
NACPData = Reader.ReadBytes((int)NACPSize);
|
||||||
|
|
||||||
|
Input.Seek(AssetOffset + RomfOffset, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
AssetRomfData = Reader.ReadBytes((int)RomfSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NACPData != null)
|
||||||
|
using (MemoryStream NACPStream = new MemoryStream(NACPData))
|
||||||
|
{
|
||||||
|
ControlArchive = new ControlArchive(NACPStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
Ryujinx.UI/GUI/DialogResult.cs
Normal file
8
Ryujinx.UI/GUI/DialogResult.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
public enum DialogResult
|
||||||
|
{
|
||||||
|
OK,
|
||||||
|
Cancel,
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
None
|
||||||
|
}
|
520
Ryujinx.UI/GUI/EmulationWindow.cs
Normal file
520
Ryujinx.UI/GUI/EmulationWindow.cs
Normal file
|
@ -0,0 +1,520 @@
|
||||||
|
using ImGuiNET;
|
||||||
|
using OpenTK;
|
||||||
|
using OpenTK.Input;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using Ryujinx.Audio;
|
||||||
|
using Ryujinx.Audio.OpenAL;
|
||||||
|
using Ryujinx.Graphics.Gal;
|
||||||
|
using Ryujinx.Graphics.Gal.OpenGL;
|
||||||
|
using Ryujinx.HLE;
|
||||||
|
using Ryujinx.HLE.Input;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
using Stopwatch = System.Diagnostics.Stopwatch;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI
|
||||||
|
{
|
||||||
|
partial class EmulationWindow : WindowHelper
|
||||||
|
{
|
||||||
|
public static EmulationController EmulationController;
|
||||||
|
|
||||||
|
//toggles
|
||||||
|
private bool isRunning = false;
|
||||||
|
private bool IsRunning
|
||||||
|
{
|
||||||
|
get => isRunning;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
isRunning = value;
|
||||||
|
UIActive = !value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool showMainUI = true;
|
||||||
|
private bool ShowMainUI
|
||||||
|
{
|
||||||
|
get => showMainUI;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
showMainUI = value;
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
CurrentPage = Page.GameList;
|
||||||
|
UIActive = value;
|
||||||
|
}
|
||||||
|
else if (!ShowPauseUI)
|
||||||
|
UIActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool showPauseUI;
|
||||||
|
private bool ShowPauseUI
|
||||||
|
{
|
||||||
|
get => showPauseUI;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
showPauseUI = value;
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
CurrentPage = Page.Emulation;
|
||||||
|
UIActive = value;
|
||||||
|
}
|
||||||
|
else if (!ShowMainUI)
|
||||||
|
UIActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Page CurrentPage = Page.GameList;
|
||||||
|
|
||||||
|
private bool EscapePressed;
|
||||||
|
private string CurrentPath;
|
||||||
|
private string PackagePath;
|
||||||
|
|
||||||
|
private const int TouchScreenWidth = 1280;
|
||||||
|
private const int TouchScreenHeight = 720;
|
||||||
|
|
||||||
|
private const float TouchScreenRatioX = (float)TouchScreenWidth / TouchScreenHeight;
|
||||||
|
private const float TouchScreenRatioY = (float)TouchScreenHeight / TouchScreenWidth;
|
||||||
|
|
||||||
|
private const int TargetFPS = 60;
|
||||||
|
|
||||||
|
FilePicker FileDialog;
|
||||||
|
|
||||||
|
IGalRenderer Renderer;
|
||||||
|
|
||||||
|
public static Switch Ns;
|
||||||
|
|
||||||
|
private Thread RenderThread;
|
||||||
|
|
||||||
|
private bool ResizeEvent;
|
||||||
|
|
||||||
|
private bool TitleEvent;
|
||||||
|
|
||||||
|
private string NewTitle;
|
||||||
|
|
||||||
|
public EmulationWindow() : base("Ryujinx")
|
||||||
|
{
|
||||||
|
CurrentPath = Environment.CurrentDirectory;
|
||||||
|
PackagePath = string.Empty;
|
||||||
|
FileDialog = FilePicker.GetFilePicker("rom",null);
|
||||||
|
|
||||||
|
InitializeSwitch();
|
||||||
|
|
||||||
|
ResizeEvent = false;
|
||||||
|
|
||||||
|
TitleEvent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnLoad(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnLoad(e);
|
||||||
|
|
||||||
|
VSync = VSyncMode.On;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderLoop()
|
||||||
|
{
|
||||||
|
MakeCurrent();
|
||||||
|
|
||||||
|
PrepareTexture();
|
||||||
|
|
||||||
|
Stopwatch Chrono = new Stopwatch();
|
||||||
|
|
||||||
|
Chrono.Start();
|
||||||
|
|
||||||
|
long TicksPerFrame = Stopwatch.Frequency / TargetFPS;
|
||||||
|
|
||||||
|
long Ticks = 0;
|
||||||
|
|
||||||
|
while (Exists && !IsExiting)
|
||||||
|
{
|
||||||
|
if (Ns.WaitFifo())
|
||||||
|
{
|
||||||
|
Ns.ProcessFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderer.RunActions();
|
||||||
|
|
||||||
|
if (ResizeEvent)
|
||||||
|
{
|
||||||
|
ResizeEvent = false;
|
||||||
|
|
||||||
|
Renderer.FrameBuffer.SetWindowSize(Width, Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ticks += Chrono.ElapsedTicks;
|
||||||
|
|
||||||
|
DeltaTime = (float)Chrono.Elapsed.TotalSeconds;
|
||||||
|
|
||||||
|
Chrono.Restart();
|
||||||
|
|
||||||
|
if (Ticks >= TicksPerFrame)
|
||||||
|
{
|
||||||
|
RenderFrame();
|
||||||
|
|
||||||
|
//Queue max. 1 vsync
|
||||||
|
Ticks = Math.Min(Ticks - TicksPerFrame, TicksPerFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MainLoop()
|
||||||
|
{
|
||||||
|
VSync = VSyncMode.Off;
|
||||||
|
|
||||||
|
Visible = true;
|
||||||
|
|
||||||
|
Renderer.FrameBuffer.SetWindowSize(Width, Height);
|
||||||
|
|
||||||
|
Context.MakeCurrent(null);
|
||||||
|
|
||||||
|
//OpenTK doesn't like sleeps in its thread, to avoid this a renderer thread is created
|
||||||
|
RenderThread = new Thread(RenderLoop);
|
||||||
|
|
||||||
|
RenderThread.Start();
|
||||||
|
|
||||||
|
while (Exists && !IsExiting)
|
||||||
|
{
|
||||||
|
ProcessEvents();
|
||||||
|
|
||||||
|
if (!IsExiting)
|
||||||
|
{
|
||||||
|
UpdateFrame();
|
||||||
|
|
||||||
|
if (TitleEvent)
|
||||||
|
{
|
||||||
|
TitleEvent = false;
|
||||||
|
|
||||||
|
Title = NewTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private new void RenderFrame()
|
||||||
|
{
|
||||||
|
if (UIActive)
|
||||||
|
{
|
||||||
|
StartFrame();
|
||||||
|
|
||||||
|
isRunning = false;
|
||||||
|
|
||||||
|
if (ShowMainUI)
|
||||||
|
{
|
||||||
|
showPauseUI = false;
|
||||||
|
|
||||||
|
RenderMainUI();
|
||||||
|
}
|
||||||
|
else if (ShowPauseUI)
|
||||||
|
{
|
||||||
|
showMainUI = false;
|
||||||
|
|
||||||
|
RenderPauseUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
EndFrame();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Renderer.FrameBuffer.Render();
|
||||||
|
|
||||||
|
Ns.Statistics.RecordSystemFrameTime();
|
||||||
|
|
||||||
|
double HostFps = Ns.Statistics.GetSystemFrameRate();
|
||||||
|
double GameFps = Ns.Statistics.GetGameFrameRate();
|
||||||
|
|
||||||
|
NewTitle = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0}";
|
||||||
|
|
||||||
|
TitleEvent = true;
|
||||||
|
|
||||||
|
SwapBuffers();
|
||||||
|
|
||||||
|
Ns.Os.SignalVsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitializeSwitch()
|
||||||
|
{
|
||||||
|
MainContext.MakeCurrent(WindowInfo);
|
||||||
|
|
||||||
|
Renderer = new OGLRenderer();
|
||||||
|
|
||||||
|
Renderer.FrameBuffer.SetWindowSize(Width, Height);
|
||||||
|
|
||||||
|
IAalOutput AudioOut = new OpenALAudioOut();
|
||||||
|
|
||||||
|
Ns = new Switch(Renderer, AudioOut);
|
||||||
|
|
||||||
|
Config.Read(Ns.Log);
|
||||||
|
|
||||||
|
Ns.Log.Updated += ConsoleLog.PrintLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
private new void UpdateFrame()
|
||||||
|
{
|
||||||
|
KeyboardState Keyboard = this.Keyboard ?? new KeyboardState();
|
||||||
|
|
||||||
|
if (!UIActive)
|
||||||
|
{
|
||||||
|
if (Keyboard[Key.Escape] && !EscapePressed)
|
||||||
|
{
|
||||||
|
EscapePressed = true;
|
||||||
|
|
||||||
|
IsRunning = false;
|
||||||
|
|
||||||
|
EmulationController.Pause();
|
||||||
|
|
||||||
|
if (EmulationController.IsLoaded)
|
||||||
|
ShowPauseUI = true;
|
||||||
|
|
||||||
|
UIActive = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (Keyboard[Key.Escape])
|
||||||
|
EscapePressed = true;
|
||||||
|
else
|
||||||
|
EscapePressed = false;
|
||||||
|
|
||||||
|
HidControllerButtons CurrentButton = 0;
|
||||||
|
HidJoystickPosition LeftJoystick;
|
||||||
|
HidJoystickPosition RightJoystick;
|
||||||
|
|
||||||
|
int LeftJoystickDX = 0;
|
||||||
|
int LeftJoystickDY = 0;
|
||||||
|
int RightJoystickDX = 0;
|
||||||
|
int RightJoystickDY = 0;
|
||||||
|
float AnalogStickDeadzone = Config.GamePadDeadzone;
|
||||||
|
|
||||||
|
//LeftJoystick
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickUp]) LeftJoystickDY = short.MaxValue;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickDown]) LeftJoystickDY = -short.MaxValue;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickLeft]) LeftJoystickDX = -short.MaxValue;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickRight]) LeftJoystickDX = short.MaxValue;
|
||||||
|
|
||||||
|
//LeftButtons
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.StickButton]) CurrentButton |= HidControllerButtons.KEY_LSTICK;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadUp]) CurrentButton |= HidControllerButtons.KEY_DUP;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadDown]) CurrentButton |= HidControllerButtons.KEY_DDOWN;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadLeft]) CurrentButton |= HidControllerButtons.KEY_DLEFT;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.DPadRight]) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.ButtonMinus]) CurrentButton |= HidControllerButtons.KEY_MINUS;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.ButtonL]) CurrentButton |= HidControllerButtons.KEY_L;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Left.ButtonZL]) CurrentButton |= HidControllerButtons.KEY_ZL;
|
||||||
|
|
||||||
|
//RightJoystick
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickUp]) RightJoystickDY = short.MaxValue;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickDown]) RightJoystickDY = -short.MaxValue;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickLeft]) RightJoystickDX = -short.MaxValue;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickRight]) RightJoystickDX = short.MaxValue;
|
||||||
|
|
||||||
|
//RightButtons
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.StickButton]) CurrentButton |= HidControllerButtons.KEY_RSTICK;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonA]) CurrentButton |= HidControllerButtons.KEY_A;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonB]) CurrentButton |= HidControllerButtons.KEY_B;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonX]) CurrentButton |= HidControllerButtons.KEY_X;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonY]) CurrentButton |= HidControllerButtons.KEY_Y;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonPlus]) CurrentButton |= HidControllerButtons.KEY_PLUS;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonR]) CurrentButton |= HidControllerButtons.KEY_R;
|
||||||
|
if (Keyboard[(Key)Config.JoyConKeyboard.Right.ButtonZR]) CurrentButton |= HidControllerButtons.KEY_ZR;
|
||||||
|
|
||||||
|
//Controller Input
|
||||||
|
if (Config.GamePadEnable)
|
||||||
|
{
|
||||||
|
GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex);
|
||||||
|
//LeftButtons
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadUp)) CurrentButton |= HidControllerButtons.KEY_DUP;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadDown)) CurrentButton |= HidControllerButtons.KEY_DDOWN;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadLeft)) CurrentButton |= HidControllerButtons.KEY_DLEFT;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadRight)) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.StickButton)) CurrentButton |= HidControllerButtons.KEY_LSTICK;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonMinus)) CurrentButton |= HidControllerButtons.KEY_MINUS;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonL)) CurrentButton |= HidControllerButtons.KEY_L;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonZL)) CurrentButton |= HidControllerButtons.KEY_ZL;
|
||||||
|
|
||||||
|
//RightButtons
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonA)) CurrentButton |= HidControllerButtons.KEY_A;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonB)) CurrentButton |= HidControllerButtons.KEY_B;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonX)) CurrentButton |= HidControllerButtons.KEY_X;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonY)) CurrentButton |= HidControllerButtons.KEY_Y;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.StickButton)) CurrentButton |= HidControllerButtons.KEY_RSTICK;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonPlus)) CurrentButton |= HidControllerButtons.KEY_PLUS;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonR)) CurrentButton |= HidControllerButtons.KEY_R;
|
||||||
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonZR)) CurrentButton |= HidControllerButtons.KEY_ZR;
|
||||||
|
|
||||||
|
//LeftJoystick
|
||||||
|
if (GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).X >= AnalogStickDeadzone
|
||||||
|
|| GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).X <= -AnalogStickDeadzone)
|
||||||
|
LeftJoystickDX = (int)(GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).X * short.MaxValue);
|
||||||
|
|
||||||
|
if (GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).Y >= AnalogStickDeadzone
|
||||||
|
|| GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).Y <= -AnalogStickDeadzone)
|
||||||
|
LeftJoystickDY = (int)(GetJoystickAxis(GamePad, Config.JoyConController.Left.Stick).Y * short.MaxValue);
|
||||||
|
|
||||||
|
//RightJoystick
|
||||||
|
if (GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).X >= AnalogStickDeadzone
|
||||||
|
|| GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).X <= -AnalogStickDeadzone)
|
||||||
|
RightJoystickDX = (int)(GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).X * short.MaxValue);
|
||||||
|
|
||||||
|
if (GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).Y >= AnalogStickDeadzone
|
||||||
|
|| GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).Y <= -AnalogStickDeadzone)
|
||||||
|
RightJoystickDY = (int)(GetJoystickAxis(GamePad, Config.JoyConController.Right.Stick).Y * short.MaxValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
LeftJoystick = new HidJoystickPosition
|
||||||
|
{
|
||||||
|
DX = LeftJoystickDX,
|
||||||
|
DY = LeftJoystickDY
|
||||||
|
};
|
||||||
|
|
||||||
|
RightJoystick = new HidJoystickPosition
|
||||||
|
{
|
||||||
|
DX = RightJoystickDX,
|
||||||
|
DY = RightJoystickDY
|
||||||
|
};
|
||||||
|
|
||||||
|
bool HasTouch = false;
|
||||||
|
|
||||||
|
//Get screen touch position from left mouse click
|
||||||
|
//OpenTK always captures mouse events, even if out of focus, so check if window is focused.
|
||||||
|
if (Focused && Mouse?.LeftButton == ButtonState.Pressed)
|
||||||
|
{
|
||||||
|
MouseState Mouse = this.Mouse.Value;
|
||||||
|
|
||||||
|
int ScrnWidth = Width;
|
||||||
|
int ScrnHeight = Height;
|
||||||
|
|
||||||
|
if (Width > Height * TouchScreenRatioX)
|
||||||
|
{
|
||||||
|
ScrnWidth = (int)(Height * TouchScreenRatioX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScrnHeight = (int)(Width * TouchScreenRatioY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int StartX = (Width - ScrnWidth) >> 1;
|
||||||
|
int StartY = (Height - ScrnHeight) >> 1;
|
||||||
|
|
||||||
|
int EndX = StartX + ScrnWidth;
|
||||||
|
int EndY = StartY + ScrnHeight;
|
||||||
|
|
||||||
|
if (Mouse.X >= StartX &&
|
||||||
|
Mouse.Y >= StartY &&
|
||||||
|
Mouse.X < EndX &&
|
||||||
|
Mouse.Y < EndY)
|
||||||
|
{
|
||||||
|
int ScrnMouseX = Mouse.X - StartX;
|
||||||
|
int ScrnMouseY = Mouse.Y - StartY;
|
||||||
|
|
||||||
|
int MX = (int)(((float)ScrnMouseX / ScrnWidth) * TouchScreenWidth);
|
||||||
|
int MY = (int)(((float)ScrnMouseY / ScrnHeight) * TouchScreenHeight);
|
||||||
|
|
||||||
|
HidTouchPoint CurrentPoint = new HidTouchPoint
|
||||||
|
{
|
||||||
|
X = MX,
|
||||||
|
Y = MY,
|
||||||
|
|
||||||
|
//Placeholder values till more data is acquired
|
||||||
|
DiameterX = 10,
|
||||||
|
DiameterY = 10,
|
||||||
|
Angle = 90
|
||||||
|
};
|
||||||
|
|
||||||
|
HasTouch = true;
|
||||||
|
|
||||||
|
Ns.Hid.SetTouchPoints(CurrentPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HasTouch)
|
||||||
|
{
|
||||||
|
Ns.Hid.SetTouchPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ns.Hid.SetJoyconButton(
|
||||||
|
HidControllerId.CONTROLLER_HANDHELD,
|
||||||
|
HidControllerLayouts.Handheld_Joined,
|
||||||
|
CurrentButton,
|
||||||
|
LeftJoystick,
|
||||||
|
RightJoystick);
|
||||||
|
|
||||||
|
Ns.Hid.SetJoyconButton(
|
||||||
|
HidControllerId.CONTROLLER_HANDHELD,
|
||||||
|
HidControllerLayouts.Main,
|
||||||
|
CurrentButton,
|
||||||
|
LeftJoystick,
|
||||||
|
RightJoystick);
|
||||||
|
}
|
||||||
|
else if (EmulationController != null)
|
||||||
|
if (EmulationController.IsLoaded)
|
||||||
|
{
|
||||||
|
if (Keyboard[Key.Escape] && !EscapePressed)
|
||||||
|
{
|
||||||
|
EscapePressed = true;
|
||||||
|
|
||||||
|
EmulationController.Resume();
|
||||||
|
|
||||||
|
if (ShowPauseUI & EmulationController.IsLoaded)
|
||||||
|
showPauseUI = false;
|
||||||
|
|
||||||
|
UIActive = false;
|
||||||
|
IsRunning = true;
|
||||||
|
}
|
||||||
|
else if (Keyboard[Key.Escape])
|
||||||
|
EscapePressed = true;
|
||||||
|
else
|
||||||
|
EscapePressed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnUnload(EventArgs e)
|
||||||
|
{
|
||||||
|
RenderThread.Join();
|
||||||
|
|
||||||
|
base.OnUnload(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnResize(EventArgs e)
|
||||||
|
{
|
||||||
|
ResizeEvent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadPackage(string path)
|
||||||
|
{
|
||||||
|
|
||||||
|
MainContext.MakeCurrent(WindowInfo);
|
||||||
|
|
||||||
|
if (Ns == null)
|
||||||
|
InitializeSwitch();
|
||||||
|
|
||||||
|
if (EmulationController == null)
|
||||||
|
EmulationController = new EmulationController(Ns);
|
||||||
|
|
||||||
|
EmulationController.IsShutDown += EmulationController_IsShutDown;
|
||||||
|
|
||||||
|
EmulationController.Load(path);
|
||||||
|
|
||||||
|
IsRunning = true;
|
||||||
|
|
||||||
|
ShowMainUI = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EmulationController_IsShutDown(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
EmulationController = null;
|
||||||
|
|
||||||
|
Ns = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Page
|
||||||
|
{
|
||||||
|
Configuration,
|
||||||
|
Emulation,
|
||||||
|
GameList,
|
||||||
|
PackageLoader
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
22
Ryujinx.UI/GUI/Values.cs
Normal file
22
Ryujinx.UI/GUI/Values.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ImGuiNET
|
||||||
|
{
|
||||||
|
public struct Values
|
||||||
|
{
|
||||||
|
public const float ButtonWidth = 170f;
|
||||||
|
public const float ButtonHeight = 50f;
|
||||||
|
public const float DefaultWindowScale = 1.0f;
|
||||||
|
public const float SelectibleHeight = 20.0f;
|
||||||
|
public static float CurrentWindowScale = 1.0f;
|
||||||
|
public static float CurrentFontScale = 1.2f;
|
||||||
|
|
||||||
|
public struct Color
|
||||||
|
{
|
||||||
|
public static Vector4 Yellow = new Vector4(1.0f, 1.0f, 0, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
168
Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs
Normal file
168
Ryujinx.UI/GUI/Widgets/ConfigurationWidget.cs
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
using ImGuiNET;
|
||||||
|
using Ryujinx.Common.Input;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI.Widgets
|
||||||
|
{
|
||||||
|
public partial class ConfigurationWidget
|
||||||
|
{
|
||||||
|
static bool ConfigIntialized = false;
|
||||||
|
static bool OpenFolderPicker;
|
||||||
|
static string CurrentPath;
|
||||||
|
static float CurrentGamePadDeadzone;
|
||||||
|
static bool CurrentGamePadEnable;
|
||||||
|
static int CurrentGamePadIndex;
|
||||||
|
static float CurrentGamePadTriggerThreshold;
|
||||||
|
|
||||||
|
static IniParser IniParser;
|
||||||
|
static FilePicker FolderPicker;
|
||||||
|
static JoyConKeyboard KeyboardInputLayout;
|
||||||
|
static JoyConController ControllerInputLayout;
|
||||||
|
static Page CurrentPage = Page.General;
|
||||||
|
|
||||||
|
static ConfigurationWidget()
|
||||||
|
{
|
||||||
|
IniParser = new IniParser(Config.IniPath);
|
||||||
|
FolderPicker = FilePicker.GetFilePicker("FolderDialog",Config.DefaultGameDirectory);
|
||||||
|
CurrentPath = Config.DefaultGameDirectory.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Reset()
|
||||||
|
{
|
||||||
|
KeyboardInputLayout = Config.JoyConKeyboard;
|
||||||
|
ControllerInputLayout = Config.JoyConController;
|
||||||
|
CurrentGamePadTriggerThreshold = Config.GamePadTriggerThreshold;
|
||||||
|
CurrentGamePadIndex = Config.GamePadIndex;
|
||||||
|
CurrentGamePadEnable = Config.GamePadEnable;
|
||||||
|
CurrentGamePadDeadzone = Config.GamePadDeadzone;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Apply()
|
||||||
|
{
|
||||||
|
Config.JoyConKeyboard = KeyboardInputLayout;
|
||||||
|
Config.JoyConController = ControllerInputLayout;
|
||||||
|
Config.GamePadDeadzone = CurrentGamePadDeadzone;
|
||||||
|
Config.GamePadEnable = CurrentGamePadEnable;
|
||||||
|
Config.GamePadIndex = CurrentGamePadIndex;
|
||||||
|
Config.GamePadTriggerThreshold = CurrentGamePadTriggerThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Draw()
|
||||||
|
{
|
||||||
|
if(!ConfigIntialized)
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
|
||||||
|
ConfigIntialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginChildFrame(2, ImGui.GetContentRegionAvailable()
|
||||||
|
- new Vector2(0,Values.ButtonHeight), WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
ImGuiNative.igBeginGroup();
|
||||||
|
|
||||||
|
if(ImGui.Button("General",new Vector2(Values.ButtonWidth,Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
CurrentPage = Page.General;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGui.Button("Input", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
CurrentPage = Page.Input;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiNative.igEndGroup();
|
||||||
|
|
||||||
|
if (ImGui.BeginChildFrame(3, ImGui.GetContentRegionAvailable(), WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
switch (CurrentPage)
|
||||||
|
{
|
||||||
|
case Page.General:
|
||||||
|
if (ImGui.BeginChild("generalFrame", true, WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
ImGui.Text("General Emulation Settings");
|
||||||
|
ImGui.Spacing();
|
||||||
|
ImGui.LabelText("", "Default Game Directory");
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGui.Selectable(Config.DefaultGameDirectory))
|
||||||
|
{
|
||||||
|
OpenFolderPicker = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OpenFolderPicker)
|
||||||
|
ImGui.OpenPopup("Open Folder");
|
||||||
|
|
||||||
|
DialogResult DialogResult = FolderPicker.GetFolder(ref CurrentPath);
|
||||||
|
if (DialogResult == DialogResult.OK)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(CurrentPath))
|
||||||
|
{
|
||||||
|
Config.DefaultGameDirectory = CurrentPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DialogResult != DialogResult.None)
|
||||||
|
{
|
||||||
|
OpenFolderPicker = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
ImGui.Checkbox("Disable Cpu Memory Checks", ref AOptimizations.DisableMemoryChecks);
|
||||||
|
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Page.Input:
|
||||||
|
if (ImGui.BeginChild("inputFrame", true, WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
DrawInputPage();
|
||||||
|
|
||||||
|
ImGui.EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndChildFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndChildFrame();
|
||||||
|
|
||||||
|
if (CurrentPage == Page.Input)
|
||||||
|
{
|
||||||
|
if (ImGui.Button("Apply", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
Apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Button("Save", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
Apply();
|
||||||
|
|
||||||
|
Config.Save(EmulationWindow.Ns.Log);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGui.Button("Discard", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
IniParser = new IniParser(Config.IniPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Page
|
||||||
|
{
|
||||||
|
General,
|
||||||
|
Input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
218
Ryujinx.UI/GUI/Widgets/FilePicker.cs
Normal file
218
Ryujinx.UI/GUI/Widgets/FilePicker.cs
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ImGuiNET
|
||||||
|
{
|
||||||
|
// Adapted from Mellinoe's file picker for imgui
|
||||||
|
// https://github.com/mellinoe/synthapp/blob/master/src/synthapp/Widgets/FilePicker.cs
|
||||||
|
public class FilePicker
|
||||||
|
{
|
||||||
|
private const string FilePickerID = "###FilePicker";
|
||||||
|
|
||||||
|
private static readonly Dictionary<object, FilePicker> FilePickers = new Dictionary<object, FilePicker>();
|
||||||
|
|
||||||
|
private static readonly Vector2 DefaultFilePickerSize = new Vector2(600, 400);
|
||||||
|
|
||||||
|
public string CurrentFolder { get; set; }
|
||||||
|
public string SelectedEntry { get; set; }
|
||||||
|
public string CurrentDrive { get; set; }
|
||||||
|
|
||||||
|
public static FilePicker GetFilePicker(object Id, string StartingPath)
|
||||||
|
{
|
||||||
|
if (File.Exists(StartingPath))
|
||||||
|
{
|
||||||
|
StartingPath = new FileInfo(StartingPath).DirectoryName;
|
||||||
|
}
|
||||||
|
else if (string.IsNullOrEmpty(StartingPath) || !Directory.Exists(StartingPath))
|
||||||
|
{
|
||||||
|
StartingPath = Environment.CurrentDirectory;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(StartingPath))
|
||||||
|
{
|
||||||
|
StartingPath = AppContext.BaseDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FilePickers.TryGetValue(Id, out FilePicker FilePicker))
|
||||||
|
{
|
||||||
|
FilePicker = new FilePicker
|
||||||
|
{
|
||||||
|
CurrentFolder = StartingPath
|
||||||
|
};
|
||||||
|
|
||||||
|
FilePickers.Add(Id, FilePicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FilePicker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DialogResult Draw(ref string SelectedPath, bool ReturnOnSelection, bool FoldersOnly = false)
|
||||||
|
{
|
||||||
|
return DrawFolder(ref SelectedPath, ReturnOnSelection, FoldersOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DialogResult DrawFolder(ref string SelectedPath, bool ReturnOnSelection = false, bool FoldersOnly = false)
|
||||||
|
{
|
||||||
|
ImGui.Text("Current Folder: " + CurrentFolder);
|
||||||
|
|
||||||
|
if(ImGui.BeginChildFrame(0,new Vector2(ImGui.GetContentRegionAvailableWidth()/3,
|
||||||
|
ImGui.GetContentRegionAvailable().Y - Values.ButtonHeight - 10), WindowFlags.Default))
|
||||||
|
{
|
||||||
|
DriveInfo[] DriveList = DriveInfo.GetDrives();
|
||||||
|
|
||||||
|
foreach(DriveInfo Drive in DriveList)
|
||||||
|
{
|
||||||
|
bool IsSelected = CurrentDrive == Drive.Name;
|
||||||
|
|
||||||
|
ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow);
|
||||||
|
|
||||||
|
if (ImGui.Selectable(Drive.Name + "/", IsSelected, SelectableFlags.DontClosePopups
|
||||||
|
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
|
||||||
|
{
|
||||||
|
CurrentDrive = Drive.Name;
|
||||||
|
CurrentFolder = Drive.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndChildFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable() - new Vector2(20, Values.ButtonHeight + 10),
|
||||||
|
WindowFlags.Default))
|
||||||
|
{
|
||||||
|
DirectoryInfo CurrentDirectory = new DirectoryInfo(CurrentFolder);
|
||||||
|
if (CurrentDirectory.Exists)
|
||||||
|
{
|
||||||
|
if (CurrentDirectory.Parent != null)
|
||||||
|
{
|
||||||
|
ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow);
|
||||||
|
|
||||||
|
if (ImGui.Selectable("../", false, SelectableFlags.DontClosePopups
|
||||||
|
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
|
||||||
|
{
|
||||||
|
CurrentFolder = CurrentDirectory.Parent.FullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string Dir in Directory.EnumerateFileSystemEntries(CurrentDirectory.FullName))
|
||||||
|
{
|
||||||
|
if (Directory.Exists(Dir))
|
||||||
|
{
|
||||||
|
string Name = Path.GetFileName(Dir);
|
||||||
|
bool IsSelected = SelectedEntry == Dir;
|
||||||
|
|
||||||
|
ImGui.PushStyleColor(ColorTarget.Text, Values.Color.Yellow);
|
||||||
|
|
||||||
|
if (ImGui.Selectable(Name + "/", IsSelected, SelectableFlags.DontClosePopups
|
||||||
|
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
|
||||||
|
{
|
||||||
|
SelectedEntry = Dir;
|
||||||
|
SelectedPath = SelectedEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedEntry != null)
|
||||||
|
if (ImGui.IsMouseDoubleClicked(0) && SelectedEntry.Equals(Dir))
|
||||||
|
{
|
||||||
|
SelectedEntry = null;
|
||||||
|
SelectedPath = null;
|
||||||
|
CurrentFolder = Dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FoldersOnly)
|
||||||
|
foreach (string File in Directory.EnumerateFiles(CurrentDirectory.FullName))
|
||||||
|
{
|
||||||
|
string Name = Path.GetFileName(File);
|
||||||
|
bool IsSelected = SelectedEntry == File;
|
||||||
|
|
||||||
|
if (ImGui.Selectable(Name, IsSelected, SelectableFlags.DontClosePopups
|
||||||
|
, new Vector2(ImGui.GetContentRegionAvailableWidth(), Values.SelectibleHeight)))
|
||||||
|
{
|
||||||
|
SelectedEntry = File;
|
||||||
|
if (ReturnOnSelection)
|
||||||
|
{
|
||||||
|
SelectedPath = SelectedEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedEntry != null)
|
||||||
|
if (ImGui.IsMouseDoubleClicked(0) && SelectedEntry.Equals(File))
|
||||||
|
{
|
||||||
|
SelectedPath = File;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndChildFrame();
|
||||||
|
|
||||||
|
if (ImGui.Button("Cancel", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
return DialogResult.Cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectedEntry != null)
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("Open", new Vector2(Values.ButtonWidth, Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
SelectedPath = SelectedEntry;
|
||||||
|
|
||||||
|
return DialogResult.OK;
|
||||||
|
}
|
||||||
|
else if (ReturnOnSelection)
|
||||||
|
{
|
||||||
|
SelectedPath = SelectedEntry;
|
||||||
|
|
||||||
|
return DialogResult.OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DialogResult.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DialogResult GetFolder(ref string CurrentPath)
|
||||||
|
{
|
||||||
|
ImGui.SetNextWindowSize(new Vector2(600, 600), Condition.FirstUseEver);
|
||||||
|
|
||||||
|
if (ImGui.BeginPopupModal("Open Folder", WindowFlags.NoResize))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string Output = CurrentPath;
|
||||||
|
|
||||||
|
DialogResult DialogResult = Draw(ref Output, false, true);
|
||||||
|
|
||||||
|
if (DialogResult == DialogResult.OK)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Output))
|
||||||
|
{
|
||||||
|
return DialogResult.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DialogResult != DialogResult.None)
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
|
||||||
|
return DialogResult;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DialogResult.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
201
Ryujinx.UI/GUI/Widgets/GameList.cs
Normal file
201
Ryujinx.UI/GUI/Widgets/GameList.cs
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
using ImGuiNET;
|
||||||
|
using NanoJpeg;
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI.Widgets
|
||||||
|
{
|
||||||
|
class GameList
|
||||||
|
{
|
||||||
|
static bool OpenFolderPicker;
|
||||||
|
static string GameDirectory;
|
||||||
|
static List<GameItem> GameItems;
|
||||||
|
static GameItem SelectedGame;
|
||||||
|
static FilePicker FolderPicker;
|
||||||
|
|
||||||
|
static GameList()
|
||||||
|
{
|
||||||
|
GameDirectory = Config.DefaultGameDirectory;
|
||||||
|
FolderPicker = FilePicker.GetFilePicker("FolderDialog", Config.DefaultGameDirectory);
|
||||||
|
|
||||||
|
Refresh(GameDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe static void Refresh(string Path)
|
||||||
|
{
|
||||||
|
GameItems = new List<GameItem>();
|
||||||
|
|
||||||
|
foreach (string entry in Directory.EnumerateFileSystemEntries(Path))
|
||||||
|
{
|
||||||
|
if (File.Exists(entry))
|
||||||
|
{
|
||||||
|
string Extension = System.IO.Path.GetExtension(entry).ToLower();
|
||||||
|
|
||||||
|
if (Extension == ".nro" || Extension == ".nso")
|
||||||
|
{
|
||||||
|
GameItem GameItem = new GameItem(entry);
|
||||||
|
|
||||||
|
if (GameItem.IsNro && GameItem.HasIcon)
|
||||||
|
{
|
||||||
|
GameItem.TextureID = GL.GenTexture();
|
||||||
|
|
||||||
|
GL.BindTexture(TextureTarget.Texture2D, GameItem.TextureID);
|
||||||
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
|
||||||
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
|
||||||
|
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
|
||||||
|
|
||||||
|
NJImage Image = new NJImage();
|
||||||
|
|
||||||
|
Image.Decode(GameItem.GetIconData());
|
||||||
|
|
||||||
|
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, Image.Width, Image.Height, 0, PixelFormat.Rgb,
|
||||||
|
PixelType.UnsignedByte, new IntPtr(Image.Image));
|
||||||
|
|
||||||
|
Image.Dispose();
|
||||||
|
|
||||||
|
GL.BindTexture(TextureTarget.Texture2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameItems.Add(GameItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe static (bool,string) DrawList()
|
||||||
|
{
|
||||||
|
uint Id = 100;
|
||||||
|
|
||||||
|
if (ImGui.Button("Refresh GameList"))
|
||||||
|
Refresh(Config.DefaultGameDirectory);
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if(ImGui.Button("Select Game Directory"))
|
||||||
|
{
|
||||||
|
OpenFolderPicker = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OpenFolderPicker)
|
||||||
|
ImGui.OpenPopup("Open Folder");
|
||||||
|
|
||||||
|
DialogResult DialogResult = FolderPicker.GetFolder(ref GameDirectory);
|
||||||
|
|
||||||
|
if (DialogResult == DialogResult.OK)
|
||||||
|
{
|
||||||
|
Config.DefaultGameDirectory = GameDirectory;
|
||||||
|
Refresh(GameDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DialogResult != DialogResult.None)
|
||||||
|
OpenFolderPicker = false;
|
||||||
|
|
||||||
|
if (ImGui.BeginChildFrame(20, ImGui.GetContentRegionAvailable(), WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
foreach (GameItem GameItem in GameItems)
|
||||||
|
{
|
||||||
|
Id++;
|
||||||
|
|
||||||
|
if (GameItem == SelectedGame)
|
||||||
|
ImGui.PushStyleColor(ColorTarget.FrameBg, Values.Color.Yellow);
|
||||||
|
|
||||||
|
if (ImGui.BeginChildFrame(Id, new Vector2(ImGui.GetContentRegionAvailableWidth(), 60)
|
||||||
|
, WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
if (GameItem.IsNro && GameItem.HasIcon)
|
||||||
|
{
|
||||||
|
ImGui.Image(new IntPtr(GameItem.TextureID), new Vector2(50, 50), new Vector2(0, 0),
|
||||||
|
new Vector2(1, 1), new Vector4(255, 255, 255, 255), new Vector4(0, 0, 0, 255));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.BeginChildFrame(Id + 500, new Vector2(50, 50), WindowFlags.NoResize);
|
||||||
|
ImGui.EndChildFrame();
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(Path.GetFileName(GameItem.Path));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
ImGuiNative.igBeginGroup();
|
||||||
|
|
||||||
|
if (GameItem.IsNro)
|
||||||
|
{
|
||||||
|
if (GameItem.Nro.ControlArchive != null)
|
||||||
|
{
|
||||||
|
ImGui.Text(GameItem.Nro.ControlArchive.LanguageEntries[0].AplicationName);
|
||||||
|
ImGui.Text(GameItem.Nro.ControlArchive.LanguageEntries[0].DeveloperName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiNative.igEndGroup();
|
||||||
|
|
||||||
|
if (GameItem == SelectedGame)
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
|
||||||
|
if (ImGui.IsMouseDoubleClicked(0) && ImGui.IsItemHovered(HoveredFlags.AllowWhenOverlapped) && GameItem == SelectedGame)
|
||||||
|
{
|
||||||
|
return (true, GameItem.Path);
|
||||||
|
}
|
||||||
|
else if (ImGui.IsMouseClicked(0) && ImGui.IsItemHovered(HoveredFlags.AllowWhenOverlapped | HoveredFlags.RootAndChildWindows))
|
||||||
|
{
|
||||||
|
SelectedGame = GameItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndChildFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndChildFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (false, string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GameItem
|
||||||
|
{
|
||||||
|
public AppletType AppletType { get; set; }
|
||||||
|
public Nro Nro { get; set; }
|
||||||
|
public string Path { get; set; }
|
||||||
|
public int TextureID { get; set; }
|
||||||
|
|
||||||
|
public bool IsNro => (System.IO.Path.GetExtension(Path) == ".nro");
|
||||||
|
public bool HasIcon => Nro?.IconData != null;
|
||||||
|
|
||||||
|
public GameItem(string Path)
|
||||||
|
{
|
||||||
|
this.Path = Path;
|
||||||
|
|
||||||
|
if (File.Exists(Path))
|
||||||
|
{
|
||||||
|
AppletType = AppletType.Homebrew;
|
||||||
|
|
||||||
|
FileInfo Package = new FileInfo(Path);
|
||||||
|
|
||||||
|
if (Package.Extension.ToLower() == ".nro")
|
||||||
|
{
|
||||||
|
Nro = new Nro(File.Open(Path, FileMode.Open), new FileInfo(Path).Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
AppletType = AppletType.Cartridge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetIconData()
|
||||||
|
{
|
||||||
|
return IsNro ? Nro.IconData : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AppletType
|
||||||
|
{
|
||||||
|
Homebrew,
|
||||||
|
Cartridge
|
||||||
|
}
|
||||||
|
}
|
117
Ryujinx.UI/GUI/Widgets/HomeUI.cs
Normal file
117
Ryujinx.UI/GUI/Widgets/HomeUI.cs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
using ImGuiNET;
|
||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI
|
||||||
|
{
|
||||||
|
partial class EmulationWindow
|
||||||
|
{
|
||||||
|
void RenderMainUI()
|
||||||
|
{
|
||||||
|
ImGui.SetNextWindowPos(Vector2.Zero, Condition.Always,
|
||||||
|
Vector2.Zero);
|
||||||
|
|
||||||
|
ImGui.SetNextWindowSize(new Vector2(Width, Height), Condition.Always);
|
||||||
|
|
||||||
|
if (ImGui.BeginWindow("MainWindow", ref showMainUI, WindowFlags.NoTitleBar
|
||||||
|
| WindowFlags.NoMove | WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
if (ImGui.BeginChildFrame(0, new Vector2(-1, -1),
|
||||||
|
WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
ImGuiNative.igBeginGroup();
|
||||||
|
|
||||||
|
if (ImGui.Button("Load Package", new Vector2(Values.ButtonWidth,
|
||||||
|
Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
CurrentPage = Page.PackageLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Button("Game List", new Vector2(Values.ButtonWidth,
|
||||||
|
Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
CurrentPage = Page.GameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Button("Settings", new Vector2(Values.ButtonWidth,
|
||||||
|
Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
CurrentPage = Page.Configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawQuitButton();
|
||||||
|
|
||||||
|
ImGuiNative.igEndGroup();
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable(),
|
||||||
|
WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
switch (CurrentPage)
|
||||||
|
{
|
||||||
|
case Page.PackageLoader:
|
||||||
|
string output = CurrentPath;
|
||||||
|
|
||||||
|
if (FileDialog.Draw(ref output, false) == DialogResult.OK)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(output))
|
||||||
|
{
|
||||||
|
PackagePath = output;
|
||||||
|
|
||||||
|
LoadPackage(PackagePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Page.Configuration:
|
||||||
|
Widgets.ConfigurationWidget.Draw();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Page.GameList:
|
||||||
|
var SelectedPath = Widgets.GameList.DrawList();
|
||||||
|
|
||||||
|
if (SelectedPath.Item1)
|
||||||
|
{
|
||||||
|
LoadPackage(SelectedPath.Item2);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndChildFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndChildFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawQuitButton()
|
||||||
|
{
|
||||||
|
if (ImGui.Button("Quit Ryujinx", new Vector2(Values.ButtonWidth,
|
||||||
|
Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
ImGui.OpenPopup("Quit");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginPopupModal("Quit"))
|
||||||
|
{
|
||||||
|
ImGui.Text("Do you want to quit Ryujinx and return to desktop?");
|
||||||
|
|
||||||
|
if (ImGui.Button("Yes"))
|
||||||
|
{
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Button("No"))
|
||||||
|
{
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1210
Ryujinx.UI/GUI/Widgets/InputPage.cs
Normal file
1210
Ryujinx.UI/GUI/Widgets/InputPage.cs
Normal file
File diff suppressed because it is too large
Load diff
1008
Ryujinx.UI/GUI/Widgets/NanoJpeg.cs
Normal file
1008
Ryujinx.UI/GUI/Widgets/NanoJpeg.cs
Normal file
File diff suppressed because it is too large
Load diff
80
Ryujinx.UI/GUI/Widgets/PauseUI.cs
Normal file
80
Ryujinx.UI/GUI/Widgets/PauseUI.cs
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
using ImGuiNET;
|
||||||
|
namespace Ryujinx.UI
|
||||||
|
{
|
||||||
|
partial class EmulationWindow
|
||||||
|
{
|
||||||
|
void RenderPauseUI()
|
||||||
|
{
|
||||||
|
ImGui.SetNextWindowPos(System.Numerics.Vector2.Zero, Condition.Always,
|
||||||
|
System.Numerics.Vector2.Zero);
|
||||||
|
|
||||||
|
ImGui.SetNextWindowSize(new System.Numerics.Vector2(Width, Height), Condition.Always);
|
||||||
|
|
||||||
|
if (ImGui.BeginWindow("PauseWindow", ref showMainUI, WindowFlags.NoTitleBar
|
||||||
|
| WindowFlags.NoMove | WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
if (ImGui.BeginChildFrame(0, new System.Numerics.Vector2(-1, -1),
|
||||||
|
WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
ImGuiNative.igBeginGroup();
|
||||||
|
|
||||||
|
if (ImGui.Button("Emulation", new System.Numerics.Vector2(Values.ButtonWidth,
|
||||||
|
Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
CurrentPage = Page.Emulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Button("Settings", new System.Numerics.Vector2(Values.ButtonWidth,
|
||||||
|
Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
CurrentPage = Page.Configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawQuitButton();
|
||||||
|
|
||||||
|
ImGuiNative.igEndGroup();
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (ImGui.BeginChildFrame(1, ImGui.GetContentRegionAvailable(),
|
||||||
|
WindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
switch (CurrentPage)
|
||||||
|
{
|
||||||
|
case Page.Emulation:
|
||||||
|
if (ImGui.Button("Resume", new System.Numerics.Vector2(Values.ButtonWidth,
|
||||||
|
Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
ShowPauseUI = false;
|
||||||
|
|
||||||
|
EmulationController.Resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Button("Stop", new System.Numerics.Vector2(Values.ButtonWidth,
|
||||||
|
Values.ButtonHeight)))
|
||||||
|
{
|
||||||
|
ShowPauseUI = false;
|
||||||
|
|
||||||
|
EmulationController.ShutDown();
|
||||||
|
|
||||||
|
ShowMainUI = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Page.Configuration:
|
||||||
|
Widgets.ConfigurationWidget.Draw();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndChildFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndChildFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
384
Ryujinx.UI/GUI/WindowHelper.cs
Normal file
384
Ryujinx.UI/GUI/WindowHelper.cs
Normal file
|
@ -0,0 +1,384 @@
|
||||||
|
using ImGuiNET;
|
||||||
|
using OpenTK;
|
||||||
|
using OpenTK.Graphics;
|
||||||
|
using OpenTK.Graphics.OpenGL;
|
||||||
|
using OpenTK.Input;
|
||||||
|
using System;
|
||||||
|
using Ryujinx.Common.Input;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI
|
||||||
|
{
|
||||||
|
class WindowHelper : GameWindow
|
||||||
|
{
|
||||||
|
protected float DeltaTime;
|
||||||
|
protected bool UIActive;
|
||||||
|
|
||||||
|
protected GraphicsContext MainContext;
|
||||||
|
protected GraphicsContext UIContext;
|
||||||
|
|
||||||
|
private bool IsWindowOpened;
|
||||||
|
private int FontTexture;
|
||||||
|
private float WheelPosition;
|
||||||
|
|
||||||
|
protected KeyboardState? Keyboard = null;
|
||||||
|
|
||||||
|
protected MouseState? Mouse = null;
|
||||||
|
|
||||||
|
protected GamePadState? GamePad = null;
|
||||||
|
|
||||||
|
public WindowHelper(string Title) : base(1280, 720, GraphicsMode.Default, Title, GameWindowFlags.Default
|
||||||
|
, DisplayDevice.Default, 3, 3, GraphicsContextFlags.ForwardCompatible)
|
||||||
|
{
|
||||||
|
base.Title = Title;
|
||||||
|
|
||||||
|
IsWindowOpened = true;
|
||||||
|
|
||||||
|
Location = new Point(
|
||||||
|
(DisplayDevice.Default.Width / 2) - (Width / 2),
|
||||||
|
(DisplayDevice.Default.Height / 2) - (Height / 2));
|
||||||
|
|
||||||
|
MainContext = new GraphicsContext(GraphicsMode.Default,
|
||||||
|
WindowInfo, 3, 3, GraphicsContextFlags.ForwardCompatible);
|
||||||
|
|
||||||
|
UIContext = new GraphicsContext(GraphicsMode.Default,
|
||||||
|
WindowInfo, 3, 3, GraphicsContextFlags.ForwardCompatible);
|
||||||
|
|
||||||
|
UIContext.MakeCurrent(WindowInfo);
|
||||||
|
|
||||||
|
UIActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartFrame()
|
||||||
|
{
|
||||||
|
UIContext.MakeCurrent(WindowInfo);
|
||||||
|
|
||||||
|
IO IO = ImGui.GetIO();
|
||||||
|
|
||||||
|
IO.DisplaySize = new System.Numerics.Vector2(Width, Height);
|
||||||
|
IO.DisplayFramebufferScale = new System.Numerics.Vector2(Values.CurrentWindowScale);
|
||||||
|
IO.DeltaTime = DeltaTime;
|
||||||
|
|
||||||
|
ImGui.NewFrame();
|
||||||
|
|
||||||
|
HandleInput(IO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void EndFrame()
|
||||||
|
{
|
||||||
|
ImGui.Render();
|
||||||
|
|
||||||
|
DrawData* data = ImGui.GetDrawData();
|
||||||
|
|
||||||
|
RenderImDrawData(data);
|
||||||
|
|
||||||
|
MainContext?.MakeCurrent(WindowInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected unsafe void PrepareTexture()
|
||||||
|
{
|
||||||
|
ImGui.GetIO().FontAtlas.AddDefaultFont();
|
||||||
|
|
||||||
|
IO IO = ImGui.GetIO();
|
||||||
|
|
||||||
|
// Build texture atlas
|
||||||
|
FontTextureData texData = IO.FontAtlas.GetTexDataAsAlpha8();
|
||||||
|
|
||||||
|
// Create OpenGL texture
|
||||||
|
FontTexture = GL.GenTexture();
|
||||||
|
|
||||||
|
GL.BindTexture(TextureTarget.Texture2D, FontTexture);
|
||||||
|
|
||||||
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
|
||||||
|
|
||||||
|
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
|
||||||
|
|
||||||
|
GL.TexImage2D(
|
||||||
|
TextureTarget.Texture2D,
|
||||||
|
0,
|
||||||
|
PixelInternalFormat.Alpha,
|
||||||
|
texData.Width,
|
||||||
|
texData.Height,
|
||||||
|
0,
|
||||||
|
PixelFormat.Alpha,
|
||||||
|
PixelType.UnsignedByte,
|
||||||
|
new IntPtr(texData.Pixels));
|
||||||
|
|
||||||
|
// Store the texture identifier in the ImFontAtlas substructure.
|
||||||
|
IO.FontAtlas.SetTexID(FontTexture);
|
||||||
|
|
||||||
|
IO.FontAtlas.ClearTexData();
|
||||||
|
|
||||||
|
GL.BindTexture(TextureTarget.Texture2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe void HandleInput(IO IO)
|
||||||
|
{
|
||||||
|
KeyboardState KeyboardState = default(KeyboardState);
|
||||||
|
|
||||||
|
if (Keyboard != null)
|
||||||
|
if (Keyboard.HasValue)
|
||||||
|
KeyboardState = Keyboard.Value;
|
||||||
|
|
||||||
|
MouseState MouseState = default(MouseState);
|
||||||
|
|
||||||
|
if (Mouse != null)
|
||||||
|
if (Mouse.HasValue)
|
||||||
|
MouseState = Mouse.Value;
|
||||||
|
|
||||||
|
if (Focused)
|
||||||
|
{
|
||||||
|
if (Mouse.HasValue)
|
||||||
|
{
|
||||||
|
Point WindowPoint = new Point(MouseState.X, MouseState.Y);
|
||||||
|
|
||||||
|
IO.MousePosition = new System.Numerics.Vector2(WindowPoint.X,
|
||||||
|
WindowPoint.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.Keyboard.HasValue)
|
||||||
|
foreach (Key Key in Enum.GetValues(typeof(Key)))
|
||||||
|
{
|
||||||
|
IO.KeysDown[(int)Key] = KeyboardState[Key];
|
||||||
|
|
||||||
|
if (KeyboardState[Key])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ImGuiNative.igGetIO()->KeyAlt = (byte)((KeyboardState[Key.AltLeft]
|
||||||
|
|| KeyboardState[Key.AltRight]) ? 1 : 0);
|
||||||
|
|
||||||
|
ImGuiNative.igGetIO()->KeyCtrl = (byte)((KeyboardState[Key.ControlLeft]
|
||||||
|
|| KeyboardState[Key.ControlRight]) ? 1 : 0);
|
||||||
|
|
||||||
|
ImGuiNative.igGetIO()->KeyShift = (byte)((KeyboardState[Key.ShiftLeft]
|
||||||
|
|| KeyboardState[Key.ShiftRight]) ? 1 : 0);
|
||||||
|
|
||||||
|
ImGuiNative.igGetIO()->KeySuper = (byte)((KeyboardState[Key.WinLeft]
|
||||||
|
|| KeyboardState[Key.WinRight]) ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IO.MousePosition = new System.Numerics.Vector2(-1f, -1f);
|
||||||
|
|
||||||
|
for (int i = 0; i <= 512; i++)
|
||||||
|
{
|
||||||
|
IO.KeysDown[i] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Mouse.HasValue)
|
||||||
|
{
|
||||||
|
IO.MouseDown[0] = MouseState.LeftButton == ButtonState.Pressed;
|
||||||
|
IO.MouseDown[1] = MouseState.RightButton == ButtonState.Pressed;
|
||||||
|
IO.MouseDown[2] = MouseState.MiddleButton == ButtonState.Pressed;
|
||||||
|
|
||||||
|
float NewWheelPos = MouseState.WheelPrecise;
|
||||||
|
float Delta = NewWheelPos - WheelPosition;
|
||||||
|
WheelPosition = NewWheelPos;
|
||||||
|
IO.MouseWheel = Delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe void RenderImDrawData(DrawData* DrawData)
|
||||||
|
{
|
||||||
|
Vector4 ClearColor = new Vector4(114f / 255f, 144f / 255f, 154f / 255f, 1.0f);
|
||||||
|
|
||||||
|
GL.Viewport(0, 0, Width, Height);
|
||||||
|
|
||||||
|
GL.ClearColor(ClearColor.X, ClearColor.Y, ClearColor.Z, ClearColor.W);
|
||||||
|
|
||||||
|
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||||
|
|
||||||
|
GL.GetInteger(GetPName.TextureBinding2D, out int last_texture);
|
||||||
|
|
||||||
|
GL.PushAttrib(AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.TransformBit);
|
||||||
|
|
||||||
|
GL.Enable(EnableCap.Blend);
|
||||||
|
|
||||||
|
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||||
|
|
||||||
|
GL.Disable(EnableCap.CullFace);
|
||||||
|
|
||||||
|
GL.Disable(EnableCap.DepthTest);
|
||||||
|
|
||||||
|
GL.Enable(EnableCap.ScissorTest);
|
||||||
|
|
||||||
|
GL.EnableClientState(ArrayCap.VertexArray);
|
||||||
|
|
||||||
|
GL.EnableClientState(ArrayCap.TextureCoordArray);
|
||||||
|
|
||||||
|
GL.EnableClientState(ArrayCap.ColorArray);
|
||||||
|
|
||||||
|
GL.Enable(EnableCap.Texture2D);
|
||||||
|
|
||||||
|
GL.UseProgram(0);
|
||||||
|
|
||||||
|
IO IO = ImGui.GetIO();
|
||||||
|
|
||||||
|
ImGui.ScaleClipRects(DrawData, IO.DisplayFramebufferScale);
|
||||||
|
|
||||||
|
GL.MatrixMode(MatrixMode.Projection);
|
||||||
|
|
||||||
|
GL.PushMatrix();
|
||||||
|
|
||||||
|
GL.LoadIdentity();
|
||||||
|
|
||||||
|
GL.Ortho(
|
||||||
|
0.0f,
|
||||||
|
IO.DisplaySize.X / IO.DisplayFramebufferScale.X,
|
||||||
|
IO.DisplaySize.Y / IO.DisplayFramebufferScale.Y,
|
||||||
|
0.0f,
|
||||||
|
-1.0f,
|
||||||
|
1.0f);
|
||||||
|
|
||||||
|
GL.MatrixMode(MatrixMode.Modelview);
|
||||||
|
|
||||||
|
GL.PushMatrix();
|
||||||
|
|
||||||
|
GL.LoadIdentity();
|
||||||
|
|
||||||
|
// Render command lists
|
||||||
|
for (int n = 0; n < DrawData->CmdListsCount; n++)
|
||||||
|
{
|
||||||
|
NativeDrawList* CmdList = DrawData->CmdLists[n];
|
||||||
|
byte* VtxBuffer = (byte*)CmdList->VtxBuffer.Data;
|
||||||
|
ushort* IdxBuffer = (ushort*)CmdList->IdxBuffer.Data;
|
||||||
|
|
||||||
|
GL.VertexPointer(2, VertexPointerType.Float, sizeof(DrawVert), new IntPtr(VtxBuffer + DrawVert.PosOffset));
|
||||||
|
|
||||||
|
GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(DrawVert), new IntPtr(VtxBuffer + DrawVert.UVOffset));
|
||||||
|
|
||||||
|
GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(DrawVert), new IntPtr(VtxBuffer + DrawVert.ColOffset));
|
||||||
|
|
||||||
|
for (int Cmd = 0; Cmd < CmdList->CmdBuffer.Size; Cmd++)
|
||||||
|
{
|
||||||
|
DrawCmd* PCmd = &(((DrawCmd*)CmdList->CmdBuffer.Data)[Cmd]);
|
||||||
|
|
||||||
|
if (PCmd->UserCallback != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GL.BindTexture(TextureTarget.Texture2D, PCmd->TextureId.ToInt32());
|
||||||
|
|
||||||
|
GL.Scissor(
|
||||||
|
(int)PCmd->ClipRect.X,
|
||||||
|
(int)(IO.DisplaySize.Y - PCmd->ClipRect.W),
|
||||||
|
(int)(PCmd->ClipRect.Z - PCmd->ClipRect.X),
|
||||||
|
(int)(PCmd->ClipRect.W - PCmd->ClipRect.Y));
|
||||||
|
|
||||||
|
ushort[] indices = new ushort[PCmd->ElemCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < indices.Length; i++)
|
||||||
|
indices[i] = IdxBuffer[i];
|
||||||
|
|
||||||
|
GL.DrawElements(PrimitiveType.Triangles, (int)PCmd->ElemCount, DrawElementsType.UnsignedShort, new IntPtr(IdxBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
IdxBuffer += PCmd->ElemCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore modified state
|
||||||
|
GL.DisableClientState(ArrayCap.ColorArray);
|
||||||
|
|
||||||
|
GL.DisableClientState(ArrayCap.TextureCoordArray);
|
||||||
|
|
||||||
|
GL.DisableClientState(ArrayCap.VertexArray);
|
||||||
|
|
||||||
|
GL.BindTexture(TextureTarget.Texture2D, last_texture);
|
||||||
|
|
||||||
|
GL.MatrixMode(MatrixMode.Modelview);
|
||||||
|
|
||||||
|
GL.PopMatrix();
|
||||||
|
|
||||||
|
GL.MatrixMode(MatrixMode.Projection);
|
||||||
|
|
||||||
|
GL.PopMatrix();
|
||||||
|
|
||||||
|
GL.PopAttrib();
|
||||||
|
|
||||||
|
SwapBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool IsGamePadButtonPressed(GamePadState GamePad, GamePadButton Button)
|
||||||
|
{
|
||||||
|
if (Button == GamePadButton.LTrigger || Button == GamePadButton.RTrigger)
|
||||||
|
{
|
||||||
|
return GetGamePadTrigger(GamePad, Button) >= Config.GamePadTriggerThreshold;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (GetGamePadButton(GamePad, Button) == ButtonState.Pressed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static ButtonState GetGamePadButton(GamePadState GamePad, GamePadButton Button)
|
||||||
|
{
|
||||||
|
switch (Button)
|
||||||
|
{
|
||||||
|
case GamePadButton.A: return GamePad.Buttons.A;
|
||||||
|
case GamePadButton.B: return GamePad.Buttons.B;
|
||||||
|
case GamePadButton.X: return GamePad.Buttons.X;
|
||||||
|
case GamePadButton.Y: return GamePad.Buttons.Y;
|
||||||
|
case GamePadButton.LStick: return GamePad.Buttons.LeftStick;
|
||||||
|
case GamePadButton.RStick: return GamePad.Buttons.RightStick;
|
||||||
|
case GamePadButton.LShoulder: return GamePad.Buttons.LeftShoulder;
|
||||||
|
case GamePadButton.RShoulder: return GamePad.Buttons.RightShoulder;
|
||||||
|
case GamePadButton.DPadUp: return GamePad.DPad.Up;
|
||||||
|
case GamePadButton.DPadDown: return GamePad.DPad.Down;
|
||||||
|
case GamePadButton.DPadLeft: return GamePad.DPad.Left;
|
||||||
|
case GamePadButton.DPadRight: return GamePad.DPad.Right;
|
||||||
|
case GamePadButton.Start: return GamePad.Buttons.Start;
|
||||||
|
case GamePadButton.Back: return GamePad.Buttons.Back;
|
||||||
|
default: throw new ArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static float GetGamePadTrigger(GamePadState GamePad, GamePadButton Trigger)
|
||||||
|
{
|
||||||
|
switch (Trigger)
|
||||||
|
{
|
||||||
|
case GamePadButton.LTrigger: return GamePad.Triggers.Left;
|
||||||
|
case GamePadButton.RTrigger: return GamePad.Triggers.Right;
|
||||||
|
default: throw new ArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Vector2 GetJoystickAxis(GamePadState GamePad, GamePadStick Joystick)
|
||||||
|
{
|
||||||
|
switch (Joystick)
|
||||||
|
{
|
||||||
|
case GamePadStick.LJoystick: return GamePad.ThumbSticks.Left;
|
||||||
|
case GamePadStick.RJoystick: return new Vector2(-GamePad.ThumbSticks.Right.Y, -GamePad.ThumbSticks.Right.X);
|
||||||
|
default: throw new ArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnKeyDown(KeyboardKeyEventArgs e)
|
||||||
|
{
|
||||||
|
Keyboard = e.Keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnKeyUp(KeyboardKeyEventArgs e)
|
||||||
|
{
|
||||||
|
Keyboard = e.Keyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseDown(MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
Mouse = e.Mouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseUp(MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
Mouse = e.Mouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnMouseMove(MouseMoveEventArgs e)
|
||||||
|
{
|
||||||
|
Mouse = e.Mouse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
Ryujinx.UI/InputDevice.cs
Normal file
21
Ryujinx.UI/InputDevice.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using OpenTK.Input;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI
|
||||||
|
{
|
||||||
|
public struct InputDevice
|
||||||
|
{
|
||||||
|
public int Index;
|
||||||
|
public string Name;
|
||||||
|
public IInputDevice Device;
|
||||||
|
public DeviceType DeviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DeviceType
|
||||||
|
{
|
||||||
|
GamePad,
|
||||||
|
Keyboard
|
||||||
|
}
|
||||||
|
}
|
16
Ryujinx.UI/Program.cs
Normal file
16
Ryujinx.UI/Program.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
EmulationWindow MainUI = new EmulationWindow();
|
||||||
|
|
||||||
|
MainUI.MainLoop();
|
||||||
|
|
||||||
|
Environment.Exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
Ryujinx.UI/Ryujinx.UI.csproj
Normal file
39
Ryujinx.UI/Ryujinx.UI.csproj
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<OutputPath>..\Ryujinx\bin\Release\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>..\Ryujinx\bin\Debug\</OutputPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="ImGui.NET" Version="0.4.5" />
|
||||||
|
<PackageReference Include="OpenTK.NetStandard" Version="1.0.4" />
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="4.5.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Graphics\Ryujinx.Graphics.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="RyujinxUI.conf">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
82
Ryujinx.UI/RyujinxUI.conf
Normal file
82
Ryujinx.UI/RyujinxUI.conf
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#Enable cpu memory checks (slow)
|
||||||
|
Enable_Memory_Checks = false
|
||||||
|
|
||||||
|
#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 =
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#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
|
16
Ryujinx.sln
16
Ryujinx.sln
|
@ -15,9 +15,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics", "Ryujinx
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "Ryujinx.Audio\Ryujinx.Audio.csproj", "{5C1D818E-682A-46A5-9D54-30006E26C270}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "Ryujinx.Audio\Ryujinx.Audio.csproj", "{5C1D818E-682A-46A5-9D54-30006E26C270}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.ShaderTools", "Ryujinx.ShaderTools\Ryujinx.ShaderTools.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.ShaderTools", "Ryujinx.ShaderTools\Ryujinx.ShaderTools.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Luea", "Ryujinx.LLE\Luea.csproj", "{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luea", "Ryujinx.LLE\Luea.csproj", "{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI", "Ryujinx.UI\Ryujinx.UI.csproj", "{00117502-1661-4C8B-8C07-177C1A8AA455}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Common", "Ryujinx.Common\Ryujinx.Common.csproj", "{E614B5D6-7497-4B8D-A6BE-76CA134BDCE7}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -57,6 +61,14 @@ Global
|
||||||
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Release|Any CPU.Build.0 = Release|Any CPU
|
{8E7D36DD-9626-47E2-8EF5-8F2F66751C9C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{00117502-1661-4C8B-8C07-177C1A8AA455}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{00117502-1661-4C8B-8C07-177C1A8AA455}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{00117502-1661-4C8B-8C07-177C1A8AA455}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{00117502-1661-4C8B-8C07-177C1A8AA455}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E614B5D6-7497-4B8D-A6BE-76CA134BDCE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E614B5D6-7497-4B8D-A6BE-76CA134BDCE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E614B5D6-7497-4B8D-A6BE-76CA134BDCE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E614B5D6-7497-4B8D-A6BE-76CA134BDCE7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using Ryujinx.UI.Input;
|
using Ryujinx.Common.Input;
|
||||||
using Ryujinx.HLE.Logging;
|
using Ryujinx.HLE.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
@ -109,28 +109,28 @@ namespace Ryujinx
|
||||||
{
|
{
|
||||||
Left = new JoyConControllerLeft
|
Left = new JoyConControllerLeft
|
||||||
{
|
{
|
||||||
Stick = Parser.Value("Controls_Left_JoyConController_Stick"),
|
Stick = Enum.Parse<GamePadStick>(Parser.Value("Controls_Left_JoyConController_Stick")),
|
||||||
StickButton = Parser.Value("Controls_Left_JoyConController_Stick_Button"),
|
StickButton = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_Stick_Button")),
|
||||||
DPadUp = Parser.Value("Controls_Left_JoyConController_DPad_Up"),
|
DPadUp = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_DPad_Up")),
|
||||||
DPadDown = Parser.Value("Controls_Left_JoyConController_DPad_Down"),
|
DPadDown = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_DPad_Down")),
|
||||||
DPadLeft = Parser.Value("Controls_Left_JoyConController_DPad_Left"),
|
DPadLeft = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_DPad_Left")),
|
||||||
DPadRight = Parser.Value("Controls_Left_JoyConController_DPad_Right"),
|
DPadRight = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_DPad_Right")),
|
||||||
ButtonMinus = Parser.Value("Controls_Left_JoyConController_Button_Minus"),
|
ButtonMinus = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_Button_Minus")),
|
||||||
ButtonL = Parser.Value("Controls_Left_JoyConController_Button_L"),
|
ButtonL = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_Button_L")),
|
||||||
ButtonZL = Parser.Value("Controls_Left_JoyConController_Button_ZL")
|
ButtonZL = Enum.Parse<GamePadButton>(Parser.Value("Controls_Left_JoyConController_Button_ZL"))
|
||||||
},
|
},
|
||||||
|
|
||||||
Right = new JoyConControllerRight
|
Right = new JoyConControllerRight
|
||||||
{
|
{
|
||||||
Stick = Parser.Value("Controls_Right_JoyConController_Stick"),
|
Stick = Enum.Parse<GamePadStick>(Parser.Value("Controls_Right_JoyConController_Stick")),
|
||||||
StickButton = Parser.Value("Controls_Right_JoyConController_Stick_Button"),
|
StickButton = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Stick_Button")),
|
||||||
ButtonA = Parser.Value("Controls_Right_JoyConController_Button_A"),
|
ButtonA = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_A")),
|
||||||
ButtonB = Parser.Value("Controls_Right_JoyConController_Button_B"),
|
ButtonB = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_B")),
|
||||||
ButtonX = Parser.Value("Controls_Right_JoyConController_Button_X"),
|
ButtonX = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_X")),
|
||||||
ButtonY = Parser.Value("Controls_Right_JoyConController_Button_Y"),
|
ButtonY = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_Y")),
|
||||||
ButtonPlus = Parser.Value("Controls_Right_JoyConController_Button_Plus"),
|
ButtonPlus = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_Plus")),
|
||||||
ButtonR = Parser.Value("Controls_Right_JoyConController_Button_R"),
|
ButtonR = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_R")),
|
||||||
ButtonZR = Parser.Value("Controls_Right_JoyConController_Button_ZR")
|
ButtonZR = Enum.Parse<GamePadButton>(Parser.Value("Controls_Right_JoyConController_Button_ZR"))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
|
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Graphics\Ryujinx.Graphics.csproj" />
|
<ProjectReference Include="..\Ryujinx.Graphics\Ryujinx.Graphics.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -4,6 +4,7 @@ using OpenTK.Input;
|
||||||
using Ryujinx.Graphics.Gal;
|
using Ryujinx.Graphics.Gal;
|
||||||
using Ryujinx.HLE;
|
using Ryujinx.HLE;
|
||||||
using Ryujinx.HLE.Input;
|
using Ryujinx.HLE.Input;
|
||||||
|
using Ryujinx.Common.Input;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
|
@ -130,57 +131,57 @@ namespace Ryujinx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsGamePadButtonPressedFromString(GamePadState GamePad, string Button)
|
private bool IsGamePadButtonPressed(GamePadState GamePad, GamePadButton Button)
|
||||||
{
|
{
|
||||||
if (Button.ToUpper() == "LTRIGGER" || Button.ToUpper() == "RTRIGGER")
|
if (Button == GamePadButton.LTrigger || Button == GamePadButton.RTrigger)
|
||||||
{
|
{
|
||||||
return GetGamePadTriggerFromString(GamePad, Button) >= Config.GamePadTriggerThreshold;
|
return GetGamePadTrigger(GamePad, Button) >= Config.GamePadTriggerThreshold;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return (GetGamePadButtonFromString(GamePad, Button) == ButtonState.Pressed);
|
return (GetGamePadButton(GamePad, Button) == ButtonState.Pressed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ButtonState GetGamePadButtonFromString(GamePadState GamePad, string Button)
|
private ButtonState GetGamePadButton(GamePadState GamePad, GamePadButton Button)
|
||||||
{
|
{
|
||||||
switch (Button.ToUpper())
|
switch (Button)
|
||||||
{
|
{
|
||||||
case "A": return GamePad.Buttons.A;
|
case GamePadButton.A: return GamePad.Buttons.A;
|
||||||
case "B": return GamePad.Buttons.B;
|
case GamePadButton.B: return GamePad.Buttons.B;
|
||||||
case "X": return GamePad.Buttons.X;
|
case GamePadButton.X: return GamePad.Buttons.X;
|
||||||
case "Y": return GamePad.Buttons.Y;
|
case GamePadButton.Y: return GamePad.Buttons.Y;
|
||||||
case "LSTICK": return GamePad.Buttons.LeftStick;
|
case GamePadButton.LStick: return GamePad.Buttons.LeftStick;
|
||||||
case "RSTICK": return GamePad.Buttons.RightStick;
|
case GamePadButton.RStick: return GamePad.Buttons.RightStick;
|
||||||
case "LSHOULDER": return GamePad.Buttons.LeftShoulder;
|
case GamePadButton.LShoulder: return GamePad.Buttons.LeftShoulder;
|
||||||
case "RSHOULDER": return GamePad.Buttons.RightShoulder;
|
case GamePadButton.RShoulder: return GamePad.Buttons.RightShoulder;
|
||||||
case "DPADUP": return GamePad.DPad.Up;
|
case GamePadButton.DPadUp: return GamePad.DPad.Up;
|
||||||
case "DPADDOWN": return GamePad.DPad.Down;
|
case GamePadButton.DPadDown: return GamePad.DPad.Down;
|
||||||
case "DPADLEFT": return GamePad.DPad.Left;
|
case GamePadButton.DPadLeft: return GamePad.DPad.Left;
|
||||||
case "DPADRIGHT": return GamePad.DPad.Right;
|
case GamePadButton.DPadRight: return GamePad.DPad.Right;
|
||||||
case "START": return GamePad.Buttons.Start;
|
case GamePadButton.Start: return GamePad.Buttons.Start;
|
||||||
case "BACK": return GamePad.Buttons.Back;
|
case GamePadButton.Back: return GamePad.Buttons.Back;
|
||||||
default: throw new ArgumentException();
|
default: throw new ArgumentException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private float GetGamePadTriggerFromString(GamePadState GamePad, string Trigger)
|
private float GetGamePadTrigger(GamePadState GamePad, GamePadButton Trigger)
|
||||||
{
|
{
|
||||||
switch (Trigger.ToUpper())
|
switch (Trigger)
|
||||||
{
|
{
|
||||||
case "LTRIGGER": return GamePad.Triggers.Left;
|
case GamePadButton.LTrigger: return GamePad.Triggers.Left;
|
||||||
case "RTRIGGER": return GamePad.Triggers.Right;
|
case GamePadButton.RTrigger: return GamePad.Triggers.Right;
|
||||||
default: throw new ArgumentException();
|
default: throw new ArgumentException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2 GetJoystickAxisFromString(GamePadState GamePad, string Joystick)
|
private Vector2 GetJoystickAxisFromString(GamePadState GamePad, GamePadStick Joystick)
|
||||||
{
|
{
|
||||||
switch (Joystick.ToUpper())
|
switch (Joystick)
|
||||||
{
|
{
|
||||||
case "LJOYSTICK": return GamePad.ThumbSticks.Left;
|
case GamePadStick.LJoystick: return GamePad.ThumbSticks.Left;
|
||||||
case "RJOYSTICK": return new Vector2(-GamePad.ThumbSticks.Right.Y, -GamePad.ThumbSticks.Right.X);
|
case GamePadStick.RJoystick: return new Vector2(-GamePad.ThumbSticks.Right.Y, -GamePad.ThumbSticks.Right.X);
|
||||||
default: throw new ArgumentException();
|
default: throw new ArgumentException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,24 +242,24 @@ namespace Ryujinx
|
||||||
{
|
{
|
||||||
GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex);
|
GamePadState GamePad = OpenTK.Input.GamePad.GetState(Config.GamePadIndex);
|
||||||
//LeftButtons
|
//LeftButtons
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadUp)) CurrentButton |= HidControllerButtons.KEY_DUP;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadUp)) CurrentButton |= HidControllerButtons.KEY_DUP;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadDown)) CurrentButton |= HidControllerButtons.KEY_DDOWN;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadDown)) CurrentButton |= HidControllerButtons.KEY_DDOWN;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadLeft)) CurrentButton |= HidControllerButtons.KEY_DLEFT;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadLeft)) CurrentButton |= HidControllerButtons.KEY_DLEFT;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.DPadRight)) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.DPadRight)) CurrentButton |= HidControllerButtons.KEY_DRIGHT;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.StickButton)) CurrentButton |= HidControllerButtons.KEY_LSTICK;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.StickButton)) CurrentButton |= HidControllerButtons.KEY_LSTICK;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.ButtonMinus)) CurrentButton |= HidControllerButtons.KEY_MINUS;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonMinus)) CurrentButton |= HidControllerButtons.KEY_MINUS;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.ButtonL)) CurrentButton |= HidControllerButtons.KEY_L;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonL)) CurrentButton |= HidControllerButtons.KEY_L;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Left.ButtonZL)) CurrentButton |= HidControllerButtons.KEY_ZL;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Left.ButtonZL)) CurrentButton |= HidControllerButtons.KEY_ZL;
|
||||||
|
|
||||||
//RightButtons
|
//RightButtons
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonA)) CurrentButton |= HidControllerButtons.KEY_A;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonA)) CurrentButton |= HidControllerButtons.KEY_A;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonB)) CurrentButton |= HidControllerButtons.KEY_B;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonB)) CurrentButton |= HidControllerButtons.KEY_B;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonX)) CurrentButton |= HidControllerButtons.KEY_X;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonX)) CurrentButton |= HidControllerButtons.KEY_X;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonY)) CurrentButton |= HidControllerButtons.KEY_Y;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonY)) CurrentButton |= HidControllerButtons.KEY_Y;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.StickButton)) CurrentButton |= HidControllerButtons.KEY_RSTICK;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.StickButton)) CurrentButton |= HidControllerButtons.KEY_RSTICK;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonPlus)) CurrentButton |= HidControllerButtons.KEY_PLUS;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonPlus)) CurrentButton |= HidControllerButtons.KEY_PLUS;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonR)) CurrentButton |= HidControllerButtons.KEY_R;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonR)) CurrentButton |= HidControllerButtons.KEY_R;
|
||||||
if (IsGamePadButtonPressedFromString(GamePad, Config.JoyConController.Right.ButtonZR)) CurrentButton |= HidControllerButtons.KEY_ZR;
|
if (IsGamePadButtonPressed(GamePad, Config.JoyConController.Right.ButtonZR)) CurrentButton |= HidControllerButtons.KEY_ZR;
|
||||||
|
|
||||||
//LeftJoystick
|
//LeftJoystick
|
||||||
if (GetJoystickAxisFromString(GamePad, Config.JoyConController.Left.Stick).X >= AnalogStickDeadzone
|
if (GetJoystickAxisFromString(GamePad, Config.JoyConController.Left.Stick).X >= AnalogStickDeadzone
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Ryujinx.UI.Input
|
|
||||||
{
|
|
||||||
public struct JoyConControllerLeft
|
|
||||||
{
|
|
||||||
public string Stick;
|
|
||||||
public string StickButton;
|
|
||||||
public string DPadUp;
|
|
||||||
public string DPadDown;
|
|
||||||
public string DPadLeft;
|
|
||||||
public string DPadRight;
|
|
||||||
public string ButtonMinus;
|
|
||||||
public string ButtonL;
|
|
||||||
public string ButtonZL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct JoyConControllerRight
|
|
||||||
{
|
|
||||||
public string Stick;
|
|
||||||
public string StickButton;
|
|
||||||
public string ButtonA;
|
|
||||||
public string ButtonB;
|
|
||||||
public string ButtonX;
|
|
||||||
public string ButtonY;
|
|
||||||
public string ButtonPlus;
|
|
||||||
public string ButtonR;
|
|
||||||
public string ButtonZR;
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct JoyConController
|
|
||||||
{
|
|
||||||
public JoyConControllerLeft Left;
|
|
||||||
public JoyConControllerRight Right;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue