예제 #1
0
        static void Main(string[] args)
        {
            Console.Title = "Ryujinx Console";

            string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine);

            Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}");

            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            AppDomain.CurrentDomain.ProcessExit        += CurrentDomain_ProcessExit;
            GLib.ExceptionManager.UnhandledException   += Glib_UnhandledException;

            Profile.Initialize();

            Application.Init();

            string appDataPath     = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "RyuFs", "system", "prod.keys");
            string userProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch", "prod.keys");

            if (!File.Exists(appDataPath) && !File.Exists(userProfilePath))
            {
                GtkDialog.CreateErrorDialog($"Key file was not found. Please refer to `KEYS.md` for more info");
            }

            MainWindow mainWindow = new MainWindow();

            mainWindow.Show();

            if (args.Length == 1)
            {
                mainWindow.LoadApplication(args[0]);
            }

            Application.Run();
        }
예제 #2
0
        static void Main(string[] args)
        {
            Console.Title = "Ryujinx Console";

            string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine);

            Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}");

            GLib.ExceptionManager.UnhandledException += Glib_UnhandledException;

            // Initialize the configuration
            ConfigurationState.Initialize();

            // Initialize the logger system
            LoggerModule.Initialize();

            // Initialize Discord integration
            DiscordIntegrationModule.Initialize();

            string configurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");

            // Now load the configuration as the other subsystems are now registered
            if (File.Exists(configurationPath))
            {
                ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(configurationPath);
                ConfigurationState.Instance.Load(configurationFileFormat);
            }
            else
            {
                // No configuration, we load the default values and save it on disk
                ConfigurationState.Instance.LoadDefault();
                ConfigurationState.Instance.ToFileFormat().SaveConfig(configurationPath);
            }


            Profile.Initialize();

            Application.Init();

            string appDataPath     = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Ryujinx", "system", "prod.keys");
            string userProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch", "prod.keys");

            if (!File.Exists(appDataPath) && !File.Exists(userProfilePath) && !Migration.IsMigrationNeeded())
            {
                GtkDialog.CreateErrorDialog("Key file was not found. Please refer to `KEYS.md` for more info");
            }

            MainWindow mainWindow = new MainWindow();

            mainWindow.Show();

            if (args.Length == 1)
            {
                mainWindow.LoadApplication(args[0]);
            }

            Application.Run();
        }
예제 #3
0
        private TitleUpdateWindow(Builder builder, MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetObject("_titleUpdateWindow").Handle)
        {
            _parent = parent;

            builder.Autoconnect(this);

            _titleId                     = titleId;
            _virtualFileSystem           = virtualFileSystem;
            _updateJsonPath              = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "updates.json");
            _radioButtonToPathDictionary = new Dictionary <RadioButton, string>();

            try
            {
                _titleUpdateWindowData = JsonHelper.DeserializeFromFile <TitleUpdateMetadata>(_updateJsonPath);
            }
            catch
            {
                _titleUpdateWindowData = new TitleUpdateMetadata
                {
                    Selected = "",
                    Paths    = new List <string>()
                };
            }

            _baseTitleInfoLabel.Text = $"Updates Available for {titleName} [{titleId.ToUpper()}]";

            int invalidUpdateCount = 0;

            foreach (string path in _titleUpdateWindowData.Paths)
            {
                if (!File.Exists(path))
                {
                    invalidUpdateCount++;
                    continue;
                }

                AddUpdate(path);
            }

            if (invalidUpdateCount > 0)
            {
                Logger.Error?.PrintMsg(LogClass.Application, "Updates have been moved or deleted; skipping " + invalidUpdateCount + " updates");
                GtkDialog.CreateErrorDialog(invalidUpdateCount + " updates have been moved or deleted; please re-add your updates.");
            }

            if (_titleUpdateWindowData.Selected == "")
            {
                _noUpdateRadioButton.Active = true;
            }
            else
            {
                foreach ((RadioButton update, var _) in _radioButtonToPathDictionary.Where(keyValuePair => keyValuePair.Value == _titleUpdateWindowData.Selected))
                {
                    update.Active = true;
                }
            }
        }
예제 #4
0
파일: DlcWindow.cs 프로젝트: YR1044/Ryujinx
        private Nca TryCreateNca(IStorage ncaStorage, string containerPath)
        {
            try
            {
                return(new Nca(_virtualFileSystem.KeySet, ncaStorage));
            }
            catch (Exception exception)
            {
                GtkDialog.CreateErrorDialog($"{exception.Message}. Errored File: {containerPath}");
            }

            return(null);
        }
예제 #5
0
        public bool DisplayErrorAppletDialog(string title, string message, string[] buttons)
        {
            ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);

            bool showDetails = false;

            Application.Invoke(delegate
            {
                try
                {
                    ErrorAppletDialog msgDialog = new ErrorAppletDialog(_parent, DialogFlags.DestroyWithParent, MessageType.Error, buttons)
                    {
                        Title          = title,
                        Text           = message,
                        UseMarkup      = true,
                        WindowPosition = WindowPosition.CenterAlways
                    };

                    msgDialog.SetDefaultSize(400, 0);

                    msgDialog.Response += (object o, ResponseArgs args) =>
                    {
                        if (buttons != null)
                        {
                            if (buttons.Length > 1)
                            {
                                if (args.ResponseId != (ResponseType)(buttons.Length - 1))
                                {
                                    showDetails = true;
                                }
                            }
                        }

                        dialogCloseEvent.Set();
                        msgDialog?.Dispose();
                    };

                    msgDialog.Show();
                }
                catch (Exception ex)
                {
                    GtkDialog.CreateErrorDialog($"Error displaying ErrorApplet Dialog: {ex}");

                    dialogCloseEvent.Set();
                }
            });

            dialogCloseEvent.WaitOne();

            return(showDetails);
        }
