Compare commits

...

28 commits

Author SHA1 Message Date
Goodfeat
e5d6090b4a Merge branch 'Master_PR' into 'master'
Improved interaction with "Input" settings.

See merge request ryubing/ryujinx!4
2025-03-17 03:55:14 +00:00
GreemDev
17f3540ac9 create CHANGELOG.md 2025-03-17 03:51:03 +00:00
Goodfeat
a1e2d24d84 Merge branch ryujinx:master into Master_PR 2025-03-16 12:57:11 +00:00
Goodfeat
ad3f6c2eac Merge branch ryujinx:master into Master_PR 2025-03-16 02:18:56 +00:00
Goodfeat
5f4ef9f9c8 Merge branch 'master' into 'Master_PR'
# Conflicts:
#   src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs
2025-03-15 10:13:00 +00:00
Goodfeat
7266f1812f Merge branch ryujinx:master into Master_PR 2025-03-14 13:24:26 +00:00
Goodfeat
fc9d42b8c3 Merge branch ryujinx:master into Master_PR 2025-03-13 23:27:54 +00:00
Vova
db08498a89 Addition: Device Name and ID are displayed when the controller is turned off, but the controller is configured.
Added the "Name" property for controllers.
Changed the controller setup message to be more informative.
2025-03-06 17:13:11 +10:00
Vova
7a43dcb513 Merge branch 'Master_PR' of https://github.com/Goodfeat/Ryujinx_alt into Master_PR 2025-03-06 14:52:48 +10:00
Vova
f2329d0e8a Fixed bug with turning off active gamepad (independent profiles)
When switching profiles, if the profile does not belong to the gamepad itself, the gamepad began to be displayed as turned off.
Fixed a bug where the return button did not return the initially selected gamepad
2025-03-06 14:52:30 +10:00
Vladimir Sokolov
3aa7ed661d
Merge branch 'master' into Master_PR 2025-03-06 11:44:18 +10:00
Vladimir Sokolov
6e824e44b8
Merge branch 'master' into Master_PR 2025-03-06 08:38:55 +10:00
Vladimir Sokolov
a964bf8f68
Merge branch 'master' into Master_PR 2025-03-05 19:12:19 +10:00
Vladimir Sokolov
89e4d287d6
Merge branch 'master' into Master_PR 2025-03-05 09:18:36 +10:00
Vladimir Sokolov
f34745a66c
Merge branch 'master' into Master_PR 2025-03-04 21:31:56 +10:00
Vladimir Sokolov
d5b7851c9b
Merge branch 'master' into Master_PR 2025-03-03 21:22:24 +10:00
Vova
1b7032b589 smal fix 2025-03-03 00:07:05 +10:00
Vova
e097ea71ff Fix: exclude device id when loading preset (independent presets)
fixed bug when selected gamepad disappears if another gamepad was disconnected
2025-03-02 23:49:40 +10:00
Vova
299f2144c8 Bug fixes, functionality improvements:
Now the profile changes immediately upon selection.
The icon for restoring settings has been changed.
A bug has been fixed where restoring settings did not restore the previously selected gamepad.
2025-03-02 19:07:49 +10:00
Vova
33e3ba9ff2 Fixed profiles on the input page:
- profiles are unlinked from controllers
- sometimes a new profile after saving changed to the previous one, had to select it again (fixed)
- when deleting, the profile now resets the name to "default"
2025-03-01 23:44:05 +10:00
Vladimir Sokolov
9dc36646c1
Merge branch 'master' into Master_PR 2025-02-28 20:54:11 +10:00
Vova
8eea75a6e8 Small fix 2025-02-23 16:44:10 +10:00
Vladimir Sokolov
57fbcc7aed
Merge branch 'master' into Master_PR 2025-02-23 16:18:11 +10:00
Vova
d1c15f3562 Fixed a bug with the (undo last changes) button in the gamepad settings 2025-02-23 16:16:43 +10:00
Vova
0423fad7ff Merge branch 'Master_PR' of https://github.com/Goodfeat/Ryujinx_alt into Master_PR 2025-02-23 16:04:12 +10:00
Vova
1951fe0077 Added the ability to delete assigned buttons with the right mouse button in the settings.
- for keyboard
- for hotkeys
2025-02-23 15:59:03 +10:00
Vladimir Sokolov
7fd5a63a5d
Merge branch 'master' into Master_PR 2025-02-23 14:18:24 +10:00
Vova
a0594e8169 Improved interaction with "Input" settings.
- paired devices have notifications that they are configured and require connection
- paired devices load the configuration when connected
- A notification appears when changing control configuration settings.
- Now control settings will be saved only when they are changed
- Added a button to roll back changes to the previously saved state
- Fixed a bug: when switching the "player", if the "input device" and "controller type" settings were changed, the save dialog box did not appear.
- "Motion", "Rumble" and "Led" also have events notifying about changes
2025-02-23 10:20:42 +10:00
14 changed files with 772 additions and 83 deletions

255
CHANGELOG.md Normal file
View file

