mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-08-01 18:49:05 -06:00
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
4ee1dff497 | |||
b2a35ecf6c | |||
5f6d9eef6b | |||
40a488799e | |||
f9f037a951 |
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@ -7,6 +7,7 @@ on:
|
|||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '.github/**'
|
- '.github/**'
|
||||||
|
- 'docs/**'
|
||||||
- '*.yml'
|
- '*.yml'
|
||||||
- '*.json'
|
- '*.json'
|
||||||
- '*.config'
|
- '*.config'
|
||||||
|
57
README.md
57
README.md
@ -1,6 +1,6 @@
|
|||||||
<h1 align="center">
|
<h1 align="center">
|
||||||
<br>
|
<br>
|
||||||
<a href="https://ryujinx.org/"><img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx/master/distribution/misc/Logo.svg" alt="Ryujinx" width="150"></a>
|
<img src="https://raw.githubusercontent.com/GreemDev/Ryujinx/master/distribution/misc/Logo.svg" alt="Ryujinx" width="150"></a>
|
||||||
<br>
|
<br>
|
||||||
<b>Ryujinx</b>
|
<b>Ryujinx</b>
|
||||||
<br>
|
<br>
|
||||||
@ -9,29 +9,34 @@
|
|||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#.
|
Ryujinx is an open-source Nintendo Switch emulator, originally created by gdkchan, written in C#.
|
||||||
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
|
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
|
||||||
It was written from scratch and development on the project began in September 2017.
|
It was written from scratch and development on the project began in September 2017.
|
||||||
Ryujinx is available on Github under the <a href="https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt" target="_blank">MIT license</a>.
|
Ryujinx is available on Github under the <a href="https://github.com/GreemDev/Ryujinx/blob/master/LICENSE.txt" target="_blank">MIT license</a>.
|
||||||
<br />
|
<br />
|
||||||
</p>
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
On October 1st 2024, Ryujinx was discontinued as the creator was forced to abandon the project.
|
||||||
|
This fork is intended to be a direct continuation for existing Ryujinx users.
|
||||||
|
Guides and documentation will not be provided at this time, though you can find the old ones on the Internet Archive.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml">
|
<a href="https://github.com/GreemDev/Ryujinx/actions/workflows/release.yml">
|
||||||
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
|
<img src="https://github.com/GreemDev/Ryujinx/actions/workflows/release.yml/badge.svg"
|
||||||
alt="">
|
alt="">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://crwd.in/ryujinx">
|
<a href="https://crwd.in/ryujinx">
|
||||||
<img src="https://badges.crowdin.net/ryujinx/localized.svg"
|
<img src="https://badges.crowdin.net/ryujinx/localized.svg"
|
||||||
alt="">
|
alt="">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://discord.com/invite/VkQYXAZ">
|
<a href="https://discord.gg/dHPrkBkkyA">
|
||||||
<img src="https://img.shields.io/discord/410208534861447168?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
|
<img src="https://img.shields.io/discord/1294443224030511104?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
|
||||||
alt="Discord">
|
alt="Discord">
|
||||||
</a>
|
</a>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx-Website/master/public/assets/images/shell.png">
|
<img src="https://raw.githubusercontent.com/GreemDev/Ryujinx/refs/heads/master/docs/shell.png">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
@ -39,8 +44,6 @@
|
|||||||
As of May 2024, Ryujinx has been tested on approximately 4,300 titles;
|
As of May 2024, Ryujinx has been tested on approximately 4,300 titles;
|
||||||
over 4,100 boot past menus and into gameplay, with roughly 3,550 of those being considered playable.
|
over 4,100 boot past menus and into gameplay, with roughly 3,550 of those being considered playable.
|
||||||
|
|
||||||
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
|
|
||||||
|
|
||||||
Anyone is free to submit a new game test or update an existing game test entry;
|
Anyone is free to submit a new game test or update an existing game test entry;
|
||||||
simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue.
|
simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue.
|
||||||
Use the search function to see if a game has been tested already!
|
Use the search function to see if a game has been tested already!
|
||||||
@ -50,22 +53,11 @@ Use the search function to see if a game has been tested already!
|
|||||||
To run this emulator, your PC must be equipped with at least 8GiB of RAM;
|
To run this emulator, your PC must be equipped with at least 8GiB of RAM;
|
||||||
failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
|
failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
|
||||||
|
|
||||||
See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide) on how to set up the emulator.
|
|
||||||
|
|
||||||
For our Local Wireless (LDN) builds, see our [Multiplayer: Local Play/Local Wireless Guide
|
|
||||||
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
|
|
||||||
|
|
||||||
Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information.
|
|
||||||
|
|
||||||
## Latest build
|
## Latest build
|
||||||
|
|
||||||
These builds are compiled automatically for each commit on the master branch.
|
These builds are compiled automatically for each commit on the master branch.
|
||||||
While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken**.
|
While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken**.
|
||||||
|
|
||||||
If you want to see details on updates to the emulator, you can visit our [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog).
|
|
||||||
|
|
||||||
The latest automatic build for Windows, macOS, and Linux can be found on the [Official Website](https://ryujinx.org/download).
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
If you are planning to contribute or just want to learn more about this project please read through our [documentation](docs/README.md).
|
If you are planning to contribute or just want to learn more about this project please read through our [documentation](docs/README.md).
|
||||||
@ -81,7 +73,7 @@ Make sure your SDK version is higher or equal to the required version specified
|
|||||||
|
|
||||||
### Step 2
|
### Step 2
|
||||||
|
|
||||||
Either use `git clone https://github.com/Ryujinx/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
|
Either use `git clone https://github.com/GreemDev/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files.
|
||||||
|
|
||||||
### Step 3
|
### Step 3
|
||||||
|
|
||||||
@ -135,27 +127,6 @@ This folder is located in the user folder, which can be accessed by clicking `Op
|
|||||||
The emulator has settings for enabling or disabling some logging, remapping controllers, and more.
|
The emulator has settings for enabling or disabling some logging, remapping controllers, and more.
|
||||||
You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
|
You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
|
||||||
|
|
||||||
## Contact
|
|
||||||
|
|
||||||
If you have contributions, suggestions, need emulator support or just want to get in touch with the team, join our [Discord server](https://discord.com/invite/Ryujinx).
|
|
||||||
You may also review our [FAQ](https://github.com/Ryujinx/Ryujinx/wiki/Frequently-Asked-Questions).
|
|
||||||
|
|
||||||
## Donations
|
|
||||||
|
|
||||||
If you'd like to support the project financially, Ryujinx has an active Patreon campaign.
|
|
||||||
|
|
||||||
<a href="https://www.patreon.com/ryujinx">
|
|
||||||
<img src="https://images.squarespace-cdn.com/content/v1/560c1d39e4b0b4fae0c9cf2a/1567548955044-WVD994WZP76EWF15T0L3/Patreon+Button.png?format=500w" width="150">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
All developers working on the project do so in their free time, but the project has several expenses:
|
|
||||||
* Hackable Nintendo Switch consoles to reverse-engineer the hardware
|
|
||||||
* Additional computer hardware for testing purposes (e.g. GPUs to diagnose graphical bugs, etc.)
|
|
||||||
* Licenses for various software development tools (e.g. Jetbrains, IDA)
|
|
||||||
* Web hosting and infrastructure maintenance (e.g. LDN servers)
|
|
||||||
|
|
||||||
All funds received through Patreon are considered a donation to support the project. Patrons receive early access to progress reports and exclusive access to developer interviews.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This software is licensed under the terms of the [MIT license](LICENSE.txt).
|
This software is licensed under the terms of the [MIT license](LICENSE.txt).
|
||||||
|
BIN
docs/shell.png
Normal file
BIN
docs/shell.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 905 KiB |
@ -492,7 +492,7 @@ namespace Ryujinx.Common.Collections
|
|||||||
Start = start;
|
Start = start;
|
||||||
End = end;
|
End = end;
|
||||||
Max = end;
|
Max = end;
|
||||||
Values = new List<RangeNode<TKey, TValue>> { new RangeNode<TKey, TValue>(start, end, value) };
|
Values = [ new RangeNode<TKey, TValue>(start, end, value) ];
|
||||||
Parent = parent;
|
Parent = parent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,8 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
|
|
||||||
public bool TextProcessingEnabled
|
public bool TextProcessingEnabled
|
||||||
{
|
{
|
||||||
get
|
get => Volatile.Read(ref _canProcessInput);
|
||||||
{
|
|
||||||
return Volatile.Read(ref _canProcessInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Volatile.Write(ref _canProcessInput, value);
|
Volatile.Write(ref _canProcessInput, value);
|
||||||
|
@ -10,6 +10,7 @@ using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationPr
|
|||||||
using Ryujinx.HLE.UI;
|
using Ryujinx.HLE.UI;
|
||||||
using Ryujinx.Input;
|
using Ryujinx.Input;
|
||||||
using Ryujinx.Input.HLE;
|
using Ryujinx.Input.HLE;
|
||||||
|
using Ryujinx.Input.SDL2;
|
||||||
using Ryujinx.SDL2.Common;
|
using Ryujinx.SDL2.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
@ -12,7 +12,10 @@ namespace Ryujinx.Input.SDL2
|
|||||||
{
|
{
|
||||||
private bool HasConfiguration => _configuration != null;
|
private bool HasConfiguration => _configuration != null;
|
||||||
|
|
||||||
private record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From);
|
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
|
||||||
|
{
|
||||||
|
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
|
||||||
|
}
|
||||||
|
|
||||||
private StandardControllerInputConfig _configuration;
|
private StandardControllerInputConfig _configuration;
|
||||||
|
|
||||||
@ -144,86 +147,64 @@ namespace Ryujinx.Input.SDL2
|
|||||||
|
|
||||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
|
||||||
{
|
{
|
||||||
if (Features.HasFlag(GamepadFeaturesFlag.Rumble))
|
if (!Features.HasFlag(GamepadFeaturesFlag.Rumble)) return;
|
||||||
{
|
|
||||||
ushort lowFrequencyRaw = (ushort)(lowFrequency * ushort.MaxValue);
|
|
||||||
ushort highFrequencyRaw = (ushort)(highFrequency * ushort.MaxValue);
|
|
||||||
|
|
||||||
if (durationMs == uint.MaxValue)
|
ushort lowFrequencyRaw = (ushort)(lowFrequency * ushort.MaxValue);
|
||||||
{
|
ushort highFrequencyRaw = (ushort)(highFrequency * ushort.MaxValue);
|
||||||
if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, SDL_HAPTIC_INFINITY) != 0)
|
|
||||||
{
|
if (durationMs == uint.MaxValue)
|
||||||
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
{
|
||||||
}
|
if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, SDL_HAPTIC_INFINITY) != 0)
|
||||||
}
|
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
||||||
else if (durationMs > SDL_HAPTIC_INFINITY)
|
}
|
||||||
{
|
else if (durationMs > SDL_HAPTIC_INFINITY)
|
||||||
Logger.Error?.Print(LogClass.Hid, $"Unsupported rumble duration {durationMs}");
|
{
|
||||||
}
|
Logger.Error?.Print(LogClass.Hid, $"Unsupported rumble duration {durationMs}");
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs) != 0)
|
{
|
||||||
{
|
if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs) != 0)
|
||||||
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 GetMotionData(MotionInputId inputId)
|
public Vector3 GetMotionData(MotionInputId inputId)
|
||||||
{
|
{
|
||||||
SDL_SensorType sensorType = SDL_SensorType.SDL_SENSOR_INVALID;
|
SDL_SensorType sensorType = inputId switch
|
||||||
|
|
||||||
if (inputId == MotionInputId.Accelerometer)
|
|
||||||
{
|
{
|
||||||
sensorType = SDL_SensorType.SDL_SENSOR_ACCEL;
|
MotionInputId.Accelerometer => SDL_SensorType.SDL_SENSOR_ACCEL,
|
||||||
}
|
MotionInputId.Gyroscope => SDL_SensorType.SDL_SENSOR_GYRO,
|
||||||
else if (inputId == MotionInputId.Gyroscope)
|
_ => SDL_SensorType.SDL_SENSOR_INVALID
|
||||||
{
|
};
|
||||||
sensorType = SDL_SensorType.SDL_SENSOR_GYRO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Features.HasFlag(GamepadFeaturesFlag.Motion) && sensorType != SDL_SensorType.SDL_SENSOR_INVALID)
|
if (!Features.HasFlag(GamepadFeaturesFlag.Motion) || sensorType is SDL_SensorType.SDL_SENSOR_INVALID)
|
||||||
{
|
return Vector3.Zero;
|
||||||
const int ElementCount = 3;
|
|
||||||
|
|
||||||
unsafe
|
const int ElementCount = 3;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
float* values = stackalloc float[ElementCount];
|
||||||
|
|
||||||
|
int result = SDL_GameControllerGetSensorData(_gamepadHandle, sensorType, (IntPtr)values, ElementCount);
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
|
return Vector3.Zero;
|
||||||
|
|
||||||
|
Vector3 value = new(values[0], values[1], values[2]);
|
||||||
|
|
||||||
|
return inputId switch
|
||||||
{
|
{
|
||||||
float* values = stackalloc float[ElementCount];
|
MotionInputId.Gyroscope => RadToDegree(value),
|
||||||
|
MotionInputId.Accelerometer => GsToMs2(value),
|
||||||
int result = SDL_GameControllerGetSensorData(_gamepadHandle, sensorType, (IntPtr)values, ElementCount);
|
_ => value
|
||||||
|
};
|
||||||
if (result == 0)
|
|
||||||
{
|
|
||||||
Vector3 value = new(values[0], values[1], values[2]);
|
|
||||||
|
|
||||||
if (inputId == MotionInputId.Gyroscope)
|
|
||||||
{
|
|
||||||
return RadToDegree(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputId == MotionInputId.Accelerometer)
|
|
||||||
{
|
|
||||||
return GsToMs2(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Vector3.Zero;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Vector3 RadToDegree(Vector3 rad)
|
private static Vector3 RadToDegree(Vector3 rad) => rad * (180 / MathF.PI);
|
||||||
{
|
|
||||||
return rad * (180 / MathF.PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Vector3 GsToMs2(Vector3 gs)
|
private static Vector3 GsToMs2(Vector3 gs) => gs / SDL_STANDARD_GRAVITY;
|
||||||
{
|
|
||||||
return gs / SDL_STANDARD_GRAVITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetConfiguration(InputConfig configuration)
|
public void SetConfiguration(InputConfig configuration)
|
||||||
{
|
{
|
||||||
@ -278,16 +259,13 @@ namespace Ryujinx.Input.SDL2
|
|||||||
lock (_userMappingLock)
|
lock (_userMappingLock)
|
||||||
{
|
{
|
||||||
if (_buttonsUserMapping.Count == 0)
|
if (_buttonsUserMapping.Count == 0)
|
||||||
{
|
|
||||||
return rawState;
|
return rawState;
|
||||||
}
|
|
||||||
|
|
||||||
|
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
|
||||||
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
|
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
|
||||||
{
|
{
|
||||||
if (entry.From == GamepadButtonInputId.Unbound || entry.To == GamepadButtonInputId.Unbound)
|
if (!entry.IsValid) continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not touch state of button already pressed
|
// Do not touch state of button already pressed
|
||||||
if (!result.IsPressed(entry.To))
|
if (!result.IsPressed(entry.To))
|
||||||
@ -316,9 +294,8 @@ namespace Ryujinx.Input.SDL2
|
|||||||
public (float, float) GetStick(StickInputId inputId)
|
public (float, float) GetStick(StickInputId inputId)
|
||||||
{
|
{
|
||||||
if (inputId == StickInputId.Unbound)
|
if (inputId == StickInputId.Unbound)
|
||||||
{
|
|
||||||
return (0.0f, 0.0f);
|
return (0.0f, 0.0f);
|
||||||
}
|
|
||||||
|
|
||||||
(short stickX, short stickY) = GetStickXY(inputId);
|
(short stickX, short stickY) = GetStickXY(inputId);
|
||||||
|
|
||||||
@ -351,6 +328,7 @@ namespace Ryujinx.Input.SDL2
|
|||||||
return (resultX, resultY);
|
return (resultX, resultY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
private (short, short) GetStickXY(StickInputId inputId) =>
|
private (short, short) GetStickXY(StickInputId inputId) =>
|
||||||
inputId switch
|
inputId switch
|
||||||
{
|
{
|
||||||
@ -365,14 +343,12 @@ namespace Ryujinx.Input.SDL2
|
|||||||
|
|
||||||
public bool IsPressed(GamepadButtonInputId inputId)
|
public bool IsPressed(GamepadButtonInputId inputId)
|
||||||
{
|
{
|
||||||
if (inputId == GamepadButtonInputId.LeftTrigger)
|
switch (inputId)
|
||||||
{
|
{
|
||||||
return ConvertRawStickValue(SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT)) > _triggerThreshold;
|
case GamepadButtonInputId.LeftTrigger:
|
||||||
}
|
return ConvertRawStickValue(SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERLEFT)) > _triggerThreshold;
|
||||||
|
case GamepadButtonInputId.RightTrigger:
|
||||||
if (inputId == GamepadButtonInputId.RightTrigger)
|
return ConvertRawStickValue(SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) > _triggerThreshold;
|
||||||
{
|
|
||||||
return ConvertRawStickValue(SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_TRIGGERRIGHT)) > _triggerThreshold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_buttonsDriverMapping[(int)inputId] == SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_INVALID)
|
if (_buttonsDriverMapping[(int)inputId] == SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_INVALID)
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Input;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Ryujinx.Headless.SDL2
|
namespace Ryujinx.Input.SDL2
|
||||||
{
|
{
|
||||||
class SDL2Mouse : IMouse
|
public class SDL2Mouse : IMouse
|
||||||
{
|
{
|
||||||
private SDL2MouseDriver _driver;
|
private SDL2MouseDriver _driver;
|
||||||
|
|
@ -1,6 +1,5 @@
|
|||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Input;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
@ -8,9 +7,9 @@ using System.Numerics;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using static SDL2.SDL;
|
using static SDL2.SDL;
|
||||||
|
|
||||||
namespace Ryujinx.Headless.SDL2
|
namespace Ryujinx.Input.SDL2
|
||||||
{
|
{
|
||||||
class SDL2MouseDriver : IGamepadDriver
|
public class SDL2MouseDriver : IGamepadDriver
|
||||||
{
|
{
|
||||||
private const int CursorHideIdleTime = 5; // seconds
|
private const int CursorHideIdleTime = 5; // seconds
|
||||||
|
|
||||||
@ -44,7 +43,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static MouseButton DriverButtonToMouseButton(uint rawButton)
|
private static MouseButton DriverButtonToMouseButton(uint rawButton)
|
||||||
{
|
{
|
||||||
Debug.Assert(rawButton > 0 && rawButton <= (int)MouseButton.Count);
|
Debug.Assert(rawButton is > 0 and <= (int)MouseButton.Count);
|
||||||
|
|
||||||
return (MouseButton)(rawButton - 1);
|
return (MouseButton)(rawButton - 1);
|
||||||
}
|
}
|
@ -143,7 +143,7 @@ namespace Ryujinx.SDL2.Common
|
|||||||
|
|
||||||
OnJoystickDisconnected?.Invoke(evnt.cbutton.which);
|
OnJoystickDisconnected?.Invoke(evnt.cbutton.which);
|
||||||
}
|
}
|
||||||
else if (evnt.type == SDL_EventType.SDL_WINDOWEVENT || evnt.type == SDL_EventType.SDL_MOUSEBUTTONDOWN || evnt.type == SDL_EventType.SDL_MOUSEBUTTONUP)
|
else if (evnt.type is SDL_EventType.SDL_WINDOWEVENT or SDL_EventType.SDL_MOUSEBUTTONDOWN or SDL_EventType.SDL_MOUSEBUTTONUP)
|
||||||
{
|
{
|
||||||
if (_registeredWindowHandlers.TryGetValue(evnt.window.windowID, out Action<SDL_Event> handler))
|
if (_registeredWindowHandlers.TryGetValue(evnt.window.windowID, out Action<SDL_Event> handler))
|
||||||
{
|
{
|
||||||
|
@ -8,10 +8,8 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
public static string ActiveApplicationTitle(ProcessResult activeProcess, string applicationVersion, string pauseString = "")
|
public static string ActiveApplicationTitle(ProcessResult activeProcess, string applicationVersion, string pauseString = "")
|
||||||
{
|
{
|
||||||
if (activeProcess == null)
|
if (activeProcess == null)
|
||||||
{
|
return string.Empty;
|
||||||
return String.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
string titleNameSection = string.IsNullOrWhiteSpace(activeProcess.Name) ? string.Empty : $" {activeProcess.Name}";
|
string titleNameSection = string.IsNullOrWhiteSpace(activeProcess.Name) ? string.Empty : $" {activeProcess.Name}";
|
||||||
string titleVersionSection = string.IsNullOrWhiteSpace(activeProcess.DisplayVersion) ? string.Empty : $" v{activeProcess.DisplayVersion}";
|
string titleVersionSection = string.IsNullOrWhiteSpace(activeProcess.DisplayVersion) ? string.Empty : $" v{activeProcess.DisplayVersion}";
|
||||||
string titleIdSection = $" ({activeProcess.ProgramIdText.ToUpper()})";
|
string titleIdSection = $" ({activeProcess.ProgramIdText.ToUpper()})";
|
||||||
@ -19,12 +17,9 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
|
|
||||||
string appTitle = $"Ryujinx {applicationVersion} -{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
|
string appTitle = $"Ryujinx {applicationVersion} -{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(pauseString))
|
return !string.IsNullOrEmpty(pauseString)
|
||||||
{
|
? appTitle + $" ({pauseString})"
|
||||||
appTitle += $" ({pauseString})";
|
: appTitle;
|
||||||
}
|
|
||||||
|
|
||||||
return appTitle;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,14 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
public class App : Application
|
public class App : Application
|
||||||
{
|
{
|
||||||
|
internal static string FormatTitle(LocaleKeys? windowTitleKey = null)
|
||||||
|
=> windowTitleKey is null
|
||||||
|
? $"Ryujinx {Program.Version}"
|
||||||
|
: $"Ryujinx {Program.Version} - {LocaleManager.Instance[windowTitleKey.Value]}";
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
Name = $"Ryujinx {Program.Version}";
|
Name = FormatTitle();
|
||||||
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
|
||||||
|
@ -1705,7 +1705,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(() =>
|
Dispatcher.UIThread.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
Title = $"Ryujinx {Program.Version}";
|
Title = App.FormatTitle();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.Amiibo];
|
Title = App.FormatTitle(LocaleKeys.Amiibo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AmiiboWindow()
|
public AmiiboWindow()
|
||||||
@ -31,7 +31,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
if (Program.PreviewerDetached)
|
if (Program.PreviewerDetached)
|
||||||
{
|
{
|
||||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.Amiibo];
|
Title = App.FormatTitle(LocaleKeys.Amiibo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.CheatWindowTitle];
|
Title = App.FormatTitle(LocaleKeys.CheatWindowTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CheatWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName, string titlePath)
|
public CheatWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName, string titlePath)
|
||||||
@ -95,7 +95,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
DataContext = this;
|
DataContext = this;
|
||||||
|
|
||||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.CheatWindowTitle];
|
Title = App.FormatTitle(LocaleKeys.CheatWindowTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save()
|
public void Save()
|
||||||
|
@ -79,7 +79,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
UiHandler = new AvaHostUIHandler(this);
|
UiHandler = new AvaHostUIHandler(this);
|
||||||
|
|
||||||
ViewModel.Title = $"Ryujinx {Program.Version}";
|
ViewModel.Title = App.FormatTitle();
|
||||||
|
|
||||||
// NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point.
|
// NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point.
|
||||||
StatusBarHeight = StatusBarView.StatusBar.MinHeight;
|
StatusBarHeight = StatusBarView.StatusBar.MinHeight;
|
||||||
|
@ -14,7 +14,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
|
public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
|
||||||
{
|
{
|
||||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.Settings]}";
|
Title = App.FormatTitle(LocaleKeys.Settings);
|
||||||
|
|
||||||
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager);
|
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager);
|
||||||
DataContext = ViewModel;
|
DataContext = ViewModel;
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using Avalonia;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
@ -64,21 +62,14 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
private void OpenLocation(object sender, RoutedEventArgs e)
|
private void OpenLocation(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is Button button)
|
if (sender is Button { DataContext: TitleUpdateModel model })
|
||||||
{
|
OpenHelper.LocateFile(model.Path);
|
||||||
if (button.DataContext is TitleUpdateModel model)
|
|
||||||
{
|
|
||||||
OpenHelper.LocateFile(model.Path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveUpdate(object sender, RoutedEventArgs e)
|
private void RemoveUpdate(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is Button button)
|
if (sender is Button { DataContext: TitleUpdateModel model })
|
||||||
{
|
ViewModel.RemoveUpdate(model);
|
||||||
ViewModel.RemoveUpdate((TitleUpdateModel)button.DataContext);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveAll(object sender, RoutedEventArgs e)
|
private void RemoveAll(object sender, RoutedEventArgs e)
|
||||||
|
Reference in New Issue
Block a user