예제 #6
0
        public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText)
        {
            ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);

            bool   okPressed = false;
            bool   error     = false;
            string inputText = args.InitialText ?? "";

            Application.Invoke(delegate
            {
                try
                {
                    var swkbdDialog = new SwkbdAppletDialog(_parent)
                    {
                        Title         = "Software Keyboard",
                        Text          = args.HeaderText,
                        SecondaryText = args.SubtitleText
                    };

                    swkbdDialog.InputEntry.Text            = inputText;
                    swkbdDialog.InputEntry.PlaceholderText = args.GuideText;
                    swkbdDialog.OkButton.Label             = args.SubmitText;

                    swkbdDialog.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax);

                    if (swkbdDialog.Run() == (int)ResponseType.Ok)
                    {
                        inputText = swkbdDialog.InputEntry.Text;
                        okPressed = true;
                    }

                    swkbdDialog.Dispose();
                }
                catch (Exception ex)
                {
                    error = true;

                    GtkDialog.CreateErrorDialog($"Error displaying Software Keyboard: {ex}");
                }
                finally
                {
                    dialogCloseEvent.Set();
                }
            });

            dialogCloseEvent.WaitOne();

            userText = error ? null : inputText;

            return(error || okPressed);
        }
예제 #7
0
        public bool DisplayMessageDialog(string title, string message)
        {
            ManualResetEvent dialogCloseEvent = new ManualResetEvent(false);

            bool okPressed = false;

            Application.Invoke(delegate
            {
                MessageDialog msgDialog = null;

                try
                {
                    msgDialog = new MessageDialog(_parent, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null)
                    {
                        Title     = title,
                        Text      = message,
                        UseMarkup = true
                    };

                    msgDialog.SetDefaultSize(400, 0);

                    msgDialog.Response += (object o, ResponseArgs args) =>
                    {
                        if (args.ResponseId == ResponseType.Ok)
                        {
                            okPressed = true;
                        }

                        dialogCloseEvent.Set();
                        msgDialog?.Dispose();
                    };

                    msgDialog.Show();
                }
                catch (Exception ex)
                {
                    GtkDialog.CreateErrorDialog($"Error displaying Message Dialog: {ex}");

                    dialogCloseEvent.Set();
                }
            });

            dialogCloseEvent.WaitOne();

            return(okPressed);
        }
예제 #8
0
        private void AddUpdate(string path)
        {
            if (File.Exists(path))
            {
                using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read))
                {
                    PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage());

                    try
                    {
                        (Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, nsp, _titleId, 0);

                        if (controlNca != null && patchNca != null)
                        {
                            ApplicationControlProperty controlData = new ApplicationControlProperty();

                            using var nacpFile = new UniqueRef <IFile>();

                            controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref(), "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
                            nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();

                            RadioButton radioButton = new RadioButton($"Version {controlData.DisplayVersion.ToString()} - {path}");
                            radioButton.JoinGroup(_noUpdateRadioButton);

                            _availableUpdatesBox.Add(radioButton);
                            _radioButtonToPathDictionary.Add(radioButton, path);

                            radioButton.Show();
                            radioButton.Active = true;
                        }
                        else
                        {
                            GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!");
                        }
                    }
                    catch (Exception exception)
                    {
                        GtkDialog.CreateErrorDialog($"{exception.Message}. Errored File: {path}");
                    }
                }
            }
        }
예제 #9
0
        public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
        {
            if (Running)
            {
                return;
            }

            Running = true;
            mainWindow.UpdateMenuItem.Sensitive = false;

            int artifactIndex = -1;

            // Detect current platform
            if (OperatingSystem.IsMacOS())
            {
                _platformExt  = "osx_x64.zip";
                artifactIndex = 1;
            }
            else if (OperatingSystem.IsWindows())
            {
                _platformExt  = "win_x64.zip";
                artifactIndex = 2;
            }
            else if (OperatingSystem.IsLinux())
            {
                _platformExt  = "linux_x64.tar.gz";
                artifactIndex = 0;
            }

            if (artifactIndex == -1)
            {
                GtkDialog.CreateErrorDialog("Your platform is not supported!");

                return;
            }

            Version newVersion;
            Version currentVersion;

            try
            {
                currentVersion = Version.Parse(Program.Version);
            }
            catch
            {
                GtkDialog.CreateWarningDialog("Failed to convert the current Ryujinx version.", "Cancelling Update!");
                Logger.Error?.Print(LogClass.Application, "Failed to convert the current Ryujinx version!");

                return;
            }

            // Get latest version number from GitHub API
            try
            {
                using (HttpClient jsonClient = ConstructHttpClient())
                {
                    string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformations.ReleaseChannelOwner}/{ReleaseInformations.ReleaseChannelRepo}/releases/latest";

                    // Fetch latest build information
                    string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);

                    JObject jsonRoot = JObject.Parse(fetchedJson);
                    JToken  assets   = jsonRoot["assets"];

                    _buildVer = (string)jsonRoot["name"];

                    foreach (JToken asset in assets)
                    {
                        string assetName   = (string)asset["name"];
                        string assetState  = (string)asset["state"];
                        string downloadURL = (string)asset["browser_download_url"];

                        if (!assetName.StartsWith("ryujinx-headless-sdl2") && assetName.EndsWith(_platformExt))
                        {
                            _buildUrl = downloadURL;

                            if (assetState != "uploaded")
                            {
                                if (showVersionUpToDate)
                                {
                                    GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", "");
                                }

                                return;
                            }

                            break;
                        }
                    }

                    if (_buildUrl == null)
                    {
                        if (showVersionUpToDate)
                        {
                            GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", "");
                        }

                        return;
                    }
                }
            }
            catch (Exception exception)
            {
                Logger.Error?.Print(LogClass.Application, exception.Message);
                GtkDialog.CreateErrorDialog("An error occurred when trying to get release information from GitHub Release. This can be caused if a new release is being compiled by GitHub Actions. Try again in a few minutes.");

                return;
            }

            try
            {
                newVersion = Version.Parse(_buildVer);
            }
            catch
            {
                GtkDialog.CreateWarningDialog("Failed to convert the received Ryujinx version from GitHub Release.", "Cancelling Update!");
                Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from GitHub Release!");

                return;
            }

            if (newVersion <= currentVersion)
            {
                if (showVersionUpToDate)
                {
                    GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", "");
                }

                Running = false;
                mainWindow.UpdateMenuItem.Sensitive = true;

                return;
            }

            // Fetch build size information to learn chunk sizes.
            using (HttpClient buildSizeClient = ConstructHttpClient())
            {
                try
                {
                    buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0");

                    HttpResponseMessage message = await buildSizeClient.GetAsync(new Uri(_buildUrl), HttpCompletionOption.ResponseHeadersRead);

                    _buildSize = message.Content.Headers.ContentRange.Length.Value;
                }
                catch (Exception ex)
                {
                    Logger.Warning?.Print(LogClass.Application, ex.Message);
                    Logger.Warning?.Print(LogClass.Application, "Couldn't determine build size for update, using single-threaded updater");

                    _buildSize = -1;
                }
            }

            // Show a message asking the user if they want to update
            UpdateDialog updateDialog = new UpdateDialog(mainWindow, newVersion, _buildUrl);

            updateDialog.Show();
        }