@ -0,0 +1,255 @@
# Ryujinx Changelog
All updates to this Ryujinx branch will be documented in this file.
## [1.2.86](<https://git.ryujinx.app/ryubing/ryujinx/-/releases/1.2.86>) - 2025-03-13
A list of notable changes can be found on the release linked in the version number above.
## [1.2.82](<https://web.archive.org/web/20250312010534/https://github.com/Ryubing/Ryujinx/releases/tag/1.2.82>) - 2025-02-16
A list of notable changes can be found on the release linked in the version number above.
## [1.2.80-81](<https://web.archive.org/web/20250302064257/https://github.com/Ryubing/Ryujinx/releases/tag/1.2.81>) - 2025-01-22
A list of notable changes can be found on the release linked in the version number above.
## [1.2.78](<https://web.archive.org/web/20250301174537/https://github.com/Ryubing/Ryujinx/releases/tag/1.2.78>) - 2024-12-19
A list of notable changes can be found on the release linked in the version number above.
## [1.2.73-1.2.76](<https://web.archive.org/web/20250209202612/https://github.com/Ryubing/Ryujinx/releases/tag/1.2.76>) - 2024-11-19
A list of notable changes can be found on the release linked in the version number above.
Additionally, 1.2.74 & 75 were fixes for uploading Windows build artifacts.
1.2.76 fixes a rare crash on startup.
## [1.2.72](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.72>) - 2024-11-03
PRs [#163](<https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://github.com/GreemDev/Ryujinx/pull/164>), [#139](<https://github.com/GreemDev/Ryujinx/pull/139>)
### HLE:
- Add DebugMouse HID device.
- Fixes "Clock Tower Rewind" crashing while loading.
### Audio:
- Fix index bounds check in GetCoefficientAtIndex.
- Fixes crashing in Super Mario Party Jamboree.
### misc:
- Update macOS distribution .icns.
## [1.2.69](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.69>) - 2024-11-01
### Infra:
- Compile the native libraries into the Ryujinx executable.
- Remove `libarmeilleure-jitsupport.dylib` from Windows & Linux releases (dylibs are macOS-only)
### Misc:
- Remove custom themes in config.
- This is a leftover from the GTK UI, as Avalonia does not have custom themes.
- Replace "" with `string.Empty`.
- Code cleanups & simplifications.
## [1.2.67](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.67>) - 2024-11-01
PRs [#36](<https://github.com/GreemDev/Ryujinx/pull/36>), [#135](<https://github.com/GreemDev/Ryujinx/pull/135>)
### GUI:
- Set UseFloatingWatermark to false when watermark is empty
- Should prevent the text prompt box from having weird jumpy behavior.
### GPU:
- Increase the amount of VRAM cache available for textures based on selected DRAM amount.
### Misc:
- Fix homebrew loading.
## [1.2.64](https://github.com/GreemDev/Ryujinx/releases/tag/1.2.64) - 2024-10-30
PRs [#92](https://github.com/GreemDev/Ryujinx/pull/92), [#96](https://github.com/GreemDev/Ryujinx/pull/96), [#97](https://github.com/GreemDev/Ryujinx/pull/97), [#101](https://github.com/GreemDev/Ryujinx/pull/101), [#103](https://github.com/GreemDev/Ryujinx/pull/103)
### GUI:
- Option to show classic-style title bar. Requires restart of emulator to take effect.
- This is only relevant on Windows. Other Operating Systems default to this being on and not being changeable, because the custom (current) title bar only works on Windows in the first place.
### i18n:
- it_IT:
- Add missing Italian strings.
- pt_BR:
- Add missing Brazilian Portuguese strings.
- fr_FR:
- Fix some French strings.
### MISC:
- Higher-res logo.
## 1.2.59 - 2024-10-27
PRs [#88](https://github.com/GreemDev/Ryujinx/pull/88), [#87](https://github.com/GreemDev/Ryujinx/pull/87)
### i18n:
- fr_FR:
- Add missing translations for new features & fix a couple wrong ones.
- Fix Ignore Missing Services / Ignore Applet tooltip.
## 1.2.57 - 2024-10-27
PRs [#60](https://github.com/GreemDev/Ryujinx/pull/60), [#42](https://github.com/GreemDev/Ryujinx/pull/42)
### GUI:
- Automatically remove invalid DLC & updates as part of autoload.
- Added Thai translation for Ignore Applet hover tooltip.
### INPUT:
- When using multiple gamepads, when reconnecting they will no longer be mixed up between players.
## 1.2.50 - 2024-10-25
### GUI:
- Fix crash when using "delete all" button in mod manager.
### Updater:
- Remove Avalonia migration code.
### MISC:
- Replace references to IntPtr/UIntPtr to nint/nuint.
## 1.2.45 - 2024-10-25
### GUI:
- Added program icon to windows other than the main.
- Reference translations added in the last version.
- Shader compile counter is now translated.
### RPC:
- Added SONIC X SHADOW GENERATIONS asset image.
### MISC:
- Code cleanup.
## 1.2.44 - 2024-10-25
PR [#59](https://github.com/GreemDev/Ryujinx/pull/59)
### GUI:
- Add descriptions for "ignoring applet" translated into other languages.
NOTE: The translation isn't referenced in the code yet, it will be in the next update. These are just the translations.
## Hotfix: 1.2.43 - 2024-10-24
### GUI:
- Do not enable Ignore Applet by default when upgrading config version.
## 1.2.42 - 2024-10-24
Sources:
Init function: https://github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9
Shader counter: https://github.com/MutantAura/Ryujinx/commit/67b873645fd593e83d042a77bf7ab12e5ec97357
Thanks MutantAura :D
### GUI:
- Implement shader compile counter (currently not translated, will change, need to pull changes.)
- Remove graphics backend / GPU name event logic in favor of a single init function.
## 1.2.41 - 2024-10-24
PR [#54](https://github.com/GreemDev/Ryujinx/pull/54)
Thanks Whitescatz!
### i18n:
- th_TH (Thai): Added missing translations, reduce transliterated words, fix grammar.
## 1.2.40 - 2024-10-23
PR [#40](https://github.com/GreemDev/Ryujinx/pull/40)
Thanks Вова С!
### GUI:
- Add option to ignore controller applet upon start.
*This option is under the hacks section for a reason; it ignores intended behavior. Use with caution.
## 1.2.39 - 2024-10-23
### MISC:
- Null-coalesce autoloaddirs on config load.
- Should prevent crashing on config loads in some circumstances.
## 1.2.38 - 2024-10-23
PR [#51](https://github.com/GreemDev/Ryujinx/pull/51)
### i18n:
- zh_CH (Simplified Chinese): Add some missing translations.
## 1.2.37 - 2024-10-23
PR [#37](https://github.com/GreemDev/Ryujinx/pull/37)
Thanks Last Breath!
### GUI:
- Set the default controller to the Pro Controller.
## 1.2.36 - 2024-10-21
PR [#30](https://github.com/GreemDev/Ryujinx/pull/30)
### GUI:
- Fix repeated dialog popup notifying you of new updates when there aren't any, while having a bundled update inside an XCI and an external update file.
## 1.2.35 - 2024-10-21
PR [#32](https://github.com/GreemDev/Ryujinx/pull/32)
### GUI:
- Replace "expand DRAM" option with a DRAM size dropdown.
- Allows for using mods which require a ridiculous amount of memory to allocate from.
## 1.2.34 - 2024-10-21
PR [#29](https://github.com/GreemDev/Ryujinx/pull/29)
### GUI:
- Fix duplicate controller names when 2 controllers of the same type are connected.
### INPUT:
- Fix invert x, y, and rotate when mapping physical left stick to logical right stick and vice versa.
## 1.2.32-1.2.33 - 2024-10-21
### i18n:
- fr_FR: Added missing strings and general improvements.
- Improve French translation clarity & add missing translations by Nebroc351, helped by Fredy27 in the Discord.
## 1.2.31 - 2024-10-21
### GUI:
- Revert maximized = fullscreen change.
- Fixes fullscreen not hiding the Windows taskbar.
## 1.2.30 - 2024-10-19
### GUI:
- Reload game list on locale change.
- Add keybinds to useful things (namely opening Amiibo scan window (Ctrl + A) and the scan button (Enter)).
- Reset RPC state when AppHost stops.
### MISC:
- XML & code cleanups.
## 1.2.29 - 2024-10-19
### GUI:
- Remove references to ryujinx.org in the localization files.
- Switch from downloading amiibo.ryujinx.org to just referencing a file in the repo & images in the repo, under assets/amiibo.
This fork is now entirely independent of the existing Ryujinx infrastructure, and as such the Amiibo features will continue to work in my version when they break in the mainline version.
## 1.2.28 - 2024-10-17
### GUI:
- Fix dialog popups doubling the window controls and laying text over the menu bar.
## 1.2.26 - 2024-10-17
### I18n:
Added Low-power PPTC mode strings to the translation files.
### GUI:
- Remove OS-provided title bar and put the Ryujinx logo next to "File" in the menu bar.
- What was in the title bar, Ryujinx version & current game information, is still visible by hovering the Ryujinx icon.
- Added icons to many actions in dropdown menus.
### RPC:
- Added Kirby and the Forgotten Land, Elder Scrolls V Skyrim, and Hyrule Warriors: Age of Calamity to the RPC assets.
## 1.2.25 - 2024-10-14
### CPU:
- Add low-power PPTC mode.
- Specifically, this setting causes the core count to get reduced by two-thirds, for lower-power but still fast loading if desired, and for unstable CPUs.
## 1.2.24 - 2024-10-14
### SDL:
- Move Mouse & MouseDriver to Input project, instead of Headless.
## 1.2.22 - 2024-10-12
### GUI/RPC:
- Added RDR, Luigi's Mansion 2 HD & 3 asset images.
### MISC:
- Minor code cleanups & improvements.
- Removed duplicate executable in the release bundle (leftovers from GTK & Avalonia dual releases).
- Removed Avalonia test release bundle, which was kept in Ryujinx for the OG Avalonia testers. That doesn't apply to this fork, so it's removed.
## 1.2.21 - 2024-10-11
### GUI/RPC:
- Add game version string when hovering large image asset.
- Add version information about this fork to the Ryujinx logo (big when in main menu, small when in game) when hovering.
## 1.2.20 - 2024-10-11
### MISC:
- Code cleanups & remove references to Ryujinx Patreon & Twitter.
### GUI:
- Add more Discord presence assets.
## 1.2.1-1.2.19 - 2024-10-08 - 2024-10-11
### GUI/INFRA/MISC:
- Remove GTK UI.
- Autoload DLC/Updates from dir ([#12](https://github.com/GreemDev/Ryujinx/pull/12)).
- Changed executable icon to rainbow logo.
- Extract Data > Logo now also extracts the square thumbnail you see for the game in the UI.
- The "use random UUID hack" checkbox in the Amiibo screen now remembers its last state when you reopen the window in a given session.

View file

@ -21,6 +21,11 @@ namespace Ryujinx.Common.Configuration.Hid
/// </summary>
public string Id { get; set; }
/// <summary>
/// Controller name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Controller's Type
/// </summary>

View file

@ -49,7 +49,6 @@
<TextBlock
Classes="globalConfigMarker"/>
</StackPanel>
</Border>
</Design.PreviewWith>
<Style Selector="DropDownButton">

View file

@ -6922,6 +6922,31 @@
"zh_TW": "輸入裝置"
}
},
{
"ID": "ControllerSettingsWaitingConnectDevice",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Configuration found:\n\nName:\t{0}\nGUID:\t{1}\n\n Waiting for controller connection...",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{
"ID": "ControllerSettingsRefresh",
"Translations": {
@ -7222,6 +7247,81 @@
"zh_TW": "新增"
}
},
{
"ID": "ControllerSettingsModifiedNotification",
"Translations": {
"ar_SA": "(تم التعديل!)",
"de_DE": "(modifiziert!)",
"el_GR": "(τροποποιημένο!)",
"en_US": "(Modified!)",
"es_ES": "(modificado!)",
"fr_FR": "(modifié!)",
"he_IL": "(שונה!)",
"it_IT": "(modificato!)",
"ja_JP": "(変更済み!)",
"ko_KR": "(수정됨!)",
"no_NO": "(modifisert!)",
"pl_PL": "(zmodyfikowane!)",
"pt_BR": "(modificado!)",
"ru_RU": "(изменено!)",
"sv_SE": "(ändrad!)",
"th_TH": "(แก้ไขแล้ว!)",
"tr_TR": "(değiştirildi!)",
"uk_UA": "(модифіковано!)",
"zh_CN": "(已修改!)",
"zh_TW": "(已修改!)"
}
},
{
"ID": "ControllerSettingsDisableDeviceForSaving",
"Translations": {
"ar_SA": "تم إعداد التحكم.\n\nفي انتظار اتصال وحدة التحكم...",
"de_DE": "Steuerung konfiguriert.\n\nWarten auf die Verbindung des Controllers...",
"el_GR": "Η διαχείριση έχει ρυθμιστεί.\n\nΑναμένεται σύνδεση του χειριστηρίου...",
"en_US": "Control configured.\n\nWaiting for controller connection...",
"es_ES": "Control configurado.\n\nEsperando la conexión del controlador...",
"fr_FR": "Contrôle configuré.\n\nEn attente de la connexion du contrôleur...",
"he_IL": "השליטה הוגדרה.\n\nממתין לחיבור הבקר...",
"it_IT": "Controllo configurato.\n\nIn attesa della connessione del controller...",
"ja_JP": "コントロールが設定されました。\n\nコントローラーの接続を待っています...",
"ko_KR": "제어가 설정되었습니다.\n\n컨트롤러 연결 대기 중...",
"no_NO": "Kontroll konfigurert.\n\nVenter på tilkobling av kontroller...",
"pl_PL": "Sterowanie skonfigurowane.\n\nOczekiwanie na połączenie kontrolera...",
"pt_BR": "Controle configurado.\n\nAguardando conexão do controle...",
"ru_RU": "Управление настроено.\n\nОжидается подключение контроллера...",
"sv_SE": "Kontroll konfigurerad.\n\nVäntar på anslutning av kontrollen...",
"th_TH": "การควบคุมได้รับการตั้งค่าแล้ว\n\nกำลังรอการเชื่อมต่อคอนโทรลเลอร์...",
"tr_TR": "Kontrol yapılandırıldı.\n\nKontrolcü bağlantısı bekleniyor...",
"uk_UA": "Керування налаштовано.\n\nОчікується підключення контролера...",
"zh_CN": "控制已配置。\n\n等待控制器连接...",
"zh_TW": "控制已設定。\n\n等待控制器連接..."
}
},
{
"ID": "ControllerSettingsUnlink",
"Translations": {
"ar_SA": "إلغاء الربط",
"de_DE": "Entkoppeln",
"el_GR": "Αποσύνδεση",
"en_US": "Unlink",
"es_ES": "Desvincular",
"fr_FR": "Dissocier",
"he_IL": "ניתוק קישור",
"it_IT": "Scollega",
"ja_JP": "リンク解除",
"ko_KR": "연결 해제",
"no_NO": "Frakoble",
"pl_PL": "Odłącz",
"pt_BR": "Desvincular",
"ru_RU": "Отвязать",
"sv_SE": "Koppla från",
"th_TH": "ยกเลิกการเชื่อมโยง",
"tr_TR": "Bağlantıyı Kes",
"uk_UA": "Відв'язати",
"zh_CN": "解除绑定",
"zh_TW": "解除綁定"
}
},
{
"ID": "ControllerSettingsRemove",
"Translations": {
@ -11872,6 +11972,31 @@
"zh_TW": "儲存設定檔"
}
},
{
"ID": "ControllerSettingsCancelCurrentChangesToolTip",
"Translations": {
"ar_SA": "إلغاء التغييرات الحالية",
"de_DE": "Aktuelle Änderungen abbrechen",
"el_GR": "Ακύρωση τρεχουσών αλλαγών",
"en_US": "Cancel current changes",
"es_ES": "Cancelar los cambios actuales",
"fr_FR": "Annuler les modifications en cours",
"he_IL": "ביטול השינויים הנוכחיים",
"it_IT": "Annulla le modifiche correnti",
"ja_JP": "現在の変更をキャンセル",
"ko_KR": "현재 변경 취소",
"no_NO": "Avbryt gjeldende endringer",
"pl_PL": "Anuluj bieżące zmiany",
"pt_BR": "Cancelar alterações atuais",
"ru_RU": "Отменить текущие изменения",
"sv_SE": "Avbryt aktuella ändringar",
"th_TH": "ยกเลิกการเปลี่ยนแปลงปัจจุบัน",
"tr_TR": "Geçerli değişiklikleri iptal et",
"uk_UA": "Скасувати поточні зміни",
"zh_CN": "取消当前更改",
"zh_TW": "取消當前變更"
}
},
{
"ID": "MenuBarFileToolsTakeScreenshot",
"Translations": {

View file

@ -269,6 +269,7 @@ namespace Ryujinx.Ava.Systems.Configuration
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.WindowKeyboard,
Id = "0",
Name = "Keyboard",
PlayerIndex = PlayerIndex.Player1,
ControllerType = ControllerType.ProController,
LeftJoycon = new LeftJoyconCommonConfig<Key>

View file

@ -22,6 +22,8 @@ namespace Ryujinx.Ava.UI.Models.Input
public float StrongRumble { get; set; }
public string Id { get; set; }
public string Name { get; set; }
public ControllerType ControllerType { get; set; }
public PlayerIndex PlayerIndex { get; set; }
@ -111,6 +113,7 @@ namespace Ryujinx.Ava.UI.Models.Input
if (config != null)
{
Id = config.Id;
Name = config.Name;
ControllerType = config.ControllerType;
PlayerIndex = config.PlayerIndex;
@ -201,6 +204,7 @@ namespace Ryujinx.Ava.UI.Models.Input
StandardControllerInputConfig config = new()
{
Id = Id,
Name = Name,
Backend = InputBackendType.GamepadSDL2,
PlayerIndex = PlayerIndex,
ControllerType = ControllerType,

View file

@ -2,12 +2,14 @@ using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Keyboard;
using System.Xml.Linq;
namespace Ryujinx.Ava.UI.Models.Input
{
public partial class KeyboardInputConfig : BaseModel
{
public string Id { get; set; }
public string Name { get; set; }
public ControllerType ControllerType { get; set; }
public PlayerIndex PlayerIndex { get; set; }
@ -53,6 +55,7 @@ namespace Ryujinx.Ava.UI.Models.Input
if (config != null)
{
Id = config.Id;
Name = config.Name;
ControllerType = config.ControllerType;
PlayerIndex = config.PlayerIndex;
@ -100,6 +103,7 @@ namespace Ryujinx.Ava.UI.Models.Input
StandardKeyboardInputConfig config = new()
{
Id = Id,
Name = Name,
Backend = InputBackendType.WindowKeyboard,
PlayerIndex = PlayerIndex,
ControllerType = ControllerType,

View file

@ -93,16 +93,19 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public async void ShowMotionConfig()
{
await MotionInputView.Show(this);
ParentModel.IsModified = true;
}
public async void ShowRumbleConfig()
{
await RumbleInputView.Show(this);
ParentModel.IsModified = true;
}
public async void ShowLedConfig()
{
await LedInputView.Show(this);
ParentModel.IsModified = true;
}
public void OnParentModelChanged()

View file

@ -51,6 +51,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private int _device;
private object _configViewModel;
[ObservableProperty] private string _profileName;
[ObservableProperty] private bool _notificationIsVisible; // Automatically call the NotificationView property with OnPropertyChanged()
[ObservableProperty] private string _notificationText; // Automatically call the NotificationText property with OnPropertyChanged()
private bool _isLoaded;
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@ -88,13 +90,40 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool IsKeyboard => !IsController;
public bool IsRight { get; set; }
public bool IsLeft { get; set; }
public string RevertDeviceId { get; set; }
public bool HasLed => SelectedGamepad.Features.HasFlag(GamepadFeaturesFlag.Led);
public bool CanClearLed => SelectedGamepad.Name.ContainsIgnoreCase("DualSense");
public bool IsModified { get; set; }
public bool _isChangeTrackingActive;
public bool _isModified;
public bool IsModified
{
get => _isModified;
set
{
_isModified = value;
OnPropertyChanged();
}
}
public event Action NotifyChangesEvent;
public string _profileChoose;
public string ProfileChoose
{
get => _profileChoose;
set
{
// When you select a profile, the settings from the profile will be applied.
// To save the settings, you still need to click the apply button
_profileChoose = value;
LoadProfile();
OnPropertyChanged();
}
}
public object ConfigViewModel
{
get => _configViewModel;
@ -121,13 +150,13 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
if (IsModified)
{
_playerIdChoose = value;
return;
}
IsModified = false;
_playerId = value;
_isChangeTrackingActive = false;
if (!Enum.IsDefined<PlayerIndex>(_playerId))
{
@ -135,13 +164,13 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
}
_isLoaded = false;
LoadConfiguration();
LoadDevice();
LoadProfiles();
RevertDeviceId = Devices[Device].Id;
_isLoaded = true;
_isChangeTrackingActive = true;
OnPropertyChanged();
}
}
@ -151,6 +180,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
get => _controller;
set
{
MarkAsChanged();
_controller = value;
if (_controller == -1)
@ -229,6 +260,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
get => _device;
set
{
MarkAsChanged();
_device = value < 0 ? 0 : value;
if (_device >= Devices.Count)
@ -248,11 +281,13 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
}
}
FindPairedDeviceInConfigFile();
OnPropertyChanged();
NotifyChanges();
}
}
public InputConfig Config { get; set; }
public InputViewModel(UserControl owner) : this()
@ -274,6 +309,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
PlayerId = PlayerIndex.Player1;
}
_isChangeTrackingActive = true;
}
public InputViewModel()
@ -311,8 +348,50 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig), VisualStick);
}
FindPairedDeviceInConfigFile();
}
private void FindPairedDeviceInConfigFile()
{
// This function allows you to output a message about the device configuration found in the file
// NOTE: if the configuration is found, we display the message "Waiting for controller connection",
// but only if the id gamepad belongs to the selected player
NotificationIsVisible = Config != null && Devices.FirstOrDefault(d => d.Id == Config.Id).Id != Config.Id && Config.PlayerIndex == PlayerId;
if (NotificationIsVisible)
{
if (string.IsNullOrEmpty(Config.Name))
{
NotificationText = $"{LocaleManager.Instance[LocaleKeys.ControllerSettingsWaitingConnectDevice].Format("No information", Config.Id)}";
}
else
{
NotificationText = $"{LocaleManager.Instance[LocaleKeys.ControllerSettingsWaitingConnectDevice].Format(Config.Name, Config.Id)}";
}
}
}
private void MarkAsChanged()
{
//If tracking is active, then allow changing the modifier
if (!IsModified && _isChangeTrackingActive)
{
RevertDeviceId = Devices[Device].Id; // Remember the device to undo changes
IsModified = true;
}
}
public void UnlinkDevice()
{
// "Disabled" mode is available after unbinding the device
// NOTE: the IsModified flag to be able to apply the settings.
NotificationIsVisible = false;
IsModified = true;
}
public void LoadDevice()
{
if (Config == null || Config.Backend == InputBackendType.Invalid)
@ -378,14 +457,34 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
}
}
private void HandleOnGamepadDisconnected(string id)
private async void HandleOnGamepadDisconnected(string id)
{
Dispatcher.UIThread.Post(LoadDevices);
_isChangeTrackingActive = false; // Disable configuration change tracking
await Dispatcher.UIThread.InvokeAsync(() =>
{
LoadDevices();
IsModified = true;
RevertChanges();
FindPairedDeviceInConfigFile();
_isChangeTrackingActive = true; // Enable configuration change tracking
return System.Threading.Tasks.Task.CompletedTask;
});
}
private void HandleOnGamepadConnected(string id)
private async void HandleOnGamepadConnected(string id)
{
Dispatcher.UIThread.Post(LoadDevices);
_isChangeTrackingActive = false; // Disable configuration change tracking
await Dispatcher.UIThread.InvokeAsync(() =>
{
LoadDevices();
IsModified = true;
RevertChanges();
_isChangeTrackingActive = true;// Enable configuration change tracking
});
}
private string GetCurrentGamepadId()
@ -558,12 +657,14 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
if (activeDevice.Type == DeviceType.Keyboard)
{
string id = activeDevice.Id;
string name = activeDevice.Name;
config = new StandardKeyboardInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.WindowKeyboard,
Id = id,
Name = name,
ControllerType = ControllerType.ProController,
LeftJoycon = new LeftJoyconCommonConfig<Key>
{
@ -613,12 +714,14 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
bool isNintendoStyle = Devices.ToList().FirstOrDefault(x => x.Id == activeDevice.Id).Name.Contains("Nintendo");
string id = activeDevice.Id.Split(" ")[0];
string name = activeDevice.Name;
config = new StandardControllerInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.GamepadSDL2,
Id = id,
Name = name,
ControllerType = ControllerType.ProController,
DeadzoneLeft = 0.1f,
DeadzoneRight = 0.1f,
@ -688,6 +791,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
return config;
}
public void LoadProfileButton()
{
LoadProfile();
IsModified = true;
}
public async void LoadProfile()
{
if (Device == 0)
@ -739,9 +848,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{
_isLoaded = false;
config.Id = Config.Id; // Set current device id instead of changing device(independent profiles)
LoadConfiguration(config);
LoadDevice();
//LoadDevice(); This line of code hard-links profiles to controllers, the commented line allows profiles to be applied to all controllers
_isLoaded = true;
@ -751,6 +862,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public async void SaveProfile()
{
if (Device == 0)
{
return;
@ -793,12 +905,15 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
await File.WriteAllTextAsync(path, jsonString);
LoadProfiles();
ProfileChoose = ProfileName; // Show new profile
}
else
{
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
}
}
}
public async void RemoveProfile()
@ -825,13 +940,32 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
}
LoadProfiles();
ProfileChoose = ProfilesList[0].ToString(); // Show default profile
}
}
public void RevertChanges()
{
Device = Devices.ToList().FindIndex(d => d.Id == RevertDeviceId);
LoadDevice();
LoadConfiguration();
OnPropertyChanged();
IsModified = false;
}
public void Save()
{
if (!IsModified)
{
return; //If the input settings were not touched, then do nothing
}
IsModified = false;
RevertDeviceId = Devices[Device].Id; // Remember selected device after saving
List <InputConfig> newConfig = [];
newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value);
@ -862,6 +996,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
: (ConfigViewModel as ControllerInputViewModel).Config.GetConfig();
config.ControllerType = Controllers[_controller].Type;
config.PlayerIndex = _playerId;
config.Name = device.Name;
int i = newConfig.FindIndex(x => x.PlayerIndex == PlayerId);
if (i == -1)

View file

@ -65,7 +65,8 @@ namespace Ryujinx.Ava.UI.Views.Input
if (!float.IsNaN(_changeSlider) && _changeSlider != (float)check.Value)
{
(DataContext as ControllerInputViewModel)!.ParentModel.IsModified = true;
FlagInputConfigChanged();
_changeSlider = (float)check.Value;
}
}
@ -75,7 +76,8 @@ namespace Ryujinx.Ava.UI.Views.Input
{
if (sender is CheckBox { IsPointerOver: true })
{
(DataContext as ControllerInputViewModel)!.ParentModel.IsModified = true;
FlagInputConfigChanged();
_currentAssigner?.Cancel();
_currentAssigner = null;
}
@ -115,7 +117,7 @@ namespace Ryujinx.Ava.UI.Views.Input
if (e.ButtonValue.HasValue)
{
Button buttonValue = e.ButtonValue.Value;
viewModel.ParentModel.IsModified = true;
FlagInputConfigChanged();
switch (button.Name)
{
@ -209,6 +211,11 @@ namespace Ryujinx.Ava.UI.Views.Input
}
}
private void FlagInputConfigChanged()
{
(DataContext as ControllerInputViewModel)!.ParentModel.IsModified = true;
}
private void MouseClick(object sender, PointerPressedEventArgs e)
{
bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
@ -232,7 +239,6 @@ namespace Ryujinx.Ava.UI.Views.Input
{
gamepad?.ClearLed();
}
_currentAssigner?.Cancel();
_currentAssigner = null;
}

View file

@ -41,13 +41,20 @@
Grid.Column="0"
Margin="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Center" ColumnDefinitions="Auto,*">
<TextBlock
VerticalAlignment="Center" ColumnDefinitions="Auto,*,Auto">
<StackPanel
Orientation="Vertical"
Margin="5,0,10,0"
Width="90"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Width="90">
<TextBlock
Text="{ext:Locale ControllerSettingsPlayer}" />
<TextBlock
Classes="pending"
Text ="{ext:Locale ControllerSettingsModifiedNotification}"
IsVisible="{Binding IsModified}"/>
</StackPanel>
<ComboBox
Grid.Column="1"
Name="PlayerIndexBox"
@ -62,6 +69,18 @@
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button
Grid.Column="2"
MinWidth="0"
Margin="5,0,0,0"
VerticalAlignment="Center"
ToolTip.Tip="{ext:Locale ControllerSettingsCancelCurrentChangesToolTip}"
Command="{Binding RevertChanges}">
<ui:SymbolIcon
Symbol="Undo"
FontSize="15"
Height="20" />
</Button>
</Grid>
<!-- Profile Selection -->
<Grid
@ -81,7 +100,8 @@
Name="ProfileBox"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
SelectedIndex="0"
SelectedItem="{Binding ProfileChoose, Mode=TwoWay}"
SelectionChanged="ComboBox_SelectionChanged"
ItemsSource="{Binding ProfilesList}"
Text="{Binding ProfileName, Mode=TwoWay}" />
<Button
@ -90,7 +110,7 @@
Margin="5,0,0,0"
VerticalAlignment="Center"
ToolTip.Tip="{ext:Locale ControllerSettingsLoadProfileToolTip}"
Command="{Binding LoadProfile}">
Command="{Binding LoadProfileButton}">
<ui:SymbolIcon
Symbol="View"
FontSize="15"
@ -148,7 +168,7 @@
MinWidth="0"
Margin="5,0,0,0"
VerticalAlignment="Center"
Command="{Binding LoadDevices}">
Command="{Binding LoadDevice}">
<ui:SymbolIcon
Symbol="Refresh"
FontSize="15"
@ -181,6 +201,28 @@
</Grid>
</Grid>
</StackPanel>
<ContentControl IsVisible="{Binding NotificationIsVisible}">
<ContentControl.Content>
<StackPanel>
<TextBlock
Margin="5,20,0,0"
Text="{Binding NotificationText}" />
<Button
MinWidth="0"
Width="90"
Height="27"
Margin="0,10,0,0"
VerticalAlignment="Center"
Command="{Binding UnlinkDevice}">
<TextBlock
Text="{ext:Locale ControllerSettingsUnlink}"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
</Button>
</StackPanel>
</ContentControl.Content>
</ContentControl>
<ContentControl Content="{Binding ConfigViewModel}" IsVisible="{Binding ShowSettings}">
<ContentControl.DataTemplates>
<DataTemplate DataType="viewModels:ControllerInputViewModel">

View file

@ -1,4 +1,5 @@
using Avalonia.Controls;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers;
@ -63,13 +64,22 @@ namespace Ryujinx.Ava.UI.Views.Input
return;
}
ViewModel.IsModified = false;
ViewModel.PlayerId = ViewModel.PlayerIdChoose;
ViewModel.IsModified = false;
}
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is FAComboBox faComboBox)
{
faComboBox.IsDropDownOpen = false;
ViewModel.IsModified = true;
}
}
public void Dispose()
{
ViewModel.Dispose();

View file

@ -9,6 +9,8 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels.Input;
using Ryujinx.Input;
using Ryujinx.Input.Assigner;
using System.Collections.Generic;
using System;
using Button = Ryujinx.Input.Button;
using Key = Ryujinx.Common.Configuration.Hid.Key;
@ -186,11 +188,63 @@ namespace Ryujinx.Ava.UI.Views.Input
{
bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
bool shouldRemoveBinding = e.GetCurrentPoint(this).Properties.IsRightButtonPressed;
if (shouldRemoveBinding)
{
DeleteBind();
}
_currentAssigner?.Cancel(shouldUnbind);
PointerPressed -= MouseClick;
}
private void DeleteBind()
{
if (_currentAssigner != null)
{
Dictionary<string, Action> buttonActions = new Dictionary<string, Action>
{
{ "ButtonZl", () => ViewModel.Config.ButtonZl = Key.Unbound },
{ "ButtonL", () => ViewModel.Config.ButtonL = Key.Unbound },
{ "ButtonMinus", () => ViewModel.Config.ButtonMinus = Key.Unbound },
{ "LeftStickButton", () => ViewModel.Config.LeftStickButton = Key.Unbound },
{ "LeftStickUp", () => ViewModel.Config.LeftStickUp = Key.Unbound },
{ "LeftStickDown", () => ViewModel.Config.LeftStickDown = Key.Unbound },
{ "LeftStickRight", () => ViewModel.Config.LeftStickRight = Key.Unbound },
{ "LeftStickLeft", () => ViewModel.Config.LeftStickLeft = Key.Unbound },
{ "DpadUp", () => ViewModel.Config.DpadUp = Key.Unbound },
{ "DpadDown", () => ViewModel.Config.DpadDown = Key.Unbound },
{ "DpadLeft", () => ViewModel.Config.DpadLeft = Key.Unbound },
{ "DpadRight", () => ViewModel.Config.DpadRight = Key.Unbound },
{ "LeftButtonSr", () => ViewModel.Config.LeftButtonSr = Key.Unbound },
{ "LeftButtonSl", () => ViewModel.Config.LeftButtonSl = Key.Unbound },
{ "RightButtonSr", () => ViewModel.Config.RightButtonSr = Key.Unbound },
{ "RightButtonSl", () => ViewModel.Config.RightButtonSl = Key.Unbound },
{ "ButtonZr", () => ViewModel.Config.ButtonZr = Key.Unbound },
{ "ButtonR", () => ViewModel.Config.ButtonR = Key.Unbound },
{ "ButtonPlus", () => ViewModel.Config.ButtonPlus = Key.Unbound },
{ "ButtonA", () => ViewModel.Config.ButtonA = Key.Unbound },
{ "ButtonB", () => ViewModel.Config.ButtonB = Key.Unbound },
{ "ButtonX", () => ViewModel.Config.ButtonX = Key.Unbound },
{ "ButtonY", () => ViewModel.Config.ButtonY = Key.Unbound },
{ "RightStickButton", () => ViewModel.Config.RightStickButton = Key.Unbound },
{ "RightStickUp", () => ViewModel.Config.RightStickUp = Key.Unbound },
{ "RightStickDown", () => ViewModel.Config.RightStickDown = Key.Unbound },
{ "RightStickRight", () => ViewModel.Config.RightStickRight = Key.Unbound },
{ "RightStickLeft", () => ViewModel.Config.RightStickLeft = Key.Unbound }
};
if (buttonActions.TryGetValue(_currentAssigner.ToggledButton.Name, out Action action))
{
action();
ViewModel.ParentModel.IsModified = true;
}
}
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);

View file

@ -10,6 +10,8 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Input;
using Ryujinx.Input.Assigner;
using System.Collections.Generic;
using System;
using Button = Ryujinx.Input.Button;
using Key = Ryujinx.Common.Configuration.Hid.Key;
@ -45,6 +47,50 @@ namespace Ryujinx.Ava.UI.Views.Settings
}
}
private void MouseClick(object sender, PointerPressedEventArgs e)
{
bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
bool shouldRemoveBinding = e.GetCurrentPoint(this).Properties.IsRightButtonPressed;
if (shouldRemoveBinding)
{
DeleteBind();
}
_currentAssigner?.Cancel(shouldUnbind);
PointerPressed -= MouseClick;
}
private void DeleteBind()
{
if (DataContext is not SettingsViewModel viewModel)
return;
if (_currentAssigner != null)
{
Dictionary<string, Action> buttonActions = new Dictionary<string, Action>
{
{ "ToggleVSyncMode", () => viewModel.KeyboardHotkey.ToggleVSyncMode = Key.Unbound },
{ "Screenshot", () => viewModel.KeyboardHotkey.Screenshot = Key.Unbound },
{ "ShowUI", () => viewModel.KeyboardHotkey.ShowUI = Key.Unbound },
{ "Pause", () => viewModel.KeyboardHotkey.Pause = Key.Unbound },
{ "ToggleMute", () => viewModel.KeyboardHotkey.ToggleMute = Key.Unbound },
{ "ResScaleUp", () => viewModel.KeyboardHotkey.ResScaleUp = Key.Unbound },
{ "ResScaleDown", () => viewModel.KeyboardHotkey.ResScaleDown = Key.Unbound },
{ "VolumeUp", () => viewModel.KeyboardHotkey.VolumeUp = Key.Unbound },
{ "VolumeDown", () => viewModel.KeyboardHotkey.VolumeDown = Key.Unbound },
{ "CustomVSyncIntervalIncrement", () => viewModel.KeyboardHotkey.CustomVSyncIntervalIncrement = Key.Unbound },
{ "CustomVSyncIntervalDecrement", () => viewModel.KeyboardHotkey.CustomVSyncIntervalDecrement = Key.Unbound }
};
if (buttonActions.TryGetValue(_currentAssigner.ToggledButton.Name, out Action action))
{
action();
}
}
}
private void Button_IsCheckedChanged(object sender, RoutedEventArgs e)
{
if (sender is ToggleButton button)