2022-07-05 20:06:31 +02:00
using Avalonia.Collections ;
using Avalonia.Controls ;
using Avalonia.Controls.ApplicationLifetimes ;
using Avalonia.Svg.Skia ;
using Avalonia.Threading ;
using Ryujinx.Ava.Common.Locale ;
using Ryujinx.Ava.Input ;
2022-12-29 15:24:05 +01:00
using Ryujinx.Ava.UI.Helpers ;
using Ryujinx.Ava.UI.Models ;
using Ryujinx.Ava.UI.Windows ;
2022-07-05 20:06:31 +02:00
using Ryujinx.Common ;
using Ryujinx.Common.Configuration ;
using Ryujinx.Common.Configuration.Hid ;
using Ryujinx.Common.Configuration.Hid.Controller ;
using Ryujinx.Common.Configuration.Hid.Controller.Motion ;
using Ryujinx.Common.Configuration.Hid.Keyboard ;
using Ryujinx.Common.Logging ;
using Ryujinx.Common.Utilities ;
using Ryujinx.Input ;
using Ryujinx.Ui.Common.Configuration ;
using System ;
using System.Collections.Generic ;
using System.Collections.ObjectModel ;
using System.IO ;
using System.Linq ;
using System.Text.Json ;
using ConfigGamepadInputId = Ryujinx . Common . Configuration . Hid . Controller . GamepadInputId ;
using ConfigStickInputId = Ryujinx . Common . Configuration . Hid . Controller . StickInputId ;
using Key = Ryujinx . Common . Configuration . Hid . Key ;
2022-12-29 15:24:05 +01:00
namespace Ryujinx.Ava.UI.ViewModels
2022-07-05 20:06:31 +02:00
{
public class ControllerSettingsViewModel : BaseModel , IDisposable
{
private const string Disabled = "disabled" ;
private const string ProControllerResource = "Ryujinx.Ui.Common/Resources/Controller_ProCon.svg" ;
private const string JoyConPairResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConPair.svg" ;
private const string JoyConLeftResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConLeft.svg" ;
private const string JoyConRightResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConRight.svg" ;
private const string KeyboardString = "keyboard" ;
private const string ControllerString = "controller" ;
private readonly MainWindow _mainWindow ;
private PlayerIndex _playerId ;
private int _controller ;
2022-09-19 21:04:22 +02:00
private int _controllerNumber = 0 ;
2022-07-05 20:06:31 +02:00
private string _controllerImage ;
private int _device ;
private object _configuration ;
private string _profileName ;
private bool _isLoaded ;
private readonly UserControl _owner ;
2023-03-21 23:41:19 +01:00
private static readonly InputConfigJsonSerializerContext SerializerContext = new ( JsonHelper . GetDefaultSerializerOptions ( ) ) ;
2022-07-05 20:06:31 +02:00
public IGamepadDriver AvaloniaKeyboardDriver { get ; }
public IGamepad SelectedGamepad { get ; private set ; }
public ObservableCollection < PlayerModel > PlayerIndexes { get ; set ; }
public ObservableCollection < ( DeviceType Type , string Id , string Name ) > Devices { get ; set ; }
internal ObservableCollection < ControllerModel > Controllers { get ; set ; }
public AvaloniaList < string > ProfilesList { get ; set ; }
public AvaloniaList < string > DeviceList { get ; set ; }
// XAML Flags
public bool ShowSettings = > _device > 0 ;
public bool IsController = > _device > 1 ;
public bool IsKeyboard = > ! IsController ;
public bool IsRight { get ; set ; }
public bool IsLeft { get ; set ; }
public bool IsModified { get ; set ; }
public object Configuration
{
get = > _configuration ;
set
{
_configuration = value ;
OnPropertyChanged ( ) ;
}
}
public PlayerIndex PlayerId
{
get = > _playerId ;
set
{
if ( IsModified )
{
return ;
}
IsModified = false ;
_playerId = value ;
if ( ! Enum . IsDefined ( typeof ( PlayerIndex ) , _playerId ) )
{
_playerId = PlayerIndex . Player1 ;
}
LoadConfiguration ( ) ;
LoadDevice ( ) ;
LoadProfiles ( ) ;
_isLoaded = true ;
OnPropertyChanged ( ) ;
}
}
public int Controller
{
get = > _controller ;
set
{
_controller = value ;
if ( _controller = = - 1 )
{
_controller = 0 ;
}
if ( Controllers . Count > 0 & & value < Controllers . Count & & _controller > - 1 )
{
ControllerType controller = Controllers [ _controller ] . Type ;
IsLeft = true ;
IsRight = true ;
switch ( controller )
{
case ControllerType . Handheld :
ControllerImage = JoyConPairResource ;
break ;
case ControllerType . ProController :
ControllerImage = ProControllerResource ;
break ;
case ControllerType . JoyconPair :
ControllerImage = JoyConPairResource ;
break ;
case ControllerType . JoyconLeft :
ControllerImage = JoyConLeftResource ;
IsRight = false ;
break ;
case ControllerType . JoyconRight :
ControllerImage = JoyConRightResource ;
IsLeft = false ;
break ;
}
LoadInputDriver ( ) ;
LoadProfiles ( ) ;
}
OnPropertyChanged ( ) ;
NotifyChanges ( ) ;
}
}
public string ControllerImage
{
get = > _controllerImage ;
set
{
_controllerImage = value ;
OnPropertyChanged ( ) ;
OnPropertyChanged ( nameof ( Image ) ) ;
}
}
public SvgImage Image
{
get
{
SvgImage image = new SvgImage ( ) ;
if ( ! string . IsNullOrWhiteSpace ( _controllerImage ) )
{
SvgSource source = new SvgSource ( ) ;
source . Load ( EmbeddedResources . GetStream ( _controllerImage ) ) ;
image . Source = source ;
}
return image ;
}
}
public string ProfileName
{
get = > _profileName ; set
{
_profileName = value ;
OnPropertyChanged ( ) ;
}
}
public int Device
{
get = > _device ;
set
{
_device = value < 0 ? 0 : value ;
if ( _device > = Devices . Count )
{
return ;
}
var selected = Devices [ _device ] . Type ;
if ( selected ! = DeviceType . None )
{
LoadControllers ( ) ;
if ( _isLoaded )
{
LoadConfiguration ( LoadDefaultConfiguration ( ) ) ;
}
}
OnPropertyChanged ( ) ;
NotifyChanges ( ) ;
}
}
public InputConfig Config { get ; set ; }
public ControllerSettingsViewModel ( UserControl owner ) : this ( )
{
_owner = owner ;
if ( Program . PreviewerDetached )
{
_mainWindow =
( MainWindow ) ( ( IClassicDesktopStyleApplicationLifetime ) Avalonia . Application . Current
. ApplicationLifetime ) . MainWindow ;
AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver ( owner ) ;
_mainWindow . InputManager . GamepadDriver . OnGamepadConnected + = HandleOnGamepadConnected ;
_mainWindow . InputManager . GamepadDriver . OnGamepadDisconnected + = HandleOnGamepadDisconnected ;
2023-01-08 18:46:25 +01:00
if ( _mainWindow . ViewModel . AppHost ! = null )
2022-07-05 20:06:31 +02:00
{
2023-01-08 18:46:25 +01:00
_mainWindow . ViewModel . AppHost . NpadManager . BlockInputUpdates ( ) ;
2022-07-05 20:06:31 +02:00
}
_isLoaded = false ;
LoadDevices ( ) ;
PlayerId = PlayerIndex . Player1 ;
}
}
public ControllerSettingsViewModel ( )
{
PlayerIndexes = new ObservableCollection < PlayerModel > ( ) ;
Controllers = new ObservableCollection < ControllerModel > ( ) ;
Devices = new ObservableCollection < ( DeviceType Type , string Id , string Name ) > ( ) ;
ProfilesList = new AvaloniaList < string > ( ) ;
DeviceList = new AvaloniaList < string > ( ) ;
ControllerImage = ProControllerResource ;
2023-01-03 19:45:08 +01:00
PlayerIndexes . Add ( new ( PlayerIndex . Player1 , LocaleManager . Instance [ LocaleKeys . ControllerSettingsPlayer1 ] ) ) ;
PlayerIndexes . Add ( new ( PlayerIndex . Player2 , LocaleManager . Instance [ LocaleKeys . ControllerSettingsPlayer2 ] ) ) ;
PlayerIndexes . Add ( new ( PlayerIndex . Player3 , LocaleManager . Instance [ LocaleKeys . ControllerSettingsPlayer3 ] ) ) ;
PlayerIndexes . Add ( new ( PlayerIndex . Player4 , LocaleManager . Instance [ LocaleKeys . ControllerSettingsPlayer4 ] ) ) ;
PlayerIndexes . Add ( new ( PlayerIndex . Player5 , LocaleManager . Instance [ LocaleKeys . ControllerSettingsPlayer5 ] ) ) ;
PlayerIndexes . Add ( new ( PlayerIndex . Player6 , LocaleManager . Instance [ LocaleKeys . ControllerSettingsPlayer6 ] ) ) ;
PlayerIndexes . Add ( new ( PlayerIndex . Player7 , LocaleManager . Instance [ LocaleKeys . ControllerSettingsPlayer7 ] ) ) ;
PlayerIndexes . Add ( new ( PlayerIndex . Player8 , LocaleManager . Instance [ LocaleKeys . ControllerSettingsPlayer8 ] ) ) ;
PlayerIndexes . Add ( new ( PlayerIndex . Handheld , LocaleManager . Instance [ LocaleKeys . ControllerSettingsHandheld ] ) ) ;
2022-07-05 20:06:31 +02:00
}
private void LoadConfiguration ( InputConfig inputConfig = null )
{
Config = inputConfig ? ? ConfigurationState . Instance . Hid . InputConfig . Value . Find ( inputConfig = > inputConfig . PlayerIndex = = _playerId ) ;
if ( Config is StandardKeyboardInputConfig keyboardInputConfig )
{
Configuration = new InputConfiguration < Key , ConfigStickInputId > ( keyboardInputConfig ) ;
}
if ( Config is StandardControllerInputConfig controllerInputConfig )
{
Configuration = new InputConfiguration < ConfigGamepadInputId , ConfigStickInputId > ( controllerInputConfig ) ;
}
}
public void LoadDevice ( )
{
if ( Config = = null | | Config . Backend = = InputBackendType . Invalid )
{
Device = 0 ;
}
else
{
var type = DeviceType . None ;
if ( Config is StandardKeyboardInputConfig )
{
type = DeviceType . Keyboard ;
}
if ( Config is StandardControllerInputConfig )
{
type = DeviceType . Controller ;
}
var item = Devices . FirstOrDefault ( x = > x . Type = = type & & x . Id = = Config . Id ) ;
if ( item ! = default )
{
Device = Devices . ToList ( ) . FindIndex ( x = > x . Id = = item . Id ) ;
}
else
{
Device = 0 ;
}
}
}
public async void ShowMotionConfig ( )
{
2022-07-24 19:38:38 +02:00
await MotionSettingsWindow . Show ( this ) ;
2022-07-05 20:06:31 +02:00
}
public async void ShowRumbleConfig ( )
{
2022-07-24 19:38:38 +02:00
await RumbleSettingsWindow . Show ( this ) ;
2022-07-05 20:06:31 +02:00
}
private void LoadInputDriver ( )
{
if ( _device < 0 )
{
return ;
}
string id = GetCurrentGamepadId ( ) ;
var type = Devices [ Device ] . Type ;
if ( type = = DeviceType . None )
{
return ;
}
else if ( type = = DeviceType . Keyboard )
{
if ( _mainWindow . InputManager . KeyboardDriver is AvaloniaKeyboardDriver )
{
// NOTE: To get input in this window, we need to bind a custom keyboard driver instead of using the InputManager one as the main window isn't focused...
SelectedGamepad = AvaloniaKeyboardDriver . GetGamepad ( id ) ;
}
else
{
SelectedGamepad = _mainWindow . InputManager . KeyboardDriver . GetGamepad ( id ) ;
}
}
else
{
SelectedGamepad = _mainWindow . InputManager . GamepadDriver . GetGamepad ( id ) ;
}
}
private void HandleOnGamepadDisconnected ( string id )
{
Dispatcher . UIThread . Post ( ( ) = >
{
LoadDevices ( ) ;
} ) ;
}
private void HandleOnGamepadConnected ( string id )
{
Dispatcher . UIThread . Post ( ( ) = >
{
LoadDevices ( ) ;
} ) ;
}
private string GetCurrentGamepadId ( )
{
if ( _device < 0 )
{
return string . Empty ;
}
var device = Devices [ Device ] ;
if ( device . Type = = DeviceType . None )
{
return null ;
}
return device . Id . Split ( " " ) [ 0 ] ;
}
public void LoadControllers ( )
{
Controllers . Clear ( ) ;
if ( _playerId = = PlayerIndex . Handheld )
{
2023-01-03 19:45:08 +01:00
Controllers . Add ( new ( ControllerType . Handheld , LocaleManager . Instance [ LocaleKeys . ControllerSettingsControllerTypeHandheld ] ) ) ;
2022-07-05 20:06:31 +02:00
Controller = 0 ;
}
else
{
2023-01-03 19:45:08 +01:00
Controllers . Add ( new ( ControllerType . ProController , LocaleManager . Instance [ LocaleKeys . ControllerSettingsControllerTypeProController ] ) ) ;
Controllers . Add ( new ( ControllerType . JoyconPair , LocaleManager . Instance [ LocaleKeys . ControllerSettingsControllerTypeJoyConPair ] ) ) ;
Controllers . Add ( new ( ControllerType . JoyconLeft , LocaleManager . Instance [ LocaleKeys . ControllerSettingsControllerTypeJoyConLeft ] ) ) ;
Controllers . Add ( new ( ControllerType . JoyconRight , LocaleManager . Instance [ LocaleKeys . ControllerSettingsControllerTypeJoyConRight ] ) ) ;
2022-07-05 20:06:31 +02:00
if ( Config ! = null & & Controllers . ToList ( ) . FindIndex ( x = > x . Type = = Config . ControllerType ) ! = - 1 )
{
Controller = Controllers . ToList ( ) . FindIndex ( x = > x . Type = = Config . ControllerType ) ;
}
else
{
Controller = 0 ;
}
}
}
private static string GetShortGamepadName ( string str )
{
const string Ellipsis = "..." ;
const int MaxSize = 50 ;
if ( str . Length > MaxSize )
{
2023-01-18 23:25:16 +01:00
return $"{str.AsSpan(0, MaxSize - Ellipsis.Length)}{Ellipsis}" ;
2022-07-05 20:06:31 +02:00
}
return str ;
}
2022-09-19 21:04:22 +02:00
private static string GetShortGamepadId ( string str )
{
const string Hyphen = "-" ;
const int Offset = 1 ;
return str . Substring ( str . IndexOf ( Hyphen ) + Offset ) ;
}
2022-07-05 20:06:31 +02:00
public void LoadDevices ( )
{
lock ( Devices )
{
Devices . Clear ( ) ;
DeviceList . Clear ( ) ;
2023-01-03 19:45:08 +01:00
Devices . Add ( ( DeviceType . None , Disabled , LocaleManager . Instance [ LocaleKeys . ControllerSettingsDeviceDisabled ] ) ) ;
2022-07-05 20:06:31 +02:00
foreach ( string id in _mainWindow . InputManager . KeyboardDriver . GamepadsIds )
{
using IGamepad gamepad = _mainWindow . InputManager . KeyboardDriver . GetGamepad ( id ) ;
if ( gamepad ! = null )
{
2022-09-19 21:04:22 +02:00
Devices . Add ( ( DeviceType . Keyboard , id , $"{GetShortGamepadName(gamepad.Name)}" ) ) ;
2022-07-05 20:06:31 +02:00
}
}
foreach ( string id in _mainWindow . InputManager . GamepadDriver . GamepadsIds )
{
using IGamepad gamepad = _mainWindow . InputManager . GamepadDriver . GetGamepad ( id ) ;
if ( gamepad ! = null )
{
2022-09-19 21:04:22 +02:00
if ( Devices . Any ( controller = > GetShortGamepadId ( controller . Id ) = = GetShortGamepadId ( gamepad . Id ) ) )
{
_controllerNumber + + ;
}
Devices . Add ( ( DeviceType . Controller , id , $"{GetShortGamepadName(gamepad.Name)} ({_controllerNumber})" ) ) ;
2022-07-05 20:06:31 +02:00
}
}
2022-09-19 21:04:22 +02:00
_controllerNumber = 0 ;
2022-07-05 20:06:31 +02:00
DeviceList . AddRange ( Devices . Select ( x = > x . Name ) ) ;
Device = Math . Min ( Device , DeviceList . Count ) ;
}
}
private string GetProfileBasePath ( )
{
string path = AppDataManager . ProfilesDirPath ;
var type = Devices [ Device = = - 1 ? 0 : Device ] . Type ;
if ( type = = DeviceType . Keyboard )
{
path = Path . Combine ( path , KeyboardString ) ;
}
else if ( type = = DeviceType . Controller )
{
path = Path . Combine ( path , ControllerString ) ;
}
return path ;
}
private void LoadProfiles ( )
{
ProfilesList . Clear ( ) ;
string basePath = GetProfileBasePath ( ) ;
if ( ! Directory . Exists ( basePath ) )
{
Directory . CreateDirectory ( basePath ) ;
}
2023-01-03 19:45:08 +01:00
ProfilesList . Add ( ( LocaleManager . Instance [ LocaleKeys . ControllerSettingsProfileDefault ] ) ) ;
2022-07-05 20:06:31 +02:00
foreach ( string profile in Directory . GetFiles ( basePath , "*.json" , SearchOption . AllDirectories ) )
{
ProfilesList . Add ( Path . GetFileNameWithoutExtension ( profile ) ) ;
}
if ( string . IsNullOrWhiteSpace ( ProfileName ) )
{
2023-01-03 19:45:08 +01:00
ProfileName = LocaleManager . Instance [ LocaleKeys . ControllerSettingsProfileDefault ] ;
2022-07-05 20:06:31 +02:00
}
}
public InputConfig LoadDefaultConfiguration ( )
{
var activeDevice = Devices . FirstOrDefault ( ) ;
if ( Devices . Count > 0 & & Device < Devices . Count & & Device > = 0 )
{
activeDevice = Devices [ Device ] ;
}
InputConfig config ;
if ( activeDevice . Type = = DeviceType . Keyboard )
{
string id = activeDevice . Id ;
config = new StandardKeyboardInputConfig
{
2022-12-10 21:21:13 +01:00
Version = InputConfig . CurrentVersion ,
2022-07-05 20:06:31 +02:00
Backend = InputBackendType . WindowKeyboard ,
Id = id ,
ControllerType = ControllerType . ProController ,
LeftJoycon = new LeftJoyconCommonConfig < Key >
{
DpadUp = Key . Up ,
DpadDown = Key . Down ,
DpadLeft = Key . Left ,
DpadRight = Key . Right ,
ButtonMinus = Key . Minus ,
ButtonL = Key . E ,
ButtonZl = Key . Q ,
ButtonSl = Key . Unbound ,
ButtonSr = Key . Unbound
} ,
LeftJoyconStick =
new JoyconConfigKeyboardStick < Key >
{
StickUp = Key . W ,
StickDown = Key . S ,
StickLeft = Key . A ,
StickRight = Key . D ,
StickButton = Key . F
} ,
RightJoycon = new RightJoyconCommonConfig < Key >
{
ButtonA = Key . Z ,
ButtonB = Key . X ,
ButtonX = Key . C ,
ButtonY = Key . V ,
ButtonPlus = Key . Plus ,
ButtonR = Key . U ,
ButtonZr = Key . O ,
ButtonSl = Key . Unbound ,
ButtonSr = Key . Unbound
} ,
RightJoyconStick = new JoyconConfigKeyboardStick < Key >
{
StickUp = Key . I ,
StickDown = Key . K ,
StickLeft = Key . J ,
StickRight = Key . L ,
StickButton = Key . H
}
} ;
}
else if ( activeDevice . Type = = DeviceType . Controller )
{
bool isNintendoStyle = Devices . ToList ( ) . Find ( x = > x . Id = = activeDevice . Id ) . Name . Contains ( "Nintendo" ) ;
string id = activeDevice . Id . Split ( " " ) [ 0 ] ;
config = new StandardControllerInputConfig
{
2022-12-10 21:21:13 +01:00
Version = InputConfig . CurrentVersion ,
2022-07-05 20:06:31 +02:00
Backend = InputBackendType . GamepadSDL2 ,
Id = id ,
ControllerType = ControllerType . ProController ,
DeadzoneLeft = 0.1f ,
DeadzoneRight = 0.1f ,
RangeLeft = 1.0f ,
RangeRight = 1.0f ,
TriggerThreshold = 0.5f ,
LeftJoycon = new LeftJoyconCommonConfig < ConfigGamepadInputId >
{
DpadUp = ConfigGamepadInputId . DpadUp ,
DpadDown = ConfigGamepadInputId . DpadDown ,
DpadLeft = ConfigGamepadInputId . DpadLeft ,
DpadRight = ConfigGamepadInputId . DpadRight ,
ButtonMinus = ConfigGamepadInputId . Minus ,
ButtonL = ConfigGamepadInputId . LeftShoulder ,
ButtonZl = ConfigGamepadInputId . LeftTrigger ,
ButtonSl = ConfigGamepadInputId . Unbound ,
ButtonSr = ConfigGamepadInputId . Unbound
} ,
LeftJoyconStick = new JoyconConfigControllerStick < ConfigGamepadInputId , ConfigStickInputId >
{
Joystick = ConfigStickInputId . Left ,
StickButton = ConfigGamepadInputId . LeftStick ,
InvertStickX = false ,
InvertStickY = false
} ,
RightJoycon = new RightJoyconCommonConfig < ConfigGamepadInputId >
{
ButtonA = isNintendoStyle ? ConfigGamepadInputId . A : ConfigGamepadInputId . B ,
ButtonB = isNintendoStyle ? ConfigGamepadInputId . B : ConfigGamepadInputId . A ,
ButtonX = isNintendoStyle ? ConfigGamepadInputId . X : ConfigGamepadInputId . Y ,
ButtonY = isNintendoStyle ? ConfigGamepadInputId . Y : ConfigGamepadInputId . X ,
ButtonPlus = ConfigGamepadInputId . Plus ,
ButtonR = ConfigGamepadInputId . RightShoulder ,
ButtonZr = ConfigGamepadInputId . RightTrigger ,
ButtonSl = ConfigGamepadInputId . Unbound ,
ButtonSr = ConfigGamepadInputId . Unbound
} ,
RightJoyconStick = new JoyconConfigControllerStick < ConfigGamepadInputId , ConfigStickInputId >
{
Joystick = ConfigStickInputId . Right ,
StickButton = ConfigGamepadInputId . RightStick ,
InvertStickX = false ,
InvertStickY = false
} ,
Motion = new StandardMotionConfigController
{
MotionBackend = MotionInputBackendType . GamepadDriver ,
EnableMotion = true ,
Sensitivity = 100 ,
GyroDeadzone = 1
} ,
Rumble = new RumbleConfigController
{
StrongRumble = 1f ,
WeakRumble = 1f ,
EnableRumble = false
}
} ;
}
else
{
config = new InputConfig ( ) ;
}
config . PlayerIndex = _playerId ;
return config ;
}
2022-07-12 00:25:33 +02:00
public async void LoadProfile ( )
2022-07-05 20:06:31 +02:00
{
if ( Device = = 0 )
{
return ;
}
InputConfig config = null ;
if ( string . IsNullOrWhiteSpace ( ProfileName ) )
{
return ;
}
2023-01-03 19:45:08 +01:00
if ( ProfileName = = LocaleManager . Instance [ LocaleKeys . ControllerSettingsProfileDefault ] )
2022-07-05 20:06:31 +02:00
{
config = LoadDefaultConfiguration ( ) ;
}
else
{
string path = Path . Combine ( GetProfileBasePath ( ) , ProfileName + ".json" ) ;
if ( ! File . Exists ( path ) )
{
var index = ProfilesList . IndexOf ( ProfileName ) ;
if ( index ! = - 1 )
{
ProfilesList . RemoveAt ( index ) ;
}
return ;
}
try
{
2023-03-21 23:41:19 +01:00
config = JsonHelper . DeserializeFromFile ( path , SerializerContext . InputConfig ) ;
2022-07-05 20:06:31 +02:00
}
catch ( JsonException ) { }
catch ( InvalidOperationException )
{
Logger . Error ? . Print ( LogClass . Configuration , $"Profile {ProfileName} is incompatible with the current input configuration system." ) ;
2022-07-24 19:38:38 +02:00
2023-01-21 02:06:19 +01:00
await ContentDialogHelper . CreateErrorDialog ( LocaleManager . Instance . UpdateAndGetDynamicValue ( LocaleKeys . DialogProfileInvalidProfileErrorMessage , ProfileName ) ) ;
2022-07-05 20:06:31 +02:00
return ;
}
}
if ( config ! = null )
{
_isLoaded = false ;
LoadConfiguration ( config ) ;
LoadDevice ( ) ;
_isLoaded = true ;
NotifyChanges ( ) ;
}
}
public async void SaveProfile ( )
{
if ( Device = = 0 )
{
return ;
}
if ( Configuration = = null )
{
return ;
}
2023-01-03 19:45:08 +01:00
if ( ProfileName = = LocaleManager . Instance [ LocaleKeys . ControllerSettingsProfileDefault ] )
2022-07-05 20:06:31 +02:00
{
2023-01-03 19:45:08 +01:00
await ContentDialogHelper . CreateErrorDialog ( LocaleManager . Instance [ LocaleKeys . DialogProfileDefaultProfileOverwriteErrorMessage ] ) ;
2022-07-05 20:06:31 +02:00
return ;
}
else
{
bool validFileName = ProfileName . IndexOfAny ( Path . GetInvalidFileNameChars ( ) ) = = - 1 ;
if ( validFileName )
{
string path = Path . Combine ( GetProfileBasePath ( ) , ProfileName + ".json" ) ;
InputConfig config = null ;
if ( IsKeyboard )
{
config = ( Configuration as InputConfiguration < Key , ConfigStickInputId > ) . GetConfig ( ) ;
}
else if ( IsController )
{
config = ( Configuration as InputConfiguration < GamepadInputId , ConfigStickInputId > ) . GetConfig ( ) ;
}
config . ControllerType = Controllers [ _controller ] . Type ;
2023-03-21 23:41:19 +01:00
string jsonString = JsonHelper . Serialize ( config , SerializerContext . InputConfig ) ;
2022-07-05 20:06:31 +02:00
await File . WriteAllTextAsync ( path , jsonString ) ;
LoadProfiles ( ) ;
}
else
{
2023-01-03 19:45:08 +01:00
await ContentDialogHelper . CreateErrorDialog ( LocaleManager . Instance [ LocaleKeys . DialogProfileInvalidProfileNameErrorMessage ] ) ;
2022-07-05 20:06:31 +02:00
}
}
}
public async void RemoveProfile ( )
{
2023-01-03 19:45:08 +01:00
if ( Device = = 0 | | ProfileName = = LocaleManager . Instance [ LocaleKeys . ControllerSettingsProfileDefault ] | | ProfilesList . IndexOf ( ProfileName ) = = - 1 )
2022-07-05 20:06:31 +02:00
{
return ;
}
UserResult result = await ContentDialogHelper . CreateConfirmationDialog (
2023-01-03 19:45:08 +01:00
LocaleManager . Instance [ LocaleKeys . DialogProfileDeleteProfileTitle ] ,
LocaleManager . Instance [ LocaleKeys . DialogProfileDeleteProfileMessage ] ,
LocaleManager . Instance [ LocaleKeys . InputDialogYes ] ,
LocaleManager . Instance [ LocaleKeys . InputDialogNo ] ,
LocaleManager . Instance [ LocaleKeys . RyujinxConfirm ] ) ;
2022-07-05 20:06:31 +02:00
if ( result = = UserResult . Yes )
{
string path = Path . Combine ( GetProfileBasePath ( ) , ProfileName + ".json" ) ;
if ( File . Exists ( path ) )
{
File . Delete ( path ) ;
}
LoadProfiles ( ) ;
}
}
public void Save ( )
{
IsModified = false ;
List < InputConfig > newConfig = new ( ) ;
newConfig . AddRange ( ConfigurationState . Instance . Hid . InputConfig . Value ) ;
newConfig . Remove ( newConfig . Find ( x = > x = = null ) ) ;
if ( Device = = 0 )
{
newConfig . Remove ( newConfig . Find ( x = > x . PlayerIndex = = this . PlayerId ) ) ;
}
else
{
var device = Devices [ Device ] ;
if ( device . Type = = DeviceType . Keyboard )
{
var inputConfig = Configuration as InputConfiguration < Key , ConfigStickInputId > ;
inputConfig . Id = device . Id ;
}
else
{
var inputConfig = Configuration as InputConfiguration < GamepadInputId , ConfigStickInputId > ;
inputConfig . Id = device . Id . Split ( " " ) [ 0 ] ;
}
var config = ! IsController
? ( Configuration as InputConfiguration < Key , ConfigStickInputId > ) . GetConfig ( )
: ( Configuration as InputConfiguration < GamepadInputId , ConfigStickInputId > ) . GetConfig ( ) ;
config . ControllerType = Controllers [ _controller ] . Type ;
config . PlayerIndex = _playerId ;
int i = newConfig . FindIndex ( x = > x . PlayerIndex = = PlayerId ) ;
if ( i = = - 1 )
{
newConfig . Add ( config ) ;
}
else
{
newConfig [ i ] = config ;
}
}
2023-01-08 18:46:25 +01:00
_mainWindow . ViewModel . AppHost ? . NpadManager . ReloadConfiguration ( newConfig , ConfigurationState . Instance . Hid . EnableKeyboard , ConfigurationState . Instance . Hid . EnableMouse ) ;
2022-07-05 20:06:31 +02:00
// Atomically replace and signal input change.
// NOTE: Do not modify InputConfig.Value directly as other code depends on the on-change event.
ConfigurationState . Instance . Hid . InputConfig . Value = newConfig ;
ConfigurationState . Instance . ToFileFormat ( ) . SaveConfig ( Program . ConfigurationPath ) ;
}
public void NotifyChange ( string property )
{
OnPropertyChanged ( property ) ;
}
public void NotifyChanges ( )
{
OnPropertyChanged ( nameof ( Configuration ) ) ;
OnPropertyChanged ( nameof ( IsController ) ) ;
OnPropertyChanged ( nameof ( ShowSettings ) ) ;
OnPropertyChanged ( nameof ( IsKeyboard ) ) ;
OnPropertyChanged ( nameof ( IsRight ) ) ;
OnPropertyChanged ( nameof ( IsLeft ) ) ;
}
public void Dispose ( )
{
_mainWindow . InputManager . GamepadDriver . OnGamepadConnected - = HandleOnGamepadConnected ;
_mainWindow . InputManager . GamepadDriver . OnGamepadDisconnected - = HandleOnGamepadDisconnected ;
2023-01-08 18:46:25 +01:00
_mainWindow . ViewModel . AppHost ? . NpadManager . UnblockInputUpdates ( ) ;
2022-07-05 20:06:31 +02:00
SelectedGamepad ? . Dispose ( ) ;
AvaloniaKeyboardDriver . Dispose ( ) ;
}
}
}