예제 #10
0
파일: DlcWindow.cs 프로젝트: YR1044/Ryujinx
        private void AddButton_Clicked(object sender, EventArgs args)
        {
            FileChooserNative fileChooser = new FileChooserNative("Select DLC files", this, FileChooserAction.Open, "Add", "Cancel")
            {
                SelectMultiple = true
            };

            FileFilter filter = new FileFilter()
            {
                Name = "Switch Game DLCs"
            };

            filter.AddPattern("*.nsp");

            fileChooser.AddFilter(filter);

            if (fileChooser.Run() == (int)ResponseType.Accept)
            {
                foreach (string containerPath in fileChooser.Filenames)
                {
                    if (!File.Exists(containerPath))
                    {
                        return;
                    }

                    using (FileStream containerFile = File.OpenRead(containerPath))
                    {
                        PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
                        bool containsDlc        = false;

                        _virtualFileSystem.ImportTickets(pfs);

                        TreeIter?parentIter = null;

                        foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
                        {
                            pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();

                            Nca nca = TryCreateNca(ncaFile.AsStorage(), containerPath);

                            if (nca == null)
                            {
                                continue;
                            }

                            if (nca.Header.ContentType == NcaContentType.PublicData)
                            {
                                if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000).ToString("x16") != _titleId)
                                {
                                    break;
                                }

                                parentIter ??= ((TreeStore)_dlcTreeView.Model).AppendValues(true, "", containerPath);

                                ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter.Value, true, nca.Header.TitleId.ToString("X16"), fileEntry.FullPath);
                                containsDlc = true;
                            }
                        }

                        if (!containsDlc)
                        {
                            GtkDialog.CreateErrorDialog("The specified file does not contain DLC for the selected title!");
                        }
                    }
                }
            }

            fileChooser.Dispose();
        }
예제 #11
0
        public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
        {
            if (Running)
            {
                return;
            }

            Running = true;
            mainWindow.UpdateMenuItem.Sensitive = false;

            int artifactIndex = -1;

            // Detect current platform
            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                _platformExt  = "osx_x64.zip";
                artifactIndex = 1;
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                _platformExt  = "win_x64.zip";
                artifactIndex = 2;
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                _platformExt  = "linux_x64.tar.gz";
                artifactIndex = 0;
            }

            if (artifactIndex == -1)
            {
                GtkDialog.CreateErrorDialog("Your platform is not supported!");

                return;
            }

            Version newVersion;
            Version currentVersion;

            try
            {
                currentVersion = Version.Parse(Program.Version);
            }
            catch
            {
                GtkDialog.CreateWarningDialog("Failed to convert the current Ryujinx version.", "Cancelling Update!");
                Logger.Error?.Print(LogClass.Application, "Failed to convert the current Ryujinx version!");

                return;
            }

            // Get latest version number from Appveyor
            try
            {
                using (WebClient jsonClient = new WebClient())
                {
                    // Fetch latest build information
                    string fetchedJson = await jsonClient.DownloadStringTaskAsync($"{AppveyorApiUrl}/projects/gdkchan/ryujinx/branch/master");

                    JObject jsonRoot   = JObject.Parse(fetchedJson);
                    JToken  buildToken = jsonRoot["build"];

                    _jobId    = (string)buildToken["jobs"][0]["jobId"];
                    _buildVer = (string)buildToken["version"];
                    _buildUrl = $"{AppveyorApiUrl}/buildjobs/{_jobId}/artifacts/ryujinx-{_buildVer}-{_platformExt}";

                    // If build not done, assume no new update are availaible.
                    if ((string)buildToken["jobs"][0]["status"] != "success")
                    {
                        if (showVersionUpToDate)
                        {
                            GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", "");
                        }

                        return;
                    }
                }
            }
            catch (Exception exception)
            {
                Logger.Error?.Print(LogClass.Application, exception.Message);
                GtkDialog.CreateErrorDialog("An error has occurred when trying to get release information from AppVeyor.");

                return;
            }

            try
            {
                newVersion = Version.Parse(_buildVer);
            }
            catch
            {
                GtkDialog.CreateWarningDialog("Failed to convert the received Ryujinx version from AppVeyor.", "Cancelling Update!");
                Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from AppVeyor!");

                return;
            }

            if (newVersion <= currentVersion)
            {
                if (showVersionUpToDate)
                {
                    GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", "");
                }

                Running = false;
                mainWindow.UpdateMenuItem.Sensitive = true;

                return;
            }

            // Fetch build size information to learn chunk sizes.
            using (WebClient buildSizeClient = new WebClient())
            {
                try
                {
                    buildSizeClient.Headers.Add("Range", "bytes=0-0");
                    await buildSizeClient.DownloadDataTaskAsync(new Uri(_buildUrl));

                    string contentRange = buildSizeClient.ResponseHeaders["Content-Range"];
                    _buildSize = long.Parse(contentRange.Substring(contentRange.IndexOf('/') + 1));
                }
                catch (Exception ex)
                {
                    Logger.Warning?.Print(LogClass.Application, ex.Message);
                    Logger.Warning?.Print(LogClass.Application, "Couldn't determine build size for update, will use single-threaded updater");

                    _buildSize = -1;
                }
            }

            // Show a message asking the user if they want to update
            UpdateDialog updateDialog = new UpdateDialog(mainWindow, newVersion, _buildUrl);

            updateDialog.Show();
        }
예제 #12
0
        public void LoadApplications(List <string> appDirs, Language desiredTitleLanguage)
        {
            int numApplicationsFound  = 0;
            int numApplicationsLoaded = 0;

            _loadingError         = false;
            _desiredTitleLanguage = desiredTitleLanguage;

            // Builds the applications list with paths to found applications
            List <string> applications = new List <string>();

            foreach (string appDir in appDirs)
            {
                if (!Directory.Exists(appDir))
                {
                    Logger.Warning?.Print(LogClass.Application, $"The \"game_dirs\" section in \"Config.json\" contains an invalid directory: \"{appDir}\"");

                    continue;
                }

                foreach (string app in GetFilesInDirectory(appDir))
                {
                    if ((Path.GetExtension(app).ToLower() == ".nsp") ||
                        (Path.GetExtension(app).ToLower() == ".pfs0") ||
                        (Path.GetExtension(app).ToLower() == ".xci") ||
                        (Path.GetExtension(app).ToLower() == ".nca") ||
                        (Path.GetExtension(app).ToLower() == ".nro") ||
                        (Path.GetExtension(app).ToLower() == ".nso"))
                    {
                        applications.Add(app);
                        numApplicationsFound++;
                    }
                }
            }

            // Loops through applications list, creating a struct and then firing an event containing the struct for each application
            foreach (string applicationPath in applications)
            {
                double fileSize        = new FileInfo(applicationPath).Length * 0.000000000931;
                string titleName       = "Unknown";
                string titleId         = "0000000000000000";
                string developer       = "Unknown";
                string version         = "0";
                byte[] applicationIcon = null;

                BlitStruct <ApplicationControlProperty> controlHolder = new BlitStruct <ApplicationControlProperty>(1);

                try
                {
                    using (FileStream file = new FileStream(applicationPath, FileMode.Open, FileAccess.Read))
                    {
                        if ((Path.GetExtension(applicationPath).ToLower() == ".nsp") ||
                            (Path.GetExtension(applicationPath).ToLower() == ".pfs0") ||
                            (Path.GetExtension(applicationPath).ToLower() == ".xci"))
                        {
                            try
                            {
                                PartitionFileSystem pfs;

                                bool isExeFs = false;

                                if (Path.GetExtension(applicationPath).ToLower() == ".xci")
                                {
                                    Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage());

                                    pfs = xci.OpenPartition(XciPartitionType.Secure);
                                }
                                else
                                {
                                    pfs = new PartitionFileSystem(file.AsStorage());

                                    // If the NSP doesn't have a main NCA, decrement the number of applications found and then continue to the next application.
                                    bool hasMainNca = false;

                                    foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*"))
                                    {
                                        if (Path.GetExtension(fileEntry.FullPath).ToLower() == ".nca")
                                        {
                                            pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();

                                            Nca nca       = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage());
                                            int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);

                                            if (nca.Header.ContentType == NcaContentType.Program && !nca.Header.GetFsHeader(dataIndex).IsPatchSection())
                                            {
                                                hasMainNca = true;

                                                break;
                                            }
                                        }
                                        else if (Path.GetFileNameWithoutExtension(fileEntry.FullPath) == "main")
                                        {
                                            isExeFs = true;
                                        }
                                    }

                                    if (!hasMainNca && !isExeFs)
                                    {
                                        numApplicationsFound--;

                                        continue;
                                    }
                                }

                                if (isExeFs)
                                {
                                    applicationIcon = _nspIcon;

                                    Result result = pfs.OpenFile(out IFile npdmFile, "/main.npdm".ToU8Span(), OpenMode.Read);

                                    if (ResultFs.PathNotFound.Includes(result))
                                    {
                                        Npdm npdm = new Npdm(npdmFile.AsStream());

                                        titleName = npdm.TitleName;
                                        titleId   = npdm.Aci0.TitleId.ToString("x16");
                                    }
                                }
                                else
                                {
                                    // Store the ControlFS in variable called controlFs
                                    GetControlFsAndTitleId(pfs, out IFileSystem controlFs, out titleId);

                                    ReadControlData(controlFs, controlHolder.ByteSpan);

                                    // Get the title name, title ID, developer name and version number from the NACP
                                    version = IsUpdateApplied(titleId, out string updateVersion) ? updateVersion : controlHolder.Value.DisplayVersion.ToString();

                                    GetNameIdDeveloper(ref controlHolder.Value, out titleName, out _, out developer);

                                    // Read the icon from the ControlFS and store it as a byte array
                                    try
                                    {
                                        controlFs.OpenFile(out IFile icon, $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure();

                                        using (MemoryStream stream = new MemoryStream())
                                        {
                                            icon.AsStream().CopyTo(stream);
                                            applicationIcon = stream.ToArray();
                                        }
                                    }
                                    catch (HorizonResultException)
                                    {
                                        foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*"))
                                        {
                                            if (entry.Name == "control.nacp")
                                            {
                                                continue;
                                            }

                                            controlFs.OpenFile(out IFile icon, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();

                                            using (MemoryStream stream = new MemoryStream())
                                            {
                                                icon.AsStream().CopyTo(stream);
                                                applicationIcon = stream.ToArray();
                                            }

                                            if (applicationIcon != null)
                                            {
                                                break;
                                            }
                                        }

                                        if (applicationIcon == null)
                                        {
                                            applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon;
                                        }
                                    }
                                }
                            }
                            catch (MissingKeyException exception)
                            {
                                applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon;

                                Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}");
                            }
                            catch (InvalidDataException)
                            {
                                applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon;

                                Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}");
                            }
                            catch (Exception exception)
                            {
                                Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{applicationPath}' Error: {exception}");

                                numApplicationsFound--;
                                _loadingError = true;

                                continue;
                            }
                        }
                        else if (Path.GetExtension(applicationPath).ToLower() == ".nro")
                        {
                            BinaryReader reader = new BinaryReader(file);

                            byte[] Read(long position, int size)
                            {
                                file.Seek(position, SeekOrigin.Begin);

                                return(reader.ReadBytes(size));
                            }

                            try
                            {
                                file.Seek(24, SeekOrigin.Begin);

                                int assetOffset = reader.ReadInt32();

                                if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET")
                                {
                                    byte[] iconSectionInfo = Read(assetOffset + 8, 0x10);

                                    long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0);
                                    long iconSize   = BitConverter.ToInt64(iconSectionInfo, 8);

                                    ulong nacpOffset = reader.ReadUInt64();
                                    ulong nacpSize   = reader.ReadUInt64();

                                    // Reads and stores game icon as byte array
                                    applicationIcon = Read(assetOffset + iconOffset, (int)iconSize);

                                    // Read the NACP data
                                    Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan);

                                    // Get the title name, title ID, developer name and version number from the NACP
                                    version = controlHolder.Value.DisplayVersion.ToString();

                                    GetNameIdDeveloper(ref controlHolder.Value, out titleName, out titleId, out developer);
                                }
                                else
                                {
                                    applicationIcon = _nroIcon;
                                    titleName       = Path.GetFileNameWithoutExtension(applicationPath);
                                }
                            }
                            catch
                            {
                                Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");

                                numApplicationsFound--;

                                continue;
                            }
                        }
                        else if (Path.GetExtension(applicationPath).ToLower() == ".nca")
                        {
                            try
                            {
                                Nca nca       = new Nca(_virtualFileSystem.KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage());
                                int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);

                                if (nca.Header.ContentType != NcaContentType.Program || nca.Header.GetFsHeader(dataIndex).IsPatchSection())
                                {
                                    numApplicationsFound--;

                                    continue;
                                }
                            }
                            catch (InvalidDataException)
                            {
                                Logger.Warning?.Print(LogClass.Application, $"The NCA header content type check has failed. This is usually because the header key is incorrect or missing. Errored File: {applicationPath}");
                            }
                            catch
                            {
                                Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}");

                                numApplicationsFound--;
                                _loadingError = true;

                                continue;
                            }

                            applicationIcon = _ncaIcon;
                            titleName       = Path.GetFileNameWithoutExtension(applicationPath);
                        }
                        // If its an NSO we just set defaults
                        else if (Path.GetExtension(applicationPath).ToLower() == ".nso")
                        {
                            applicationIcon = _nsoIcon;
                            titleName       = Path.GetFileNameWithoutExtension(applicationPath);
                        }
                    }
                }
                catch (IOException exception)
                {
                    Logger.Warning?.Print(LogClass.Application, exception.Message);

                    numApplicationsFound--;
                    _loadingError = true;

                    continue;
                }

                ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId);

                if (appMetadata.LastPlayed != "Never" && !DateTime.TryParse(appMetadata.LastPlayed, out _))
                {
                    Logger.Warning?.Print(LogClass.Application, $"Last played datetime \"{appMetadata.LastPlayed}\" is invalid for current system culture, skipping (did current culture change?)");

                    appMetadata.LastPlayed = "Never";
                }

                ApplicationData data = new ApplicationData
                {
                    Favorite      = appMetadata.Favorite,
                    Icon          = applicationIcon,
                    TitleName     = titleName,
                    TitleId       = titleId,
                    Developer     = developer,
                    Version       = version,
                    TimePlayed    = ConvertSecondsToReadableString(appMetadata.TimePlayed),
                    LastPlayed    = appMetadata.LastPlayed,
                    FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0, 1),
                    FileSize      = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB",
                    Path          = applicationPath,
                    ControlHolder = controlHolder
                };

                numApplicationsLoaded++;

                OnApplicationAdded(new ApplicationAddedEventArgs()
                {
                    AppData = data
                });

                OnApplicationCountUpdated(new ApplicationCountUpdatedEventArgs()
                {
                    NumAppsFound  = numApplicationsFound,
                    NumAppsLoaded = numApplicationsLoaded
                });
            }

            OnApplicationCountUpdated(new ApplicationCountUpdatedEventArgs()
            {
                NumAppsFound  = numApplicationsFound,
                NumAppsLoaded = numApplicationsLoaded
            });

            if (_loadingError)
            {
                Gtk.Application.Invoke(delegate
                {
                    GtkDialog.CreateErrorDialog("One or more files encountered could not be loaded, check logs for more info.");
                });
            }
        }
예제 #13
0
파일: Updater.cs 프로젝트: ski982/Ryujinx-1
        public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
        {
            if (Running)
            {
                return;
            }

            Running = true;
            mainWindow.UpdateMenuItem.Sensitive = false;

            // Detect current platform
            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                _platformExt = "osx_x64.zip";
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                _platformExt = "win_x64.zip";
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                _platformExt = "linux_x64.tar.gz";
            }

            Version newVersion;
            Version currentVersion;

            try
            {
                currentVersion = Version.Parse(Program.Version);
            }
            catch
            {
                GtkDialog.CreateWarningDialog("Failed to convert the current Ryujinx version.", "Cancelling Update!");
                Logger.Error?.Print(LogClass.Application, "Failed to convert the current Ryujinx version!");

                return;
            }

            // Get latest version number from Appveyor
            try
            {
                using (WebClient jsonClient = new WebClient())
                {
                    string fetchedJson = await jsonClient.DownloadStringTaskAsync($"{AppveyorApiUrl}/projects/gdkchan/ryujinx/branch/master");

                    JObject jsonRoot   = JObject.Parse(fetchedJson);
                    JToken  buildToken = jsonRoot["build"];

                    _jobId    = (string)buildToken["jobs"][0]["jobId"];
                    _buildVer = (string)buildToken["version"];
                    _buildUrl = $"{AppveyorApiUrl}/buildjobs/{_jobId}/artifacts/ryujinx-{_buildVer}-{_platformExt}";

                    // If build not done, assume no new update are availaible.
                    if ((string)buildToken["jobs"][0]["status"] != "success")
                    {
                        if (showVersionUpToDate)
                        {
                            GtkDialog.CreateInfoDialog("Ryujinx - Updater", "You are already using the most updated version of Ryujinx!", "");
                        }

                        return;
                    }
                }
            }
            catch (Exception exception)
            {
                Logger.Error?.Print(LogClass.Application, exception.Message);
                GtkDialog.CreateErrorDialog("An error has occurred when trying to get release information from AppVeyor.");

                return;
            }

            try
            {
                newVersion = Version.Parse(_buildVer);
            }
            catch
            {
                GtkDialog.CreateWarningDialog("Failed to convert the received Ryujinx version from AppVeyor.", "Cancelling Update!");
                Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from AppVeyor!");

                return;
            }

            if (newVersion <= currentVersion)
            {
                if (showVersionUpToDate)
                {
                    GtkDialog.CreateInfoDialog("Ryujinx - Updater", "You are already using the most updated version of Ryujinx!", "");
                }

                Running = false;
                mainWindow.UpdateMenuItem.Sensitive = true;

                return;
            }

            // Show a message asking the user if they want to update
            UpdateDialog updateDialog = new UpdateDialog(mainWindow, newVersion, _buildUrl);

            updateDialog.Show();
        }
예제 #14
0
파일: Updater.cs 프로젝트: mailwl/Ryujinx
        public static async Task BeginParse(MainWindow mainWindow, bool showVersionUpToDate)
        {
            if (Running)
            {
                return;
            }

            Running = true;
            mainWindow.UpdateMenuItem.Sensitive = false;

            int artifactIndex = -1;

            // Detect current platform
            if (OperatingSystem.IsMacOS())
            {
                _platformExt  = "osx_x64.zip";
                artifactIndex = 1;
            }
            else if (OperatingSystem.IsWindows())
            {
                _platformExt  = "win_x64.zip";
                artifactIndex = 2;
            }
            else if (OperatingSystem.IsLinux())
            {
                _platformExt  = "linux_x64.tar.gz";
                artifactIndex = 0;
            }

            if (artifactIndex == -1)
            {
                GtkDialog.CreateErrorDialog("Your platform is not supported!");

                return;
            }

            Version newVersion;
            Version currentVersion;

            try
            {
                currentVersion = Version.Parse(Program.Version);
            }
            catch
            {
                GtkDialog.CreateWarningDialog("Failed to convert the current Ryujinx version.", "Cancelling Update!");
                Logger.Error?.Print(LogClass.Application, "Failed to convert the current Ryujinx version!");

                return;
            }

            // Get latest version number from Appveyor
            try
            {
                using (HttpClient jsonClient = new HttpClient())
                {
                    // Fetch latest build information
                    string fetchedJson = await jsonClient.GetStringAsync($"{AppveyorApiUrl}/projects/gdkchan/ryujinx/branch/master");

                    JObject jsonRoot   = JObject.Parse(fetchedJson);
                    JToken  buildToken = jsonRoot["build"];

                    _jobId    = (string)buildToken["jobs"][0]["jobId"];
                    _buildVer = (string)buildToken["version"];
                    _buildUrl = $"{AppveyorApiUrl}/buildjobs/{_jobId}/artifacts/ryujinx-{_buildVer}-{_platformExt}";

                    // If build not done, assume no new update are availaible.
                    if ((string)buildToken["jobs"][0]["status"] != "success")
                    {
                        if (showVersionUpToDate)
                        {
                            GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", "");
                        }

                        return;
                    }
                }
            }
            catch (Exception exception)
            {
                Logger.Error?.Print(LogClass.Application, exception.Message);
                GtkDialog.CreateErrorDialog("An error occurred when trying to get release information from AppVeyor. This can be caused if a new release is being compiled by AppVeyor. Try again in a few minutes.");

                return;
            }

            try
            {
                newVersion = Version.Parse(_buildVer);
            }
            catch
            {
                GtkDialog.CreateWarningDialog("Failed to convert the received Ryujinx version from AppVeyor.", "Cancelling Update!");
                Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from AppVeyor!");

                return;
            }

            if (newVersion <= currentVersion)
            {
                if (showVersionUpToDate)
                {
                    GtkDialog.CreateUpdaterInfoDialog("You are already using the latest version of Ryujinx!", "");
                }

                Running = false;
                mainWindow.UpdateMenuItem.Sensitive = true;

                return;
            }

            // Fetch build size information to learn chunk sizes.
            using (HttpClient buildSizeClient = new HttpClient())
            {
                try
                {
                    buildSizeClient.DefaultRequestHeaders.Add("Range", "bytes=0-0");

                    HttpResponseMessage message = await buildSizeClient.GetAsync(new Uri(_buildUrl), HttpCompletionOption.ResponseHeadersRead);

                    _buildSize = message.Content.Headers.ContentRange.Length.Value;
                }
                catch (Exception ex)
                {
                    Logger.Warning?.Print(LogClass.Application, ex.Message);
                    Logger.Warning?.Print(LogClass.Application, "Couldn't determine build size for update, using single-threaded updater");

                    _buildSize = -1;
                }
            }

            // Show a message asking the user if they want to update
            UpdateDialog updateDialog = new UpdateDialog(mainWindow, newVersion, _buildUrl);

            updateDialog.Show();
        }
예제 #15
0
        public static void BeginParse()
        {
            try
            {
                // Detect current platform

                if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
                {
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                    {
                        _platformExt = "osx_x64.zip";
                    }
                    else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        _platformExt = "win_x64.zip";
                    }
                    else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                    {
                        _platformExt = "linux_x64.tar.gz";
                    }
                }
                else
                {
                    Logger.PrintError(LogClass.Application, $"You are using an operating system architecture ({RuntimeInformation.ProcessArchitecture.ToString()}) not compatible with Ryujinx.");
                    GtkDialog.CreateErrorDialog($"You are using an operating system architecture ({RuntimeInformation.ProcessArchitecture.ToString()}) not compatible with Ryujinx.");

                    return;
                }

                // Begin the Appveyor parsing

                WebClient jsonClient  = new WebClient();
                string    fetchedJSON = jsonClient.DownloadString(_masterUrl);
                JObject   jsonRoot    = JObject.Parse(fetchedJSON);

                JToken _buildToken = jsonRoot["build"];

                _jobId    = (string)_buildToken["jobs"][0]["jobId"];
                _buildVer = (string)_buildToken["version"];
                _buildUrl = "https://ci.appveyor.com/api/buildjobs/" + _jobId + "/artifacts/ryujinx-" + _buildVer + "-" + _platformExt;

                if (!Directory.Exists(localAppPath))
                {
                    Directory.CreateDirectory(localAppPath);
                }

                // Get Version from app.config to compare versions

                Version newVersion     = Version.Parse(_buildVer);
                Version currentVersion = Version.Parse(ConfigurationManager.AppSettings["Version"]);

                if (newVersion < currentVersion)
                {
                    GtkDialog.CreateInfoDialog("Update", "Ryujinx - Updater", "You are already using the most updated version of Ryujinx!", "");

                    return;
                }

                // Show a message asking the user if they want to update

                using (MessageDialog dialog = GtkDialog.CreateAcceptDialog("Update", "Ryujinx - Update", "Would you like to update?", "Version " + _buildVer + " is available."))
                {
                    if (dialog.Run() == (int)ResponseType.Yes)
                    {
                        try
                        {
                            // Start Updater.exe

                            string updaterPath = Path.Combine(RyuDir, "Updater.exe");

                            ProcessStartInfo startInfo = new ProcessStartInfo(updaterPath);
                            startInfo.Arguments       = _buildUrl + " " + _buildVer;
                            startInfo.UseShellExecute = true;
                            Process.Start(startInfo);

                            Application.Quit();
                        }
                        catch (Exception ex)
                        {
                            GtkDialog.CreateErrorDialog(ex.Message);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.PrintError(LogClass.Application, ex.Message);
                GtkDialog.CreateErrorDialog("Update failed to grab or parse the information.\nPlease try at a later time, or report the error to our GitHub.");
            }
        }
예제 #16
0
파일: DlcWindow.cs 프로젝트: jms-c/Ryujinx
        private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetObject("_dlcWindow").Handle)
        {
            builder.Autoconnect(this);

            _titleId                 = titleId;
            _virtualFileSystem       = virtualFileSystem;
            _dlcJsonPath             = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "dlc.json");
            _baseTitleInfoLabel.Text = $"DLC Available for {titleName} [{titleId.ToUpper()}]";

            try
            {
                _dlcContainerList = JsonHelper.DeserializeFromFile <List <DlcContainer> >(_dlcJsonPath);
            }
            catch
            {
                _dlcContainerList = new List <DlcContainer>();
            }

            _dlcTreeView.Model = new TreeStore(typeof(bool), typeof(string), typeof(string));

            CellRendererToggle enableToggle = new CellRendererToggle();

            enableToggle.Toggled += (sender, args) =>
            {
                _dlcTreeView.Model.GetIter(out TreeIter treeIter, new TreePath(args.Path));
                bool newValue = !(bool)_dlcTreeView.Model.GetValue(treeIter, 0);
                _dlcTreeView.Model.SetValue(treeIter, 0, newValue);

                if (_dlcTreeView.Model.IterChildren(out TreeIter childIter, treeIter))
                {
                    do
                    {
                        _dlcTreeView.Model.SetValue(childIter, 0, newValue);
                    }while (_dlcTreeView.Model.IterNext(ref childIter));
                }
            };

            _dlcTreeView.AppendColumn("Enabled", enableToggle, "active", 0);
            _dlcTreeView.AppendColumn("TitleId", new CellRendererText(), "text", 1);
            _dlcTreeView.AppendColumn("Path", new CellRendererText(), "text", 2);

            int invalidDlcCount = 0;

            foreach (DlcContainer dlcContainer in _dlcContainerList)
            {
                if (!File.Exists(dlcContainer.Path))
                {
                    invalidDlcCount++;
                    continue; // skip invalid dlc (next save, no invalid dlc!)
                }

                TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(false, "", dlcContainer.Path);

                using FileStream containerFile = File.OpenRead(dlcContainer.Path);
                PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
                _virtualFileSystem.ImportTickets(pfs);

                foreach (DlcNca dlcNca in dlcContainer.DlcNcaList)
                {
                    pfs.OpenFile(out IFile ncaFile, dlcNca.Path.ToU8Span(), OpenMode.Read).ThrowIfFailure();
                    Nca nca = TryCreateNca(ncaFile.AsStorage(), dlcContainer.Path);

                    if (nca != null)
                    {
                        ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter, dlcNca.Enabled, nca.Header.TitleId.ToString("X16"), dlcNca.Path);
                    }
                }
            }

            if (invalidDlcCount > 0)
            {
                Logger.Error?.PrintMsg(LogClass.Application, "DLC files have been moved or deleted; skipping " + invalidDlcCount + " DLC files");
                GtkDialog.CreateErrorDialog(invalidDlcCount + " DLC files have been moved or deleted; please re-add your DLC.");
            }
        }
예제 #17
0
        private InputConfig GetValues()
        {
            if (_inputDevice.ActiveId.StartsWith("keyboard"))
            {
                Enum.TryParse(_lStickUp.Label, out Key lStickUp);
                Enum.TryParse(_lStickDown.Label, out Key lStickDown);
                Enum.TryParse(_lStickLeft.Label, out Key lStickLeft);
                Enum.TryParse(_lStickRight.Label, out Key lStickRight);
                Enum.TryParse(_lStickButton.Label, out Key lStickButton);
                Enum.TryParse(_dpadUp.Label, out Key lDPadUp);
                Enum.TryParse(_dpadDown.Label, out Key lDPadDown);
                Enum.TryParse(_dpadLeft.Label, out Key lDPadLeft);
                Enum.TryParse(_dpadRight.Label, out Key lDPadRight);
                Enum.TryParse(_minus.Label, out Key lButtonMinus);
                Enum.TryParse(_l.Label, out Key lButtonL);
                Enum.TryParse(_zL.Label, out Key lButtonZl);
                Enum.TryParse(_lSl.Label, out Key lButtonSl);
                Enum.TryParse(_lSr.Label, out Key lButtonSr);

                Enum.TryParse(_rStickUp.Label, out Key rStickUp);
                Enum.TryParse(_rStickDown.Label, out Key rStickDown);
                Enum.TryParse(_rStickLeft.Label, out Key rStickLeft);
                Enum.TryParse(_rStickRight.Label, out Key rStickRight);
                Enum.TryParse(_rStickButton.Label, out Key rStickButton);
                Enum.TryParse(_a.Label, out Key rButtonA);
                Enum.TryParse(_b.Label, out Key rButtonB);
                Enum.TryParse(_x.Label, out Key rButtonX);
                Enum.TryParse(_y.Label, out Key rButtonY);
                Enum.TryParse(_plus.Label, out Key rButtonPlus);
                Enum.TryParse(_r.Label, out Key rButtonR);
                Enum.TryParse(_zR.Label, out Key rButtonZr);
                Enum.TryParse(_rSl.Label, out Key rButtonSl);
                Enum.TryParse(_rSr.Label, out Key rButtonSr);

                int.TryParse(_dsuServerPort.Buffer.Text, out int port);

                return(new KeyboardConfig
                {
                    Index = int.Parse(_inputDevice.ActiveId.Split("/")[1]),
                    ControllerType = Enum.Parse <ControllerType>(_controllerType.ActiveId),
                    PlayerIndex = _playerIndex,
                    LeftJoycon = new NpadKeyboardLeft
                    {
                        StickUp = lStickUp,
                        StickDown = lStickDown,
                        StickLeft = lStickLeft,
                        StickRight = lStickRight,
                        StickButton = lStickButton,
                        DPadUp = lDPadUp,
                        DPadDown = lDPadDown,
                        DPadLeft = lDPadLeft,
                        DPadRight = lDPadRight,
                        ButtonMinus = lButtonMinus,
                        ButtonL = lButtonL,
                        ButtonZl = lButtonZl,
                        ButtonSl = lButtonSl,
                        ButtonSr = lButtonSr
                    },
                    RightJoycon = new NpadKeyboardRight
                    {
                        StickUp = rStickUp,
                        StickDown = rStickDown,
                        StickLeft = rStickLeft,
                        StickRight = rStickRight,
                        StickButton = rStickButton,
                        ButtonA = rButtonA,
                        ButtonB = rButtonB,
                        ButtonX = rButtonX,
                        ButtonY = rButtonY,
                        ButtonPlus = rButtonPlus,
                        ButtonR = rButtonR,
                        ButtonZr = rButtonZr,
                        ButtonSl = rButtonSl,
                        ButtonSr = rButtonSr
                    },
                    EnableMotion = _enableMotion.Active,
                    MirrorInput = _mirrorInput.Active,
                    Slot = (int)_slotNumber.Value,
                    AltSlot = (int)_altSlotNumber.Value,
                    Sensitivity = (int)_sensitivity.Value,
                    GyroDeadzone = _gyroDeadzone.Value,
                    DsuServerHost = _dsuServerHost.Buffer.Text,
                    DsuServerPort = port
                });
            }

            if (_inputDevice.ActiveId.StartsWith("controller"))
            {
                Enum.TryParse(_lStickX.Label, out ControllerInputId lStickX);
                Enum.TryParse(_lStickY.Label, out ControllerInputId lStickY);
                Enum.TryParse(_lStickButton.Label, out ControllerInputId lStickButton);
                Enum.TryParse(_minus.Label, out ControllerInputId lButtonMinus);
                Enum.TryParse(_l.Label, out ControllerInputId lButtonL);
                Enum.TryParse(_zL.Label, out ControllerInputId lButtonZl);
                Enum.TryParse(_lSl.Label, out ControllerInputId lButtonSl);
                Enum.TryParse(_lSr.Label, out ControllerInputId lButtonSr);
                Enum.TryParse(_dpadUp.Label, out ControllerInputId lDPadUp);
                Enum.TryParse(_dpadDown.Label, out ControllerInputId lDPadDown);
                Enum.TryParse(_dpadLeft.Label, out ControllerInputId lDPadLeft);
                Enum.TryParse(_dpadRight.Label, out ControllerInputId lDPadRight);

                Enum.TryParse(_rStickX.Label, out ControllerInputId rStickX);
                Enum.TryParse(_rStickY.Label, out ControllerInputId rStickY);
                Enum.TryParse(_rStickButton.Label, out ControllerInputId rStickButton);
                Enum.TryParse(_a.Label, out ControllerInputId rButtonA);
                Enum.TryParse(_b.Label, out ControllerInputId rButtonB);
                Enum.TryParse(_x.Label, out ControllerInputId rButtonX);
                Enum.TryParse(_y.Label, out ControllerInputId rButtonY);
                Enum.TryParse(_plus.Label, out ControllerInputId rButtonPlus);
                Enum.TryParse(_r.Label, out ControllerInputId rButtonR);
                Enum.TryParse(_zR.Label, out ControllerInputId rButtonZr);
                Enum.TryParse(_rSl.Label, out ControllerInputId rButtonSl);
                Enum.TryParse(_rSr.Label, out ControllerInputId rButtonSr);

                int.TryParse(_dsuServerPort.Buffer.Text, out int port);

                return(new ControllerConfig
                {
                    Index = int.Parse(_inputDevice.ActiveId.Split("/")[1]),
                    ControllerType = Enum.Parse <ControllerType>(_controllerType.ActiveId),
                    PlayerIndex = _playerIndex,
                    DeadzoneLeft = (float)_controllerDeadzoneLeft.Value,
                    DeadzoneRight = (float)_controllerDeadzoneRight.Value,
                    TriggerThreshold = (float)_controllerTriggerThreshold.Value,
                    LeftJoycon = new NpadControllerLeft
                    {
                        InvertStickX = _invertLStickX.Active,
                        StickX = lStickX,
                        InvertStickY = _invertLStickY.Active,
                        StickY = lStickY,
                        StickButton = lStickButton,
                        ButtonMinus = lButtonMinus,
                        ButtonL = lButtonL,
                        ButtonZl = lButtonZl,
                        ButtonSl = lButtonSl,
                        ButtonSr = lButtonSr,
                        DPadUp = lDPadUp,
                        DPadDown = lDPadDown,
                        DPadLeft = lDPadLeft,
                        DPadRight = lDPadRight
                    },
                    RightJoycon = new NpadControllerRight
                    {
                        InvertStickX = _invertRStickX.Active,
                        StickX = rStickX,
                        InvertStickY = _invertRStickY.Active,
                        StickY = rStickY,
                        StickButton = rStickButton,
                        ButtonA = rButtonA,
                        ButtonB = rButtonB,
                        ButtonX = rButtonX,
                        ButtonY = rButtonY,
                        ButtonPlus = rButtonPlus,
                        ButtonR = rButtonR,
                        ButtonZr = rButtonZr,
                        ButtonSl = rButtonSl,
                        ButtonSr = rButtonSr
                    },
                    EnableMotion = _enableMotion.Active,
                    MirrorInput = _mirrorInput.Active,
                    Slot = (int)_slotNumber.Value,
                    AltSlot = (int)_altSlotNumber.Value,
                    Sensitivity = (int)_sensitivity.Value,
                    GyroDeadzone = _gyroDeadzone.Value,
                    DsuServerHost = _dsuServerHost.Buffer.Text,
                    DsuServerPort = port
                });
            }

            if (!_inputDevice.ActiveId.StartsWith("disabled"))
            {
                GtkDialog.CreateErrorDialog("Some fields entered where invalid and therefore your config was not saved.");
            }

            return(null);
        }