Compare commits

...
136 Commits
Author SHA1 Message Date
KamFretoZandrefractionpcsx2 3695862368 Qt/BPM: Minor icon tweaks 2024-01-31 14:45:03 +00:00
KamFretoZandrefractionpcsx2 18ae23b99d InputRec: Stop input recording on VM shutdown 2024-01-31 14:45:03 +00:00
Stenzekandrefractionpcsx2 bb60058fa0 Achievements: Handle fake memory map 2024-01-30 15:26:40 +00:00
Stenzekandrefractionpcsx2 1ad25605d1 GS: Check for D3D Mapping Layers and disable Vulkan if present 2024-01-30 15:26:21 +00:00
Stenzek 9809265be4 GS/Vulkan: Fix potential race between submit and main thread
Backport of https://github.com/stenzek/duckstation/commit/bcf7f55b93d6c61a66c1aabec5b8568d10a5b26c
2024-01-29 12:40:06 +10:00
Stenzek 63872e6b28 GS/Capture: Stop capture on VM shutdown 2024-01-28 21:23:05 +10:00
Stenzek fb3a9eae9b ImGuiOverlays: Use white font for recording time 2024-01-28 21:23:05 +10:00
Stenzek f53c3050df GS/Capture: Show video timestamp instead of wall time 2024-01-28 21:23:05 +10:00
PCSX2 BotandConnor McLaughlin 67bd0dfcdb Qt: Update Base Translation 2024-01-28 21:12:06 +10:00
Stenzek 12196359f7 Qt: Deprecate per-game WS/NI toggles in favor of Patches 2024-01-28 21:09:53 +10:00
Stenzek 609165e412 USB: Fix buffer copies in EyeToy 2024-01-28 17:04:24 +10:00
lightningterror 41f14a8cf8 GameDB: Add mipmap full with ps2 trilinear to SWAT Global Strike Team.
Improves building textures to match sw renderer.
2024-01-28 02:36:46 +01:00
lightningterror a8bdd3fbfc GameDB: Add gshwfixes to Band Hero.
Fixes character shadow misalignment.
Fixes icons.
2024-01-28 00:27:25 +01:00
refractionpcsx2 993ec82a9e GSDumpReplayer: Fix UI not responded to messages when replaying dumps 2024-01-27 16:38:54 +00:00
Stenzek c5a2844367 USB: Fix possible buffer overflow in webcam 2024-01-27 21:26:04 +10:00
Stenzek e5bb405b47 USB: Don't reset configuration when saving state 2024-01-27 21:26:04 +10:00
Stenzek 8c9a65d094 USB: Audio devices don't need port numbers 2024-01-27 21:26:04 +10:00
Stenzek 047b8593ac USB: Fix incorrect config keys for usb-headset 2024-01-27 21:26:04 +10:00
Stenzek 4fc4eb8a66 USB: Rewrite RingBuffer class
It was overflowing and corrupting the heap...
2024-01-27 21:26:04 +10:00
PCSX2 BotandConnor McLaughlin 1f95a86f0a Qt: Update Base Translation 2024-01-27 13:32:21 +10:00
lightningterrorandConnor McLaughlin 2b90451c4a Qt: Fix more compiler warnings.
-Wsign-compare, -Wunused-variable.
2024-01-27 13:30:45 +10:00
Stenzek 77a6525556 Counters: Move input poll to after throttle 2024-01-27 13:29:55 +10:00
refractionpcsx2 5eacab387d GameDB: Add Merge Targets to Shadow Hearts 2024-01-26 12:17:52 +00:00
refractionpcsx2 ddaf57d5b0 GS/HW: Kill old source using target if rect is outside target surface 2024-01-26 12:17:52 +00:00
Stenzek 1144c46109 ImGuiOverlays: Fix OSD margin 2024-01-26 19:47:50 +10:00
Stenzek 850b839fc3 Qt: Make "Ignore Inversion" a global mapping setting
Instead of being specific to DInput.
2024-01-26 18:14:08 +10:00
PCSX2 BotandConnor McLaughlin 22037e75ba Qt: Update Base Translation 2024-01-26 13:04:42 +10:00
TheLastRarandConnor McLaughlin 303ab163ab DEV9: Remove some casts in ATA Info 2024-01-26 13:03:06 +10:00
TheLastRarandConnor McLaughlin 2833537167 DEV9: Various ATA fixes 2024-01-26 13:03:06 +10:00
TheLastRarandConnor McLaughlin 1aa7b591b6 DEV9: LBA48 Support 2024-01-26 13:02:53 +10:00
KamFretoZandConnor McLaughlin 2f0463d936 Qt: Icon Refresh 2024-01-26 13:02:36 +10:00
TellowKrinkleandConnor McLaughlin 82a1ec0c3a Qt: Fix use of tr outside of Qt class 2024-01-26 12:48:37 +10:00
TellowKrinkleandConnor McLaughlin d65133451d Common: Add helper for creating an NSString from a string_view 2024-01-26 12:48:37 +10:00
TellowKrinkleandConnor McLaughlin 36e81949e0 Qt: Use proper Show in Finder on macOS 2024-01-26 12:48:37 +10:00
TellowKrinkleandConnor McLaughlin 6b62945632 CMake: Set qm files as non-source data in Xcode
Prevents their contents from coming up in searches
2024-01-26 12:48:37 +10:00
Stenzek fa2f578900 GS/HW: Handle more double-half clear edge cases
Spiderman: Web of Shadows clears its depth buffer with 32-bit FRAME
and 24-bit Z. So the upper 8 bits of half the depth buffer are not
cleared, yay. We can't turn this into a 32-bit clear, because then
it'll zero out those bits, which other games need (e.g. Jak 2). We
can't do a 24-bit clear, because something might rely on half those
bits actually getting zeroed. So, instead, we toss the depth buffer,
and let the mem clear path write out FRAME and Z separately, with
their associated masks. Limit it to black to avoid false positives.

Also fixes FBW getting blown out to 20 for a horizontal double-half
clear in Wakeboarding Unleashed.
2024-01-26 12:08:29 +10:00
JordanTheToasterandrefractionpcsx2 e1c9987059 GameDB: Hot Shots Golf Fore Fixes 2024-01-26 01:51:00 +00:00
GovanifYandConnor McLaughlin 325e219bb1 PINE: fix save state regression introduced during the switch to Qt
Ensure thread safety when loading/saving state
2024-01-25 20:05:44 +10:00
Dan McCarthyandConnor McLaughlin be208df11b Debugger: Allow copying address of memory search results
Adds the ability to copy the address directly of a memory search result through the right click context menu.
2024-01-25 16:55:43 +10:00
KamFretoZandConnor McLaughlin 49df804d1b FSUI: Add Recording Indicator and Time 2024-01-25 00:05:34 +10:00
JordanTheToasterandConnor McLaughlin 122fde79bd GameDB: Thrillville fixes 2024-01-24 20:07:12 +10:00
Pierre GRASSERandConnor McLaughlin 2099e68c41 GUI: Memory Card "slot" instead of "port"
"Slot" is the official term, we should use it instead of "port".
2024-01-24 20:06:54 +10:00
Dan McCarthyandConnor McLaughlin 52ccc609cd Debugger: Adds loading breakpoints/saved addresses from settings
Adds `/inis/debuggersettings/` settings folder to contain settings specifically for the debugger. Adds functionality to manually save (to settings) Breakpoints/Saved addresses and automatically load them upon launching the debugger.
2024-01-24 20:06:20 +10:00
Stenzek b402f6a404 Qt: Fix unclickable links in Setup Wizard 2024-01-24 17:49:18 +10:00
KamFretoZandConnor McLaughlin 3576a1824d Qt: Remove the duplicate memcard button 2024-01-24 13:47:20 +10:00
Stenzek c3afaae169 Qt: Remove NTFS compression checkbox on Linux/Mac 2024-01-24 13:46:47 +10:00
Stenzek c5a9ce6b56 MemoryCardFile: Log size/formatted state on load 2024-01-24 13:46:47 +10:00
Stenzek 4f0d944bb9 MemoryCardFile: Don't compress file on opening 2024-01-24 13:46:47 +10:00
Stenzek 5684bcb6f4 Qt: Explicitly set memcard compression regardless of choice
Fixes compressed cards being created when the directory has the
compressed flag set (probably from wx..).
2024-01-24 13:46:47 +10:00
JordanTheToasterandrefractionpcsx2 5087fcea88 GameDB: Various fixes 2024-01-23 18:52:09 +00:00
refractionpcsx2 28f984e87f GS/HW: Don't preload target from other targets after hw clear 2024-01-22 20:38:49 +00:00
PCSX2 Botandlightningterror e0233daeb0 PAD: Update to latest controller database. 2024-01-22 19:30:53 +01:00
refractionpcsx2 49922ebe32 GS/HW: Fix up Tekken 5 CRC hack to not remove post + break other scenes 2024-01-21 14:56:54 +00:00
MrlinkwiiandConnor McLaughlin 8fe0c3441c config: remove unused variables 2024-01-21 21:39:07 +10:00
PCSX2 BotandConnor McLaughlin ba55caa404 Qt: Update Base Translation 2024-01-21 19:28:44 +10:00
Stenzek e50e651078 Qt: Warning fix 2024-01-21 19:04:16 +10:00
Stenzek 39b4fd47c7 GS/HW: Fix incorrect page mask in ClearGSLocalMemory() 2024-01-21 19:04:16 +10:00
Stenzek 56b83e5cfa GS/HW: Fix double-half clears misfiring on CT32+Z24 when clearing depth 2024-01-21 19:04:16 +10:00
Stenzek ed57355948 GS/HW: Prevent creating texture with invalid mipmap levels
Fixes crash during loading in Jak with Metal renderer, and UB with
Vulkan.
2024-01-21 19:04:16 +10:00
Stenzek b4b2f3a0b6 GS/Metal: Don't discard alpha on RGB depth copy 2024-01-21 19:03:16 +10:00
TheTechnician27andrefractionpcsx2 1946882952 GameDB: A few trilinear+mipmap games 2024-01-21 09:00:09 +00:00
refractionpcsx2 dbe4930c17 GS: Correct flush reasons 2024-01-20 18:41:06 +00:00
Stenzek 3b25fa3065 GS/HW: Better avoid target uploads on HW clear 2024-01-21 00:49:35 +10:00
ZiemasandConnor McLaughlin 01849565aa SPU: VolumeSlide: disregard phase when exp + decr 2024-01-21 00:05:50 +10:00
Stenzek e3ca5833d0 GS/HW: Fix false positive on shared bits with double-half clears 2024-01-20 23:03:01 +10:00
Stenzek dfac1f034b Qt: Make Shift+Wheel scroll settings info panel 2024-01-20 22:58:22 +10:00
Stenzek a8d07df81d GunCon2: Fix cursor assertions in devbuilds 2024-01-20 22:58:22 +10:00
refractionpcsx2andlightningterror 609cb44b01 GS/HW: Optimize out some situations of texture loading 2024-01-20 06:05:49 +01:00
JordanTheToasterandrefractionpcsx2 feb4d605d0 GameDB: Various fixes 2: Electric Boogaloo
Revert VP2 changes as they cause issues and fix a shadow issue in Star Wars Force Unleashed.
2024-01-19 11:38:54 +00:00
JordanTheToasterandrefractionpcsx2 276d887917 GameDB: Various fixes 2024-01-19 08:27:43 +00:00
PCSX2 Botandlightningterror 61aef9c96f Qt: Update Base Translation 2024-01-18 16:56:06 +01:00
lightningterror b4005682f2 GS/HW: Fix compiler warnings. 2024-01-18 16:41:05 +01:00
Pierre GRASSERandrefractionpcsx2 7d98461fc6 Qt: Remove non-printable character from some strings
This non-printable character (U+FE0F, VARIATION SELECTOR 16) has been added for seemingly no reason to multiple strings and have polluted Translation Memory on Crowdin for some languages (👀).
Let's get rid of it.
2024-01-18 15:02:20 +00:00
Stenzek 862d03b78e FullscreenUI: Link create memory card to Qt dialog 2024-01-18 21:48:22 +10:00
Stenzek 0ecf46240f Qt: Fix OSD/Big Picture display for missing languages 2024-01-18 21:10:52 +10:00
Tyler WildingandGitHub a2755e212b translations: Syncing Crowdin translations (#10638)
* New translations pcsx2-qt_en.ts (Romanian)
[ci skip]

* New translations pcsx2-qt_en.ts (French)
[ci skip]

* New translations pcsx2-qt_en.ts (Spanish)
[ci skip]

* New translations pcsx2-qt_en.ts (Afrikaans)
[ci skip]

* New translations pcsx2-qt_en.ts (Arabic)
[ci skip]

* New translations pcsx2-qt_en.ts (Catalan)
[ci skip]

* New translations pcsx2-qt_en.ts (Czech)
[ci skip]

* New translations pcsx2-qt_en.ts (Danish)
[ci skip]

* New translations pcsx2-qt_en.ts (German)
[ci skip]

* New translations pcsx2-qt_en.ts (Greek)
[ci skip]

* New translations pcsx2-qt_en.ts (Finnish)
[ci skip]

* New translations pcsx2-qt_en.ts (Hebrew)
[ci skip]

* New translations pcsx2-qt_en.ts (Hungarian)
[ci skip]

* New translations pcsx2-qt_en.ts (Italian)
[ci skip]

* New translations pcsx2-qt_en.ts (Japanese)
[ci skip]

* New translations pcsx2-qt_en.ts (Korean)
[ci skip]

* New translations pcsx2-qt_en.ts (Lithuanian)
[ci skip]

* New translations pcsx2-qt_en.ts (Dutch)
[ci skip]

* New translations pcsx2-qt_en.ts (Norwegian)
[ci skip]

* New translations pcsx2-qt_en.ts (Polish)
[ci skip]

* New translations pcsx2-qt_en.ts (Portuguese)
[ci skip]

* New translations pcsx2-qt_en.ts (Russian)
[ci skip]

* New translations pcsx2-qt_en.ts (Serbian (Cyrillic))
[ci skip]

* New translations pcsx2-qt_en.ts (Swedish)
[ci skip]

* New translations pcsx2-qt_en.ts (Turkish)
[ci skip]

* New translations pcsx2-qt_en.ts (Ukrainian)
[ci skip]

* New translations pcsx2-qt_en.ts (Chinese Simplified)
[ci skip]

* New translations pcsx2-qt_en.ts (Chinese Traditional)
[ci skip]

* New translations pcsx2-qt_en.ts (Vietnamese)
[ci skip]

* New translations pcsx2-qt_en.ts (Portuguese, Brazilian)
[ci skip]

* New translations pcsx2-qt_en.ts (Indonesian)
[ci skip]

* New translations pcsx2-qt_en.ts (Persian)
[ci skip]

* New translations pcsx2-qt_en.ts (Croatian)
[ci skip]

* New translations pcsx2-qt_en.ts (Latvian)
[ci skip]

* New translations pcsx2-qt_en.ts (Hindi)
[ci skip]

* New translations pcsx2-qt_en.ts (Spanish, Latin America)
[ci skip]
2024-01-18 20:21:15 +10:00
forrvalhallaandrefractionpcsx2 2ec5559dd6 GameDB: Add HPO Native to SLAI 2024-01-18 09:28:34 +00:00
RedDevilusandrefractionpcsx2 6f904759ee GameDB: Gun Align to Native + typo fix
Looks better with the bloom and character shadows
2024-01-18 09:27:14 +00:00
RedPanda4552andConnor McLaughlin 507fafd601 Pad: Force multitapped slots to Not Connected if their multitap is missing 2024-01-18 14:05:21 +10:00
refractionpcsx2andConnor McLaughlin 9c463f1338 GS/HW: Add DS and Alpha Test checks 2024-01-18 13:33:34 +10:00
Stenzek 8818cd0285 GS/HW: Further improve no_rt heuristics
Reduces copies by almost 500 in Crash and Burn, few hundred drawcall
reductions in other games.
2024-01-18 13:33:34 +10:00
Stenzek 23b72d08d2 ImGuiOverlays: Fix analog input display 2024-01-17 19:02:33 +10:00
Stenzek 227049b6f2 FileSystem: Handle infinite symlink loops in FindFiles() 2024-01-17 13:57:19 +10:00
Stenzek 97abd3e1f9 ImGuiOverlays: Display inputs as integer, ignoring deadzone 2024-01-17 13:56:54 +10:00
Stenzek 6f34b7ba99 Pad: Add GetEffectiveInput()
Returns the value, incorporating any deadzone.
2024-01-17 13:56:54 +10:00
Alessa BakerandConnor McLaughlin c0d86c3852 Adding Jetbrains Rider to Gitignore. 2024-01-17 12:24:15 +10:00
Stenzek bf743ff467 gitignore: Add portable.ini/fix font paths 2024-01-16 22:13:56 +10:00
Connor McLaughlin 306f994464 CI/Linux: Use wildcard for AppImage libc downgrade 2024-01-16 21:43:25 +10:00
TheLastRarandrefractionpcsx2 f56676942b DEV9: Remove SDMA code 2024-01-16 10:45:14 +00:00
TheLastRarandrefractionpcsx2 bfd0a05289 DEV9: Fix ATA MDMA 2024-01-16 10:45:14 +00:00
JordanTheToasterandrefractionpcsx2 3999c08f00 GameDB: Various fixes 2024-01-16 10:43:38 +00:00
TheTechnician27andGitHub febb8ec1a6 GameDB: Fix water in Just Cause (#10645) 2024-01-16 10:29:31 +00:00
RedPanda4552andConnor McLaughlin cdd38ef7aa Game List: Ignore exclusion paths if they are empty string
Works around a bug of unknown origin which causes empty string to be added to the exclusions list, clearing the games list completely.
2024-01-16 18:38:18 +10:00
Stenzek 54c620a5df CI: Default to non-portable builds 2024-01-16 13:13:02 +10:00
Martino FontanaandConnor McLaughlin 089b7fa73e Build: Remove unused option DISABLE_BUILD_DATE 2024-01-16 13:12:20 +10:00
PCSX2 Botandlightningterror d9d0e84ca1 PAD: Update to latest controller database. 2024-01-15 17:17:01 +01:00
refractionpcsx2 badede2e2d GS/HW: ignore lower 3 bits of 16bit color for AEM check 2024-01-15 14:45:00 +00:00
Stenzek e2ae28741d Qt: Look for a file named DefaultUpdaterChannel.h
Make manual releases create this file, and make it contain

  #define DEFAULT_UPDATER_CHANNEL "stable"

So that the release defaults to the stable update channel.
2024-01-15 15:35:21 +10:00
Stenzek ff34150b15 Build: Simplify Git version extraction
Get rid of SysForwardDefs.h
Use last known git tag to determine version info, if it is not a tagged commit.
2024-01-15 15:35:21 +10:00
Tyler Wilding 4a93ceac58 Update Crowdin configuration file 2024-01-14 14:18:03 -05:00
JordanTheToasterandrefractionpcsx2 5a724bf49e GameDB: Flower sun and rain fixes 2024-01-14 17:40:58 +00:00
Connor McLaughlinandGitHub c23bcf6322 Qt: Remove debug popup after update cleanup 2024-01-14 18:36:01 +10:00
PCSX2 BotandConnor McLaughlin c863149ad9 Qt: Update Base Translation 2024-01-14 18:07:44 +10:00
Connor McLaughlin 5fb6e22bed Qt: Invoke Updater as Administrator for Program Files installs 2024-01-14 18:03:10 +10:00
refractionpcsx2 d634088282 GS/HW: Don't mark 24bit alpha as valid on upgrade 2024-01-14 06:56:57 +00:00
Stenzek c99a935831 CDVD: Fix block dump path generation 2024-01-14 15:23:25 +10:00
Stenzek 165da677ed Qt: Use native path separators for block dump 2024-01-14 15:23:25 +10:00
Stenzek 0bbde2ca52 IPU: Fix regression from #10617 2024-01-14 15:22:43 +10:00
Stenzek 3d13c5d13c CI: Allow user to override deps build path 2024-01-14 14:05:16 +10:00
Stenzek 9d978c67ec GS/DX11: Remove unused field 2024-01-14 12:51:51 +10:00
Stenzek 8766e1fa57 GS: Fix enum type return warnings 2024-01-14 12:51:51 +10:00
Stenzek c0e4883987 GS: Make GSVertex POD
Same code is generated with optimization (256-bit store in AVX2).
2024-01-14 12:51:51 +10:00
Stenzek 57f2cd5f9e GS: Make GSDrawingContext and GSDrawingEnvironment POD 2024-01-14 12:51:51 +10:00
Stenzek 50d8d06a94 GS: Make vector types POD
Generates the same code in Release, but slightly difference code in Debug.
In Debug, with the default copy assignment operator, it turns into two
8-byte moves. With the overloaded operator, it turns into a function call
with a vector move.
2024-01-14 12:51:51 +10:00
Stenzek 2e07328878 GS: Skip vertex append for GS_INVALID PRIM 2024-01-14 12:51:51 +10:00
Stenzek ad8294e521 GS: Remove unused vertex types 2024-01-14 12:51:51 +10:00
Stenzek 14426a7b45 GSCapture: Fix invalid substring comparison 2024-01-14 12:51:51 +10:00
Stenzek 6697e76be1 x86/iR5900: Fix signed/unsigned comparison in timeout loop 2024-01-14 12:51:51 +10:00
Stenzek 73cd876f6d SPU2: Make StereoOut16/32 POD 2024-01-14 12:51:51 +10:00
Stenzek e626754000 IPU: Remove last parameter from IDCT_Add
It was always being used uninitialized.
2024-01-14 12:51:51 +10:00
Stenzek 1fedd31229 HW: Make various DMAC/IPU/VIF register types POD 2024-01-14 12:51:51 +10:00
Stenzek bfe1746ddb Cache: Make CacheTag/CacheData POD 2024-01-14 12:51:51 +10:00
PCSX2 BotandConnor McLaughlin 4800c32db4 Qt: Update Base Translation 2024-01-13 12:27:29 +10:00
KamFretoZandConnor McLaughlin 140fc28b3e FSUI: Allow toggling fullscreen when VM is paused 2024-01-13 12:27:05 +10:00
Stenzek f9833bb8af Qt: Tidy up Tools menu
Make System Console and Verbose contingent on Advanced Settings being enabled.
Make Debug Console contingent on actually running under a debugger.
2024-01-13 12:26:34 +10:00
TheTechnician27andConnor McLaughlin 4b6ddaf09e Update VMManager.cpp to not count paused time toward time played
Hopefully resolves #10497. Between each update to played time, we calculate the sum of the deltas between VM resume and pause in order to subtract that off from the total session (paused and unpaused) session time.

Thus, if someone pauses the emulator, that time spent paused will no longer be reflected in the GameList.
2024-01-12 22:52:34 +10:00
Stenzek d427db4a15 GS/HW: Fix drawing with mismatched target sizes 2024-01-12 19:40:30 +10:00
Stenzek deb39cc20f CMake: Set LINUX in current and parent scope 2024-01-12 19:21:31 +10:00
Stenzek 3a4c25e916 VMManager: Force TimeStretch in Achievements HC Mode 2024-01-12 19:20:38 +10:00
f416eb3d4f Translation\UI: Updates Bitrate "Kbps" to "kpbs"
Co-Authored-By: KamFretoZ <14798312+kamfretoz@users.noreply.github.com>
2024-01-12 15:59:15 +10:00
Dan McCarthyandConnor McLaughlin 87cbb1f90c Settings: Adds description to 'All CRCs' on hover for cheat/patch settings
Add an on hover description to explain the purpose of the 'All CRCs' button in the Cheat and Patch Settings window.
2024-01-12 15:59:15 +10:00
Stenzek 68f43121fb MTGS: Explicitly set FP control register on startup
Linux appears? to inherit the value of MXCSR from the creating thread,
and that breaks parts of the software renderer.
2024-01-12 15:23:31 +10:00
Stenzek 51ceab1f3c PINE: Convert from class to namespace
Fewer global objects, indirect includes via headers.
2024-01-12 12:57:28 +10:00
Stenzek 2257992a3f PINE: Tidy up and fix shutdown hang on Linux 2024-01-12 12:57:28 +10:00
TellowKrinkleandConnor McLaughlin 40ead584d7 GS:MTL: Properly handle hdr rendering to cleared textures 2024-01-12 12:51:50 +10:00
PCSX2 BotandConnor McLaughlin 6f2be7bd17 Qt: Update Base Translation 2024-01-12 12:51:24 +10:00
236 changed files with 155645 additions and 123706 deletions
+2 -2
View File
@@ -64,7 +64,7 @@ jobs:
run: |
sudo rm -f /etc/apt/sources.list.d/ubuntu-toolchain-r-ubuntu-test-jammy.list
sudo apt-get update
sudo apt-get install -y --allow-downgrades libc6=2.35-0ubuntu3.5 libc6-dev=2.35-0ubuntu3.5 libstdc++6=12.3.0-1ubuntu1~22.04 libgcc-s1=12.3.0-1ubuntu1~22.04
sudo apt-get install -y --allow-downgrades 'libc6=2.35-0ubuntu*' 'libc6-dev=2.35-0ubuntu*' libstdc++6=12.3.0-1ubuntu1~22.04 libgcc-s1=12.3.0-1ubuntu1~22.04
- name: Checkout Repository
uses: actions/checkout@v4
@@ -120,7 +120,7 @@ jobs:
- name: Build Dependencies
if: steps.cache-deps.outputs.cache-hit != 'true'
run: .github/workflows/scripts/linux/build-dependencies-qt.sh
run: .github/workflows/scripts/linux/build-dependencies-qt.sh "$HOME/deps"
- name: Download patches
run: |
@@ -2,7 +2,12 @@
set -e
INSTALLDIR="$HOME/deps"
if [ "$#" -ne 1 ]; then
echo "Syntax: $0 <output directory>"
exit 1
fi
INSTALLDIR="$1"
NPROCS="$(getconf _NPROCESSORS_ONLN)"
SDL=SDL2-2.28.5
QT=6.6.1
+13 -4
View File
@@ -56,6 +56,9 @@ oprofile_data/
/UpgradeLog*.htm
/.vscode*
# Jetbrains Rider
/.idea*
# KDevelop 4 Workspace Configuration Files
*.kdev4
/.kdev4*
@@ -77,6 +80,7 @@ oprofile_data/
/bin/gamesettings
/bin/help
/bin/inis
/bin/inis/debuggersettings
/bin/logs
/bin/memcards
/bin/plugins
@@ -85,12 +89,17 @@ oprofile_data/
/bin/textures
/bin/translations
/bin/inputprofiles
/bin/videos
/bin/portable.ini
# Manually added by user.
/bin/resources/patches.zip
# Resources that are runtime downloaded.
/bin/resources/NotoSansJP-Regular.ttf
/bin/resources/NotoSansKR-Regular.ttf
/bin/resources/NotoSansSC-Regular.ttf
/bin/resources/NotoSansTC-Regular.ttf
/bin/resources/fonts/NotoSansJP-Regular.ttf
/bin/resources/fonts/NotoSansKR-Regular.ttf
/bin/resources/fonts/NotoSansSC-Regular.ttf
/bin/resources/fonts/NotoSansTC-Regular.ttf
/deps
/ipch
+1
View File
@@ -706,6 +706,7 @@
#define ICON_FA_RANDOM "\xef\x81\xb4" // U+f074
#define ICON_FA_RECEIPT "\xef\x95\x83" // U+f543
#define ICON_FA_RECORD_VINYL "\xef\xa3\x99" // U+f8d9
#define ICON_FA_RECORDING "\xef\xa3\x9a" // U+f8da
#define ICON_FA_RECYCLE "\xef\x86\xb8" // U+f1b8
#define ICON_FA_REDO "\xef\x80\x9e" // U+f01e
#define ICON_FA_REDO_ALT "\xef\x8b\xb9" // U+f2f9
+1428 -1142
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -1 +0,0 @@
RunWizard=0
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
+13 -5
View File
@@ -314,6 +314,7 @@
03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows,
03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows,
03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows,
03000000242e00006a48000000000000,Hyperkin RetroN Sq,a:b3,b:b7,back:b5,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b0,rightshoulder:b1,start:b4,x:b2,y:b6,platform:Windows,
03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Windows,
03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,
03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@@ -352,7 +353,7 @@
030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,
030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,lefttrigger:a2,righttrigger:a5,platform:Windows,
030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d0400001ec2000000000000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006d04000019c2000000000000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -461,7 +462,7 @@
030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,
03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,
03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
030000006f0e00008501000000000000,PDP Fightpad Pro GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
@@ -612,6 +613,7 @@
03000000050b00001a1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
03000000050b00001c1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
030000004f04000001d0000000000000,Rumble Force,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
030000000d0f0000ad00000000000000,RX Gamepad,a:b0,b:b4,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b6,start:b9,x:b2,y:b1,platform:Windows,
030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
@@ -678,6 +680,7 @@
03000000457500002211000000000000,Szmy Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000004f0400000ab1000000000000,T16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows,
030000000d0f00007b00000000000000,TAC GEAR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000e40a00000307000000000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows,
03000000e40a00000207000000000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows,
03000000d814000001a0000000000000,TE Kitty,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@@ -1018,6 +1021,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
030000000d0f0000f600000000010000,Switch Hori Pad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000e40a00000307000001000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,
03000000e40a00000207000001000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,
03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X,
@@ -1169,15 +1174,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c21100000791000011010000,Be1 GC101 Controller 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000c31100000791000011010000,Be1 GC101 Controller 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e0400008e02000003030000,Be1 GC101 Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000bc2000004d50000011010000,BEITONG A1T2 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000bc2000000055000001000000,BETOP AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000bc2000004d50000011010000,Beitong A1T2 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000bc2000000055000001000000,Betop AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000af1e00002400000010010000,ClockworkPI DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,
03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,
030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,
03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,
03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
@@ -1261,6 +1266,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000830500006020000010010000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
030000008f0e00001330000001010000,iCode Retro Adapter,b:b3,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b1,start:b7,x:b2,y:b0,platform:Linux,
050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,
@@ -1573,6 +1579,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000457500000401000011010000,SZMY Power DS4 Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000457500002211000010010000,SZMY Power Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000008f0e00001431000010010000,SZMY Power PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000e40a00000307000011010000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux,
03000000e40a00000207000011010000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Linux,
03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux,
03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000591c00002400000010010000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 98 KiB

+1 -1
View File
@@ -631,7 +631,7 @@ float4 sample_color(float2 st, float uv_w)
}
else if(PS_AEM_FMT == FMT_16)
{
c[i].a = c[i].a >= 0.5 ? TA.y : !PS_AEM || any(c[i].rgb) ? TA.x : 0;
c[i].a = c[i].a >= 0.5 ? TA.y : !PS_AEM || any(int3(c[i].rgb * 255.0f) & 0xF8) ? TA.x : 0;
}
}
+1 -1
View File
@@ -580,7 +580,7 @@ vec4 sample_color(vec2 st)
c[i].a = ( (PS_AEM == 0) || any(bvec3(c[i].rgb)) ) ? TA.x : 0.0f;
//c[i].a = ( (PS_AEM == 0) || (sum > 0.0f) ) ? TA.x : 0.0f;
#elif (PS_AEM_FMT == FMT_16)
c[i].a = c[i].a >= 0.5 ? TA.y : ( (PS_AEM == 0) || any(bvec3(c[i].rgb)) ) ? TA.x : 0.0f;
c[i].a = c[i].a >= 0.5 ? TA.y : ( (PS_AEM == 0) || any(bvec3(ivec3(c[i].rgb * 255.0f) & ivec3(0xF8))) ) ? TA.x : 0.0f;
//c[i].a = c[i].a >= 0.5 ? TA.y : ( (PS_AEM == 0) || (sum > 0.0f) ) ? TA.x : 0.0f;
#endif
}
+1 -1
View File
@@ -817,7 +817,7 @@ vec4 sample_color(vec2 st)
#if (PS_AEM_FMT == FMT_24)
c[i].a = (PS_AEM == 0 || any(bvec3(c[i].rgb))) ? TA.x : 0.0f;
#elif (PS_AEM_FMT == FMT_16)
c[i].a = (c[i].a >= 0.5) ? TA.y : ((PS_AEM == 0 || any(bvec3(c[i].rgb))) ? TA.x : 0.0f);
c[i].a = (c[i].a >= 0.5) ? TA.y : ((PS_AEM == 0 || any(bvec3(ivec3(c[i].rgb * 255.0f) & ivec3(0xF8)))) ? TA.x : 0.0f);
#endif
}
-6
View File
@@ -4,7 +4,6 @@ set(PCSX2_DEFS "")
#-------------------------------------------------------------------------------
# Misc option
#-------------------------------------------------------------------------------
option(DISABLE_BUILD_DATE "Disable including the binary compile date")
option(ENABLE_TESTS "Enables building the unit tests" ON)
option(LTO_PCSX2_CORE "Enable LTO/IPO/LTCG on the subset of pcsx2 that benefits most from it but not anything else")
option(USE_VTUNE "Plug VTUNE to profile GS JIT.")
@@ -231,11 +230,6 @@ endif()
set(PCSX2_WARNINGS ${DEFAULT_WARNINGS})
if(DISABLE_BUILD_DATE)
message(STATUS "Disabling the inclusion of the binary compile date.")
list(APPEND PCSX2_DEFS DISABLE_BUILD_DATE)
endif()
#-------------------------------------------------------------------------------
# MacOS-specific things
#-------------------------------------------------------------------------------
+50 -47
View File
@@ -1,7 +1,12 @@
function(detect_operating_system)
message(STATUS "CMake Version: ${CMAKE_VERSION}")
message(STATUS "CMake System Name: ${CMAKE_SYSTEM_NAME}")
# LINUX wasn't added until CMake 3.25.
if (CMAKE_VERSION VERSION_LESS 3.25.0 AND CMAKE_SYSTEM_NAME MATCHES "Linux")
# Have to make it visible in this scope as well for below.
set(LINUX TRUE PARENT_SCOPE)
set(LINUX TRUE)
endif()
if(WIN32)
@@ -39,19 +44,11 @@ function(detect_compiler)
endfunction()
function(get_git_version_info)
set(PCSX2_WC_TIME 0)
set(PCSX2_GIT_REV "")
set(PCSX2_GIT_TAG "")
set(PCSX2_GIT_HASH "")
if (GIT_FOUND AND EXISTS ${PROJECT_SOURCE_DIR}/.git)
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} show -s --format=%ci HEAD
OUTPUT_VARIABLE PCSX2_WC_TIME
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Output: "YYYY-MM-DD HH:MM:SS +HHMM" (last part is time zone, offset from UTC)
string(REGEX REPLACE "[%:\\-]" "" PCSX2_WC_TIME "${PCSX2_WC_TIME}")
string(REGEX REPLACE "([0-9]+) ([0-9]+).*" "\\1\\2" PCSX2_WC_TIME "${PCSX2_WC_TIME}")
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} describe
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} describe --tags
OUTPUT_VARIABLE PCSX2_GIT_REV
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
@@ -78,58 +75,61 @@ function(get_git_version_info)
OUTPUT_VARIABLE PCSX2_GIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} log -1 --format=%cd --date=local
OUTPUT_VARIABLE PCSX2_GIT_DATE
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
endif()
if ("${PCSX2_GIT_TAG}" MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" PCSX2_VERSION_LONG "${PCSX2_GIT_TAG}")
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" PCSX2_VERSION_SHORT "${PCSX2_GIT_TAG}")
elseif(PCSX2_GIT_REV)
set(PCSX2_VERSION_LONG "${PCSX2_GIT_REV}")
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?(-[a-z][a-z0-9]+)?" PCSX2_VERSION_SHORT "${PCSX2_VERSION_LONG}")
else()
set(PCSX2_VERSION_LONG "Unknown (git unavailable)")
set(PCSX2_VERSION_SHORT "Unknown")
endif()
if ("${PCSX2_WC_TIME}" STREQUAL "")
set(PCSX2_WC_TIME 0)
if (NOT PCSX2_GIT_REV)
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
OUTPUT_VARIABLE PCSX2_GIT_REV
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
if (NOT PCSX2_GIT_REV)
set(PCSX2_GIT_REV "Unknown")
endif()
endif()
set(PCSX2_WC_TIME "${PCSX2_WC_TIME}" PARENT_SCOPE)
set(PCSX2_GIT_REV "${PCSX2_GIT_REV}" PARENT_SCOPE)
set(PCSX2_GIT_TAG "${PCSX2_GIT_TAG}" PARENT_SCOPE)
set(PCSX2_GIT_HASH "${PCSX2_GIT_HASH}" PARENT_SCOPE)
set(PCSX2_VERSION_LONG "${PCSX2_VERSION_LONG}" PARENT_SCOPE)
set(PCSX2_VERSION_SHORT "${PCSX2_VERSION_SHORT}" PARENT_SCOPE)
set(PCSX2_GIT_DATE "${PCSX2_GIT_DATE}" PARENT_SCOPE)
endfunction()
function(write_svnrev_h)
if(PCSX2_GIT_TAG)
if ("${PCSX2_GIT_TAG}" MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
"#define SVN_REV ${PCSX2_WC_TIME}ll\n"
"#define GIT_TAG \"${PCSX2_GIT_TAG}\"\n"
"#define GIT_TAGGED_COMMIT 1\n"
"#define GIT_TAG_HI ${CMAKE_MATCH_1}\n"
"#define GIT_TAG_MID ${CMAKE_MATCH_2}\n"
"#define GIT_TAG_LO ${CMAKE_MATCH_3}\n"
"#define GIT_REV \"\"\n"
"#define GIT_HASH \"${PCSX2_GIT_HASH}\"\n"
)
else()
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
"#define SVN_REV ${PCSX2_WC_TIME}ll\n"
"#define GIT_TAG \"${PCSX2_GIT_TAG}\"\n"
"#define GIT_TAGGED_COMMIT 1\n"
"#define GIT_REV \"\"\n"
"#define GIT_HASH \"${PCSX2_GIT_HASH}\"\n"
)
endif()
else()
if ("${PCSX2_GIT_TAG}" MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
"#define GIT_TAG \"${PCSX2_GIT_TAG}\"\n"
"#define GIT_TAGGED_COMMIT 1\n"
"#define GIT_TAG_HI ${CMAKE_MATCH_1}\n"
"#define GIT_TAG_MID ${CMAKE_MATCH_2}\n"
"#define GIT_TAG_LO ${CMAKE_MATCH_3}\n"
"#define GIT_REV \"${PCSX2_GIT_TAG}\"\n"
"#define GIT_HASH \"${PCSX2_GIT_HASH}\"\n"
"#define GIT_DATE \"${PCSX2_GIT_DATE}\"\n"
)
elseif ("${PCSX2_GIT_REV}" MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)")
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
"#define SVN_REV ${PCSX2_WC_TIME}ll\n"
"#define GIT_TAG \"${PCSX2_GIT_TAG}\"\n"
"#define GIT_TAGGED_COMMIT 0\n"
"#define GIT_TAG_HI ${CMAKE_MATCH_1}\n"
"#define GIT_TAG_MID ${CMAKE_MATCH_2}\n"
"#define GIT_TAG_LO ${CMAKE_MATCH_3}\n"
"#define GIT_REV \"${PCSX2_GIT_REV}\"\n"
"#define GIT_HASH \"${PCSX2_GIT_HASH}\"\n"
"#define GIT_DATE \"${PCSX2_GIT_DATE}\"\n"
)
else()
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
"#define GIT_TAG \"${PCSX2_GIT_TAG}\"\n"
"#define GIT_TAGGED_COMMIT 0\n"
"#define GIT_TAG_HI 0\n"
"#define GIT_TAG_MID 0\n"
"#define GIT_TAG_LO 0\n"
"#define GIT_REV \"${PCSX2_GIT_REV}\"\n"
"#define GIT_HASH \"${PCSX2_GIT_HASH}\"\n"
"#define GIT_DATE \"${PCSX2_GIT_DATE}\"\n"
)
endif()
endfunction()
@@ -213,6 +213,9 @@ function(fixup_file_properties target)
if("${source}" MATCHES "\\.(inl|h)$")
set_source_files_properties("${source}" PROPERTIES XCODE_EXPLICIT_FILE_TYPE sourcecode.cpp.h)
endif()
if("${source}" MATCHES "\\.(qm)$")
set_source_files_properties("${source}" PROPERTIES XCODE_EXPLICIT_FILE_TYPE compiled)
endif()
# CMake makefile and ninja generators will attempt to share one PCH for both cpp and mm files
# That's not actually OK
if("${source}" MATCHES "\\.mm$")
+2
View File
@@ -23,6 +23,8 @@ namespace CocoaTools
std::optional<std::string> MoveToTrash(std::string_view file);
/// Launch the given application once this one quits
bool DelayedLaunch(std::string_view file);
/// Open a Finder window to the given URL
bool ShowInFinder(std::string_view file);
}
#endif // __APPLE__
+15 -2
View File
@@ -17,6 +17,11 @@
// MARK: - Metal Layers
static NSString*_Nonnull NSStringFromStringView(std::string_view sv)
{
return [[NSString alloc] initWithBytes:sv.data() length:sv.size() encoding:NSUTF8StringEncoding];
}
bool CocoaTools::CreateMetalLayer(WindowInfo* wi)
{
if (![NSThread isMainThread])
@@ -156,7 +161,7 @@ std::optional<std::string> CocoaTools::GetNonTranslocatedBundlePath()
std::optional<std::string> CocoaTools::MoveToTrash(std::string_view file)
{
NSURL* url = [NSURL fileURLWithPath:[[NSString alloc] initWithBytes:file.data() length:file.size() encoding:NSUTF8StringEncoding]];
NSURL* url = [NSURL fileURLWithPath:NSStringFromStringView(file)];
NSURL* new_url;
if (![[NSFileManager defaultManager] trashItemAtURL:url resultingItemURL:&new_url error:nil])
return std::nullopt;
@@ -170,9 +175,17 @@ bool CocoaTools::DelayedLaunch(std::string_view file)
[task setExecutableURL:[NSURL fileURLWithPath:@"/bin/sh"]];
[task setEnvironment:@{
@"WAITPID": [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]],
@"LAUNCHAPP": [[NSString alloc] initWithBytes:file.data() length:file.size() encoding:NSUTF8StringEncoding],
@"LAUNCHAPP": NSStringFromStringView(file),
}];
[task setArguments:@[@"-c", @"while /bin/ps -p $WAITPID > /dev/null; do /bin/sleep 0.1; done; exec /usr/bin/open \"$LAUNCHAPP\";"]];
return [task launchAndReturnError:nil];
}
}
// MARK: - Directory Services
bool CocoaTools::ShowInFinder(std::string_view file)
{
return [[NSWorkspace sharedWorkspace] selectFile:NSStringFromStringView(file)
inFileViewerRootedAtPath:nil];
}
+9
View File
@@ -271,6 +271,15 @@ cleanup:
#endif
}
bool Log::IsDebugOutputAvailable()
{
#ifdef _WIN32
return IsDebuggerPresent();
#else
return false;
#endif
}
bool Log::IsDebugOutputEnabled()
{
return (s_console_level > LOGLEVEL_NONE);
+1
View File
@@ -73,6 +73,7 @@ namespace Log
void SetConsoleOutputLevel(LOGLEVEL level);
// adds a debug console output
bool IsDebugOutputAvailable();
bool IsDebugOutputEnabled();
void SetDebugOutputLevel(LOGLEVEL level);
+92 -56
View File
@@ -1076,19 +1076,19 @@ static u32 TranslateWin32Attributes(u32 Win32Attributes)
}
static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path, const char* path, const char* pattern,
u32 flags, FileSystem::FindResultsArray* results)
u32 flags, FileSystem::FindResultsArray* results, std::vector<std::string>& visited)
{
std::string tempStr;
std::string search_dir;
if (path)
{
if (parent_path)
tempStr = StringUtil::StdStringFromFormat("%s\\%s\\%s\\*", origin_path, parent_path, path);
search_dir = fmt::format("{}\\{}\\{}\\*", origin_path, parent_path, path);
else
tempStr = StringUtil::StdStringFromFormat("%s\\%s\\*", origin_path, path);
search_dir = fmt::format("{}\\{}\\*", origin_path, path);
}
else
{
tempStr = StringUtil::StdStringFromFormat("%s\\*", origin_path);
search_dir = fmt::format("{}\\*", origin_path);
}
// holder for utf-8 conversion
@@ -1096,7 +1096,7 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
std::string utf8_filename;
utf8_filename.reserve((sizeof(wfd.cFileName) / sizeof(wfd.cFileName[0])) * 2);
HANDLE hFind = FindFirstFileW(StringUtil::UTF8StringToWideString(tempStr).c_str(), &wfd);
const HANDLE hFind = FindFirstFileW(StringUtil::UTF8StringToWideString(search_dir).c_str(), &wfd);
if (hFind == INVALID_HANDLE_VALUE)
return 0;
@@ -1104,7 +1104,7 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
bool hasWildCards = false;
bool wildCardMatchAll = false;
u32 nFiles = 0;
if (std::strpbrk(pattern, "*?") != nullptr)
if (std::strpbrk(pattern, "*?"))
{
hasWildCards = true;
wildCardMatchAll = !(std::strcmp(pattern, "*"));
@@ -1132,15 +1132,29 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
{
if (flags & FILESYSTEM_FIND_RECURSIVE)
{
// recurse into this directory
if (parent_path != nullptr)
{
const std::string recurseDir = StringUtil::StdStringFromFormat("%s\\%s", parent_path, path);
nFiles += RecursiveFindFiles(origin_path, recurseDir.c_str(), utf8_filename.c_str(), pattern, flags, results);
}
// check that we're not following an infinite symbolic link loop
std::string real_recurse_dir;
if (parent_path)
real_recurse_dir = Path::RealPath(fmt::format("{}\\{}\\{}\\{}", origin_path, parent_path, path, utf8_filename));
else if (path)
real_recurse_dir = Path::RealPath(fmt::format("{}\\{}\\{}", origin_path, path, utf8_filename));
else
real_recurse_dir = Path::RealPath(fmt::format("{}\\{}", origin_path, utf8_filename));
if (real_recurse_dir.empty() || std::find(visited.begin(), visited.end(), real_recurse_dir) == visited.end())
{
nFiles += RecursiveFindFiles(origin_path, path, utf8_filename.c_str(), pattern, flags, results);
if (!real_recurse_dir.empty())
visited.push_back(std::move(real_recurse_dir));
// recurse into this directory
if (parent_path)
{
const std::string recurse_dir = fmt::format("{}\\{}", parent_path, path);
nFiles += RecursiveFindFiles(origin_path, recurse_dir.c_str(), utf8_filename.c_str(), pattern, flags, results, visited);
}
else
{
nFiles += RecursiveFindFiles(origin_path, path, utf8_filename.c_str(), pattern, flags, results, visited);
}
}
}
@@ -1171,23 +1185,21 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
}
// add file to list
// TODO string formatter, clean this mess..
if (!(flags & FILESYSTEM_FIND_RELATIVE_PATHS))
{
if (parent_path != nullptr)
outData.FileName =
StringUtil::StdStringFromFormat("%s\\%s\\%s\\%s", origin_path, parent_path, path, utf8_filename.c_str());
else if (path != nullptr)
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s\\%s", origin_path, path, utf8_filename.c_str());
if (parent_path)
outData.FileName = fmt::format("{}\\{}\\{}\\{}", origin_path, parent_path, path, utf8_filename);
else if (path)
outData.FileName = fmt::format("{}\\{}\\{}", origin_path, path, utf8_filename);
else
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", origin_path, utf8_filename.c_str());
outData.FileName = fmt::format("{}\\{}", origin_path, utf8_filename);
}
else
{
if (parent_path != nullptr)
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s\\%s", parent_path, path, utf8_filename.c_str());
else if (path != nullptr)
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", path, utf8_filename.c_str());
if (parent_path)
outData.FileName = fmt::format("{}\\{}\\{}", parent_path, path, utf8_filename);
else if (path)
outData.FileName = fmt::format("{}\\{}", path, utf8_filename);
else
outData.FileName = utf8_filename;
}
@@ -1214,10 +1226,18 @@ bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, Fin
if (!(flags & FILESYSTEM_FIND_KEEP_ARRAY))
results->clear();
// enter the recursive function
return (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results) > 0);
}
// add self if recursive, we don't want to visit it twice
std::vector<std::string> visited;
if (flags & FILESYSTEM_FIND_RECURSIVE)
{
std::string real_path = Path::RealPath(path);
if (!real_path.empty())
visited.push_back(std::move(real_path));
}
// enter the recursive function
return (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) > 0);
}
static void TranslateStat64(struct stat* st, const struct _stat64& st64)
{
@@ -1620,23 +1640,23 @@ bool FileSystem::SetPathCompression(const char* path, bool enable)
static_assert(sizeof(off_t) == sizeof(s64));
static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, const char* Path, const char* Pattern,
u32 Flags, FileSystem::FindResultsArray* pResults)
u32 Flags, FileSystem::FindResultsArray* pResults, std::vector<std::string>& visited)
{
std::string tempStr;
if (Path)
{
if (ParentPath)
tempStr = StringUtil::StdStringFromFormat("%s/%s/%s", OriginPath, ParentPath, Path);
tempStr = fmt::format("{}/{}/{}", OriginPath, ParentPath, Path);
else
tempStr = StringUtil::StdStringFromFormat("%s/%s", OriginPath, Path);
tempStr = fmt::format("{}/{}", OriginPath, Path);
}
else
{
tempStr = StringUtil::StdStringFromFormat("%s", OriginPath);
tempStr = fmt::format("{}", OriginPath);
}
DIR* pDir = opendir(tempStr.c_str());
if (pDir == nullptr)
if (!pDir)
return 0;
// small speed optimization for '*' case
@@ -1663,12 +1683,12 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
}
std::string full_path;
if (ParentPath != nullptr)
full_path = StringUtil::StdStringFromFormat("%s/%s/%s/%s", OriginPath, ParentPath, Path, pDirEnt->d_name);
else if (Path != nullptr)
full_path = StringUtil::StdStringFromFormat("%s/%s/%s", OriginPath, Path, pDirEnt->d_name);
if (ParentPath)
full_path = fmt::format("{}/{}/{}/{}", OriginPath, ParentPath, Path, pDirEnt->d_name);
else if (Path)
full_path = fmt::format("{}/{}/{}", OriginPath, Path, pDirEnt->d_name);
else
full_path = StringUtil::StdStringFromFormat("%s/%s", OriginPath, pDirEnt->d_name);
full_path = fmt::format("{}/{}", OriginPath, pDirEnt->d_name);
FILESYSTEM_FIND_DATA outData;
outData.Attributes = 0;
@@ -1681,15 +1701,23 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
{
if (Flags & FILESYSTEM_FIND_RECURSIVE)
{
// recurse into this directory
if (ParentPath != nullptr)
// check that we're not following an infinite symbolic link loop
if (std::string real_recurse_dir = Path::RealPath(full_path);
real_recurse_dir.empty() || std::find(visited.begin(), visited.end(), real_recurse_dir) == visited.end())
{
std::string recursiveDir = StringUtil::StdStringFromFormat("%s/%s", ParentPath, Path);
nFiles += RecursiveFindFiles(OriginPath, recursiveDir.c_str(), pDirEnt->d_name, Pattern, Flags, pResults);
}
else
{
nFiles += RecursiveFindFiles(OriginPath, Path, pDirEnt->d_name, Pattern, Flags, pResults);
if (!real_recurse_dir.empty())
visited.push_back(std::move(real_recurse_dir));
// recurse into this directory
if (ParentPath)
{
const std::string recursive_dir = fmt::format("{}/{}", ParentPath, Path);
nFiles += RecursiveFindFiles(OriginPath, recursive_dir.c_str(), pDirEnt->d_name, Pattern, Flags, pResults, visited);
}
else
{
nFiles += RecursiveFindFiles(OriginPath, Path, pDirEnt->d_name, Pattern, Flags, pResults, visited);
}
}
}
@@ -1721,17 +1749,16 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
}
// add file to list
// TODO string formatter, clean this mess..
if (!(Flags & FILESYSTEM_FIND_RELATIVE_PATHS))
{
outData.FileName = std::move(full_path);
}
else
{
if (ParentPath != nullptr)
outData.FileName = StringUtil::StdStringFromFormat("%s/%s/%s", ParentPath, Path, pDirEnt->d_name);
else if (Path != nullptr)
outData.FileName = StringUtil::StdStringFromFormat("%s/%s", Path, pDirEnt->d_name);
if (ParentPath)
outData.FileName = fmt::format("{}/{}/{}", ParentPath, Path, pDirEnt->d_name);
else if (Path)
outData.FileName = fmt::format("{}/{}", Path, pDirEnt->d_name);
else
outData.FileName = pDirEnt->d_name;
}
@@ -1744,18 +1771,27 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
return nFiles;
}
bool FileSystem::FindFiles(const char* Path, const char* Pattern, u32 Flags, FindResultsArray* pResults)
bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results)
{
// has a path
if (Path[0] == '\0')
if (path[0] == '\0')
return false;
// clear result array
if (!(Flags & FILESYSTEM_FIND_KEEP_ARRAY))
pResults->clear();
if (!(flags & FILESYSTEM_FIND_KEEP_ARRAY))
results->clear();
// add self if recursive, we don't want to visit it twice
std::vector<std::string> visited;
if (flags & FILESYSTEM_FIND_RECURSIVE)
{
std::string real_path = Path::RealPath(path);
if (!real_path.empty())
visited.push_back(std::move(real_path));
}
// enter the recursive function
return (RecursiveFindFiles(Path, nullptr, nullptr, Pattern, Flags, pResults) > 0);
return (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) > 0);
}
bool FileSystem::StatFile(const char* path, struct stat* st)
+10
View File
@@ -55,6 +55,11 @@ using r128 = __m128i;
return _mm_set_epi64x(0, val);
}
[[maybe_unused]] __fi static r128 r128_from_u32_dup(u32 val)
{
return _mm_set1_epi32(val);
}
[[maybe_unused]] __fi static r128 r128_from_u32x4(u32 lo0, u32 lo1, u32 hi0, u32 hi1)
{
return _mm_setr_epi32(lo0, lo1, hi0, hi1);
@@ -150,6 +155,11 @@ using r128 = uint32x4_t;
return vreinterpretq_u32_u64(vcombine_u64(vcreate_u64(val), vcreate_u64(0)));
}
[[maybe_unused]] __fi static r128 r128_from_u32_dup(u32 val)
{
return vdupq_n_u32(val);
}
[[maybe_unused]] __fi static r128 r128_from_u32x4(u32 lo0, u32 lo1, u32 hi0, u32 hi1)
{
const u32 values[4] = {lo0, lo1, hi0, hi1};
+3
View File
@@ -6,6 +6,9 @@
#include "common/Threading.h"
#include "common/Assertions.h"
#include "common/RedtapeWindows.h"
#include <memory>
#include <mmsystem.h>
#include <process.h>
#include <timeapi.h>
+39 -45
View File
@@ -18,12 +18,15 @@ IF EXIST "%ProgramFiles%\Git\bin\git.exe" SET "GITPATH=%ProgramFiles%\Git\bin"
IF EXIST "%ProgramW6432%\Git\bin\git.exe" SET "GITPATH=%ProgramW6432%\Git\bin"
IF DEFINED GITPATH SET "PATH=%PATH%;%GITPATH%"
FOR /F "tokens=1-2" %%i IN ('"git show -s --format=%%%ci HEAD 2> NUL"') do (
set REV3=%%i%%j
)
FOR /F %%i IN ('"git describe 2> NUL"') do (
set GIT_REV=%%i
git describe --tags > NUL 2>NUL
if !ERRORLEVEL! EQU 0 (
FOR /F %%i IN ('"git describe --tags 2> NUL"') do (
set GIT_REV=%%i
)
) else (
FOR /F %%i IN ('"git rev-parse --short HEAD 2> NUL"') do (
set GIT_REV=%%i
)
)
FOR /F "tokens=* USEBACKQ" %%i IN (`git tag --points-at HEAD`) DO (
@@ -34,11 +37,11 @@ FOR /F "tokens=* USEBACKQ" %%i IN (`git rev-parse HEAD`) DO (
set GIT_HASH=%%i
)
set REV2=%REV3: =%
set REV1=%REV2:-=%
set REV=%REV1::=%
FOR /F "tokens=* USEBACKQ" %%i IN (`git log -1 "--format=%%cd" "--date=local"`) DO (
set GIT_DATE=%%i
)
SET SIGNATURELINE=// H[%GIT_HASH%] T[%GIT_TAG%]
SET SIGNATURELINE=// R[%GIT_REV%] H[%GIT_HASH%] T[%GIT_TAG%]
SET /P EXISTINGLINE=<"%CD%\svnrev.h"
IF "%EXISTINGLINE%"=="%SIGNATURELINE%" (
@@ -48,45 +51,36 @@ IF "%EXISTINGLINE%"=="%SIGNATURELINE%" (
ECHO Updating "%CD%\svnrev.h"...
echo %SIGNATURELINE%> "%CD%\svnrev.h"
git show -s > NUL 2>&1
if %ERRORLEVEL% NEQ 0 (
echo Automatic version detection unavailable.
echo If you want to have the version string print correctly,
echo make sure your Git.exe is in the default installation directory,
echo or in your PATH.
echo You can safely ignore this message - a dummy string will be printed.
echo #define GIT_HASH "%GIT_HASH%" >> "%CD%\svnrev.h"
echo #define GIT_TAG "%GIT_TAG%" >> "%CD%\svnrev.h"
echo #define GIT_DATE "%GIT_DATE%" >> "%CD%\svnrev.h"
echo #define SVN_REV_UNKNOWN >> "%CD%\svnrev.h"
echo #define SVN_REV 0ll >> "%CD%\svnrev.h"
echo #define GIT_REV "" >> "%CD%\svnrev.h"
echo #define GIT_HASH "" >> "%CD%\svnrev.h"
echo #define GIT_TAG "" >> "%CD%\svnrev.h"
echo #define GIT_TAGGED_COMMIT 0 >> "%CD%\svnrev.h"
echo %GIT_TAG%|FINDSTR /R "^v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$" > NUL
if !ERRORLEVEL! EQU 0 (
echo #define GIT_REV "%GIT_TAG%" >> "%CD%\svnrev.h"
echo #define GIT_TAGGED_COMMIT 1 >> "%CD%\svnrev.h"
FOR /F "tokens=1,2,3 delims=v." %%a in ("%GIT_TAG%") DO (
echo #define GIT_TAG_HI %%a >> "%CD%\svnrev.h"
echo #define GIT_TAG_MID %%b >> "%CD%\svnrev.h"
echo #define GIT_TAG_LO %%c >> "%CD%\svnrev.h"
)
) else (
:: Support New Tagged Release Model
if [%GIT_TAG%] NEQ [] (
echo Detected that the current commit is tagged, using that!
echo #define SVN_REV %REV%ll >> "%CD%\svnrev.h"
echo #define GIT_REV "" >> "%CD%\svnrev.h"
echo #define GIT_HASH "%GIT_HASH%" >> "%CD%\svnrev.h"
echo #define GIT_TAG "%GIT_TAG%" >> "%CD%\svnrev.h"
echo %GIT_TAG%|FINDSTR /R "^v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$" > NUL
if !ERRORLEVEL! EQU 0 (
FOR /F "tokens=1,2,3 delims=v." %%a in ("%GIT_TAG%") DO (
echo #define GIT_TAG_HI %%a >> "%CD%\svnrev.h"
echo #define GIT_TAG_MID %%b >> "%CD%\svnrev.h"
echo #define GIT_TAG_LO %%c >> "%CD%\svnrev.h"
)
:: Local branches
echo #define GIT_REV "%GIT_REV%" >> "%CD%\svnrev.h"
echo #define GIT_TAGGED_COMMIT 0 >> "%CD%\svnrev.h"
echo %GIT_REV%|FINDSTR /R "^v[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]-*" > NUL
if !ERRORLEVEL! EQU 0 (
FOR /F "tokens=1,2,3 delims=v." %%a in ("%GIT_REV%") DO (
echo #define GIT_TAG_HI %%a >> "%CD%\svnrev.h"
echo #define GIT_TAG_MID %%b >> "%CD%\svnrev.h"
FOR /F "tokens=1 delims=-" %%d in ("%%c%") DO (
echo #define GIT_TAG_LO %%d >> "%CD%\svnrev.h"
)
)
echo #define GIT_TAGGED_COMMIT 1 >> "%CD%\svnrev.h"
) else (
echo #define SVN_REV %REV%ll >> "%CD%\svnrev.h"
echo #define GIT_REV "%GIT_REV%" >> "%CD%\svnrev.h"
echo #define GIT_HASH "%GIT_HASH%" >> "%CD%\svnrev.h"
echo #define GIT_TAG "" >> "%CD%\svnrev.h"
echo #define GIT_TAGGED_COMMIT 0 >> "%CD%\svnrev.h"
echo #define GIT_TAG_HI 0 >> "%CD%\svnrev.h"
echo #define GIT_TAG_MID 0 >> "%CD%\svnrev.h"
echo #define GIT_TAG_LO 0 >> "%CD%\svnrev.h"
)
)
+3 -3
View File
@@ -1,5 +1,5 @@
pull_request_title: "translations: Syncing Crowdin translations"
commit_message: "[ci skip]"
pull_request_title: 'translations: Syncing Crowdin translations'
commit_message: '[ci skip]'
files:
- source: pcsx2-qt/Translations/pcsx2-qt_en.ts
translation: '/pcsx2-qt/Translations/pcsx2-qt_%locale%.ts'
translation: /pcsx2-qt/Translations/pcsx2-qt_%locale%.ts
+7 -1
View File
@@ -33,6 +33,7 @@
#include "pcsx2/GameList.h"
#include "pcsx2/Host.h"
#include "pcsx2/INISettingsInterface.h"
#include "pcsx2/ImGui/FullscreenUI.h"
#include "pcsx2/ImGui/ImGuiManager.h"
#include "pcsx2/Input/InputManager.h"
#include "pcsx2/MTGS.h"
@@ -391,6 +392,11 @@ void Host::OnCoverDownloaderOpenRequested()
// noop
}
void Host::OnCreateMemoryCardOpenRequested()
{
// noop
}
std::optional<u32> InputManager::ConvertHostKeyboardStringToCode(const std::string_view& str)
{
return std::nullopt;
@@ -701,7 +707,7 @@ int main(int argc, char* argv[])
return EXIT_SUCCESS;
}
void Host::VSyncOnCPUThread()
void Host::PumpMessagesOnCPUThread()
{
// update GS thread copy of frame number
MTGS::RunOnGSThread([frame_number = GSDumpReplayer::GetFrameNumber()]() { s_dump_frame_number = frame_number; });
+1 -1
View File
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#include "pcsx2/SysForwardDefs.h"
#include "pcsx2/SupportURLs.h"
#include "AboutDialog.h"
#include "QtHost.h"
+74 -49
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#include "AutoUpdaterDialog.h"
@@ -8,7 +8,6 @@
#include "QtUtils.h"
#include "pcsx2/Host.h"
#include "pcsx2/SysForwardDefs.h"
#include "svnrev.h"
#include "updater/UpdaterExtractor.h"
@@ -16,8 +15,10 @@
#include "common/Assertions.h"
#include "common/CocoaTools.h"
#include "common/Console.h"
#include "common/Error.h"
#include "common/FileSystem.h"
#include "common/HTTPDownloader.h"
#include "common/Path.h"
#include "common/StringUtil.h"
#include "cpuinfo.h"
@@ -38,12 +39,17 @@
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QProgressDialog>
#ifdef _WIN32
#include "common/RedtapeWindows.h"
#include <shellapi.h>
#endif
// Interval at which HTTP requests are polled.
static constexpr u32 HTTP_POLL_INTERVAL = 10;
// Logic to detect whether we can use the auto updater.
// We use tagged commit, because this gets set on nightly builds.
#if (defined(_WIN32) || defined(__linux__) || defined(__APPLE__)) && defined(GIT_TAG_LO)
#if (defined(_WIN32) || defined(__linux__) || defined(__APPLE__)) && GIT_TAGGED_COMMIT
#define AUTO_UPDATER_SUPPORTED 1
@@ -73,8 +79,13 @@ static constexpr u32 HTTP_POLL_INTERVAL = 10;
// Available release channels.
static const char* UPDATE_TAGS[] = {"stable", "nightly"};
// Bit annoying, because PCSX2_isReleaseVersion is a bool, but whatever.
#define THIS_RELEASE_TAG (PCSX2_isReleaseVersion ? "stable" : "nightly")
// TODO: Make manual releases create this file, and make it contain `#define DEFAULT_UPDATER_CHANNEL "stable"`.
#if __has_include("DefaultUpdaterChannel.h")
#include "DefaultUpdaterChannel.h"
#endif
#ifndef DEFAULT_UPDATER_CHANNEL
#define DEFAULT_UPDATER_CHANNEL "nightly"
#endif
#endif
@@ -129,7 +140,7 @@ QStringList AutoUpdaterDialog::getTagList()
std::string AutoUpdaterDialog::getDefaultTag()
{
#ifdef AUTO_UPDATER_SUPPORTED
return THIS_RELEASE_TAG;
return DEFAULT_UPDATER_CHANNEL;
#else
return {};
#endif
@@ -142,15 +153,13 @@ QString AutoUpdaterDialog::getCurrentVersion()
QString AutoUpdaterDialog::getCurrentVersionDate()
{
// 20220403235450ll
const QDateTime current_build_date(QDateTime::fromString(QStringLiteral("%1").arg(SVN_REV), "yyyyMMddhhmmss"));
return current_build_date.toString();
return QStringLiteral(GIT_DATE);
}
QString AutoUpdaterDialog::getCurrentUpdateTag() const
{
#ifdef AUTO_UPDATER_SUPPORTED
return QString::fromStdString(Host::GetBaseStringSettingValue("AutoUpdater", "UpdateTag", THIS_RELEASE_TAG));
return QString::fromStdString(Host::GetBaseStringSettingValue("AutoUpdater", "UpdateTag", DEFAULT_UPDATER_CHANNEL));
#else
return QString();
#endif
@@ -566,70 +575,74 @@ void AutoUpdaterDialog::remindMeLaterClicked()
#if defined(_WIN32)
bool AutoUpdaterDialog::doesUpdaterNeedElevation(const std::string& application_dir) const
{
// Try to create a dummy text file in the PCSX2 updater directory. If it fails, we probably won't have write permission.
const std::string dummy_path = Path::Combine(application_dir, "update.txt");
auto fp = FileSystem::OpenManagedCFile(dummy_path.c_str(), "wb");
if (!fp)
return true;
fp.reset();
FileSystem::DeleteFilePath(dummy_path.c_str());
return false;
}
bool AutoUpdaterDialog::processUpdate(const std::vector<u8>& data, QProgressDialog&)
{
const QString update_directory = QCoreApplication::applicationDirPath();
const QString update_zip_path = QStringLiteral("%1" FS_OSPATH_SEPARATOR_STR "%2").arg(update_directory).arg(UPDATER_ARCHIVE_NAME);
const QString updater_path = QStringLiteral("%1" FS_OSPATH_SEPARATOR_STR "%2").arg(update_directory).arg(UPDATER_EXECUTABLE);
const std::string& application_dir = EmuFolders::AppRoot;
const std::string update_zip_path = Path::Combine(EmuFolders::DataRoot, UPDATER_ARCHIVE_NAME);
const std::string updater_path = Path::Combine(EmuFolders::DataRoot, UPDATER_EXECUTABLE);
Q_ASSERT(!update_zip_path.isEmpty() && !updater_path.isEmpty() && !update_directory.isEmpty());
if ((QFile::exists(update_zip_path) && !QFile::remove(update_zip_path)) ||
(QFile::exists(updater_path) && !QFile::remove(updater_path)))
if ((FileSystem::FileExists(update_zip_path.c_str()) && !FileSystem::DeleteFilePath(update_zip_path.c_str())))
{
reportError("Removing existing update zip/updater failed");
reportError("Removing existing update zip failed");
return false;
}
if (!FileSystem::WriteBinaryFile(update_zip_path.c_str(), data.data(), data.size()))
{
QFile update_zip_file(update_zip_path);
if (!update_zip_file.open(QIODevice::WriteOnly) ||
update_zip_file.write(reinterpret_cast<const char*>(data.data()), static_cast<qint64>(data.size())) != static_cast<qint64>(data.size()))
{
reportError("Writing update zip to '%s' failed", update_zip_path.toUtf8().constData());
return false;
}
update_zip_file.close();
reportError("Writing update zip to '%s' failed", update_zip_path.c_str());
return false;
}
std::string updater_extract_error;
if (!ExtractUpdater(update_zip_path.toUtf8().constData(), updater_path.toUtf8().constData(), &updater_extract_error))
if (!ExtractUpdater(update_zip_path.c_str(), updater_path.c_str(), &updater_extract_error))
{
reportError("Extracting updater failed: %s", updater_extract_error.c_str());
return false;
}
if (!doUpdate(update_zip_path, updater_path, update_directory))
{
reportError("Launching updater failed");
return false;
}
return true;
return doUpdate(application_dir, update_zip_path, updater_path);
}
bool AutoUpdaterDialog::doUpdate(const QString& zip_path, const QString& updater_path, const QString& destination_path)
bool AutoUpdaterDialog::doUpdate(const std::string& application_dir, const std::string& zip_path, const std::string& updater_path)
{
const QString program_path = QCoreApplication::applicationFilePath();
if (program_path.isEmpty())
const std::string program_path = QDir::toNativeSeparators(QCoreApplication::applicationFilePath()).toStdString();
if (program_path.empty())
{
reportError("Failed to get current application path");
return false;
}
QStringList arguments;
arguments << QString::number(QCoreApplication::applicationPid());
arguments << destination_path;
arguments << zip_path;
arguments << program_path;
const std::wstring wupdater_path = StringUtil::UTF8StringToWideString(updater_path);
const std::wstring wapplication_dir = StringUtil::UTF8StringToWideString(application_dir);
const std::wstring arguments = StringUtil::UTF8StringToWideString(fmt::format("{} \"{}\" \"{}\" \"{}\"",
QCoreApplication::applicationPid(), application_dir, zip_path, program_path));
// this will leak, but not sure how else to handle it...
QProcess* updater_process = new QProcess();
updater_process->setProgram(updater_path);
updater_process->setArguments(arguments);
updater_process->start(QIODevice::NotOpen);
if (!updater_process->waitForStarted())
const bool needs_elevation = doesUpdaterNeedElevation(application_dir);
SHELLEXECUTEINFOW sei = {};
sei.cbSize = sizeof(sei);
sei.lpVerb = needs_elevation ? L"runas" : nullptr; // needed to trigger elevation
sei.lpFile = wupdater_path.c_str();
sei.lpParameters = arguments.c_str();
sei.lpDirectory = wapplication_dir.c_str();
sei.nShow = SW_SHOWNORMAL;
if (!ShellExecuteExW(&sei))
{
reportError("Failed to start updater");
reportError("Failed to start %s: %s", needs_elevation ? "elevated updater" : "updater",
Error::CreateWin32(GetLastError()).GetDescription().c_str());
return false;
}
@@ -638,7 +651,19 @@ bool AutoUpdaterDialog::doUpdate(const QString& zip_path, const QString& updater
void AutoUpdaterDialog::cleanupAfterUpdate()
{
// Nothing to do on Windows for now, the updater stub cleans everything up.
// If we weren't portable, then updater executable gets left in the application directory.
if (EmuFolders::AppRoot == EmuFolders::DataRoot)
return;
const std::string updater_path = Path::Combine(EmuFolders::DataRoot, UPDATER_EXECUTABLE);
if (!FileSystem::FileExists(updater_path.c_str()))
return;
if (!FileSystem::DeleteFilePath(updater_path.c_str()))
{
QMessageBox::critical(nullptr, tr("Updater Error"), tr("Failed to remove updater exe after update."));
return;
}
}
#elif defined(__linux__)
+3 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#pragma once
@@ -60,7 +60,8 @@ private:
bool processUpdate(const std::vector<u8>& data, QProgressDialog& progress);
#if defined(_WIN32)
bool doUpdate(const QString& zip_path, const QString& updater_path, const QString& destination_path);
bool doesUpdaterNeedElevation(const std::string& application_dir) const;
bool doUpdate(const std::string& application_dir, const std::string& zip_path, const std::string& updater_path);
#endif
Ui::AutoUpdaterDialog m_ui;
+4
View File
@@ -75,6 +75,7 @@ target_sources(pcsx2-qt PRIVATE
Settings/ControllerGlobalSettingsWidget.ui
Settings/ControllerMacroEditWidget.ui
Settings/ControllerMacroWidget.ui
Settings/ControllerMappingSettingsDialog.ui
Settings/ControllerMouseSettingsDialog.ui
Settings/ControllerSettingsWindow.cpp
Settings/ControllerSettingsWindow.h
@@ -149,6 +150,8 @@ target_sources(pcsx2-qt PRIVATE
Debugger/CpuWidget.cpp
Debugger/CpuWidget.h
Debugger/CpuWidget.ui
Debugger/DebuggerSettingsManager.cpp
Debugger/DebuggerSettingsManager.h
Debugger/DebuggerWindow.cpp
Debugger/DebuggerWindow.h
Debugger/DebuggerWindow.ui
@@ -247,4 +250,5 @@ if(WIN32)
)
endif()
fixup_file_properties(pcsx2-qt)
setup_main_executable(pcsx2-qt)
+104 -144
View File
@@ -8,6 +8,7 @@
#include "Models/BreakpointModel.h"
#include "Models/ThreadModel.h"
#include "Models/SavedAddressesModel.h"
#include "Debugger/DebuggerSettingsManager.h"
#include "DebugTools/DebugInterface.h"
#include "DebugTools/Breakpoints.h"
@@ -45,6 +46,15 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
m_ui.setupUi(this);
connect(g_emu_thread, &EmuThread::onVMPaused, this, &CpuWidget::onVMPaused);
connect(g_emu_thread, &EmuThread::onGameChanged, [this](const QString& title) {
if (title.isEmpty())
return;
// Don't overwrite users BPs/Saved Addresses unless they have a clean state.
if (m_bpModel.rowCount() == 0)
DebuggerSettingsManager::loadGameSettings(&m_bpModel);
if (m_savedAddressesModel.rowCount() == 0)
DebuggerSettingsManager::loadGameSettings(&m_savedAddressesModel);
});
connect(m_ui.registerWidget, &RegisterWidget::gotoInDisasm, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddress);
connect(m_ui.memoryviewWidget, &MemoryViewWidget::gotoInDisasm, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddress);
@@ -143,9 +153,12 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
m_ui.savedAddressesList->horizontalHeader()->setSectionResizeMode(i++, mode);
}
QTableView* savedAddressesTableView = m_ui.savedAddressesList;
connect(m_ui.savedAddressesList->model(), &QAbstractItemModel::dataChanged, [savedAddressesTableView](const QModelIndex& topLeft) {
connect(m_ui.savedAddressesList->model(), &QAbstractItemModel::dataChanged, [savedAddressesTableView](const QModelIndex& topLeft) {
savedAddressesTableView->resizeColumnToContents(topLeft.column());
});
DebuggerSettingsManager::loadGameSettings(&m_bpModel);
DebuggerSettingsManager::loadGameSettings(&m_savedAddressesModel);
}
CpuWidget::~CpuWidget() = default;
@@ -301,46 +314,63 @@ void CpuWidget::onBPListDoubleClicked(const QModelIndex& index)
void CpuWidget::onBPListContextMenu(QPoint pos)
{
if (!m_cpu.isAlive())
return;
QMenu* contextMenu = new QMenu(tr("Breakpoint List Context Menu"), m_ui.breakpointList);
QAction* newAction = new QAction(tr("New"), m_ui.breakpointList);
connect(newAction, &QAction::triggered, this, &CpuWidget::contextBPListNew);
contextMenu->addAction(newAction);
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
if (selModel->hasSelection())
if (m_cpu.isAlive())
{
QAction* editAction = new QAction(tr("Edit"), m_ui.breakpointList);
connect(editAction, &QAction::triggered, this, &CpuWidget::contextBPListEdit);
contextMenu->addAction(editAction);
if (selModel->selectedIndexes().count() == 1)
QAction* newAction = new QAction(tr("New"), m_ui.breakpointList);
connect(newAction, &QAction::triggered, this, &CpuWidget::contextBPListNew);
contextMenu->addAction(newAction);
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
if (selModel->hasSelection())
{
QAction* copyAction = new QAction(tr("Copy"), m_ui.breakpointList);
connect(copyAction, &QAction::triggered, this, &CpuWidget::contextBPListCopy);
contextMenu->addAction(copyAction);
}
QAction* editAction = new QAction(tr("Edit"), m_ui.breakpointList);
connect(editAction, &QAction::triggered, this, &CpuWidget::contextBPListEdit);
contextMenu->addAction(editAction);
QAction* deleteAction = new QAction(tr("Delete"), m_ui.breakpointList);
connect(deleteAction, &QAction::triggered, this, &CpuWidget::contextBPListDelete);
contextMenu->addAction(deleteAction);
if (selModel->selectedIndexes().count() == 1)
{
QAction* copyAction = new QAction(tr("Copy"), m_ui.breakpointList);
connect(copyAction, &QAction::triggered, this, &CpuWidget::contextBPListCopy);
contextMenu->addAction(copyAction);
}
QAction* deleteAction = new QAction(tr("Delete"), m_ui.breakpointList);
connect(deleteAction, &QAction::triggered, this, &CpuWidget::contextBPListDelete);
contextMenu->addAction(deleteAction);
}
}
contextMenu->addSeparator();
QAction* actionExport = new QAction(tr("Copy all as CSV"), m_ui.breakpointList);
connect(actionExport, &QAction::triggered, [this]() {
// It's important to use the Export Role here to allow pasting to be translation agnostic
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.breakpointList->model(), BreakpointModel::ExportRole, true));
});
contextMenu->addAction(actionExport);
if (m_bpModel.rowCount() > 0)
{
QAction* actionExport = new QAction(tr("Copy all as CSV"), m_ui.breakpointList);
connect(actionExport, &QAction::triggered, [this]() {
// It's important to use the Export Role here to allow pasting to be translation agnostic
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.breakpointList->model(), BreakpointModel::ExportRole, true));
});
contextMenu->addAction(actionExport);
}
QAction* actionImport = new QAction(tr("Paste from CSV"), m_ui.breakpointList);
connect(actionImport, &QAction::triggered, this, &CpuWidget::contextBPListPasteCSV);
contextMenu->addAction(actionImport);
if (m_cpu.isAlive())
{
QAction* actionImport = new QAction(tr("Paste from CSV"), m_ui.breakpointList);
connect(actionImport, &QAction::triggered, this, &CpuWidget::contextBPListPasteCSV);
contextMenu->addAction(actionImport);
QAction* actionLoad = new QAction(tr("Load from Settings"), m_ui.breakpointList);
connect(actionLoad, &QAction::triggered, [this]() {
m_bpModel.clear();
DebuggerSettingsManager::loadGameSettings(&m_bpModel);
});
contextMenu->addAction(actionLoad);
QAction* actionSave = new QAction(tr("Save to Settings"), m_ui.breakpointList);
connect(actionSave, &QAction::triggered, this, &CpuWidget::saveBreakpointsToDebuggerSettings);
contextMenu->addAction(actionSave);
}
contextMenu->popup(m_ui.breakpointList->viewport()->mapToGlobal(pos));
}
@@ -407,7 +437,7 @@ void CpuWidget::contextBPListPasteCSV()
// In order to handle text with commas in them we must wrap values in quotes to mark
// where a value starts and end so that text commas aren't identified as delimiters.
// So matches each quote pair, parse it out, and removes the quotes to get the value.
QRegularExpression eachQuotePair(R"("([^"]|\\.)*")");
QRegularExpression eachQuotePair(R"("([^"]|\\.)*")");
QRegularExpressionMatchIterator it = eachQuotePair.globalMatch(line);
while (it.hasNext())
{
@@ -415,98 +445,7 @@ void CpuWidget::contextBPListPasteCSV()
QString matchedValue = match.captured(0);
fields << matchedValue.mid(1, matchedValue.length() - 2);
}
if (fields.size() != BreakpointModel::BreakpointColumns::COLUMN_COUNT)
{
Console.WriteLn("Debugger CSV Import: Invalid number of columns, skipping");
continue;
}
bool ok;
const int type = fields[BreakpointModel::BreakpointColumns::TYPE].toUInt(&ok);
if (!ok)
{
Console.WriteLn("Debugger CSV Import: Failed to parse type '%s', skipping", fields[BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
continue;
}
// This is how we differentiate between breakpoints and memchecks
if (type == MEMCHECK_INVALID)
{
BreakPoint bp;
// Address
bp.addr = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16);
if (!ok)
{
Console.WriteLn("Debugger CSV Import: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData());
continue;
}
// Condition
if (!fields[BreakpointModel::BreakpointColumns::CONDITION].isEmpty())
{
PostfixExpression expr;
bp.hasCond = true;
bp.cond.debug = &m_cpu;
if (!m_cpu.initExpression(fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), expr))
{
Console.WriteLn("Debugger CSV Import: Failed to parse cond '%s', skipping", fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData());
continue;
}
bp.cond.expression = expr;
strncpy(&bp.cond.expressionString[0], fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), sizeof(bp.cond.expressionString));
}
// Enabled
bp.enabled = fields[BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
if (!ok)
{
Console.WriteLn("Debugger CSV Import: Failed to parse enable flag '%s', skipping", fields[BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData());
continue;
}
m_bpModel.insertBreakpointRows(0, 1, {bp});
}
else
{
MemCheck mc;
// Mode
if (type >= MEMCHECK_INVALID)
{
Console.WriteLn("Debugger CSV Import: Failed to parse cond type '%s', skipping", fields [BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
continue;
}
mc.cond = static_cast<MemCheckCondition>(type);
// Address
mc.start = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16);
if (!ok)
{
Console.WriteLn("Debugger CSV Import: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData());
continue;
}
// Size
mc.end = fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUInt(&ok) + mc.start;
if (!ok)
{
Console.WriteLn("Debugger CSV Import: Failed to parse length '%s', skipping", fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUtf8().constData());
continue;
}
// Result
const int result = fields [BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
if (!ok)
{
Console.WriteLn("Debugger CSV Import: Failed to parse result flag '%s', skipping", fields [BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData());
continue;
}
mc.result = static_cast<MemCheckResult>(result);
m_bpModel.insertBreakpointRows(0, 1, {mc});
}
m_bpModel.loadBreakpointFromFieldList(fields);
}
}
@@ -561,7 +500,19 @@ void CpuWidget::onSavedAddressesListContextMenu(QPoint pos)
connect(actionImportCSV, &QAction::triggered, this, &CpuWidget::contextSavedAddressesListPasteCSV);
contextMenu->addAction(actionImportCSV);
contextMenu->popup(m_ui.savedAddressesList->viewport()->mapToGlobal(pos));
if (m_cpu.isAlive())
{
QAction* actionLoad = new QAction(tr("Load from Settings"), m_ui.savedAddressesList);
connect(actionLoad, &QAction::triggered, [this]() {
m_savedAddressesModel.clear();
DebuggerSettingsManager::loadGameSettings(&m_savedAddressesModel);
});
contextMenu->addAction(actionLoad);
QAction* actionSave = new QAction(tr("Save to Settings"), m_ui.savedAddressesList);
connect(actionSave, &QAction::triggered, this, &CpuWidget::saveSavedAddressesToDebuggerSettings);
contextMenu->addAction(actionSave);
}
if (isIndexValid)
{
@@ -571,6 +522,8 @@ void CpuWidget::onSavedAddressesListContextMenu(QPoint pos)
});
contextMenu->addAction(deleteAction);
}
contextMenu->popup(m_ui.savedAddressesList->viewport()->mapToGlobal(pos));
}
void CpuWidget::contextSavedAddressesListPasteCSV()
@@ -594,24 +547,7 @@ void CpuWidget::contextSavedAddressesListPasteCSV()
fields << matchedValue.mid(1, matchedValue.length() - 2);
}
if (fields.size() != SavedAddressesModel::HeaderColumns::COLUMN_COUNT)
{
Console.WriteLn("Debugger CSV Import: Invalid number of columns, skipping");
continue;
}
bool ok;
const u32 address = fields[SavedAddressesModel::HeaderColumns::ADDRESS].toUInt(&ok, 16);
if (!ok)
{
Console.WriteLn("Debugger CSV Import: Failed to parse address '%s', skipping", fields[SavedAddressesModel::HeaderColumns::ADDRESS].toUtf8().constData());
continue;
}
const QString label = fields[SavedAddressesModel::HeaderColumns::LABEL];
const QString description = fields[SavedAddressesModel::HeaderColumns::DESCRIPTION];
const SavedAddressesModel::SavedAddress importedAddress = {address, label, description};
m_savedAddressesModel.addRow(importedAddress);
m_savedAddressesModel.loadSavedAddressFromFieldList(fields);
}
}
@@ -656,6 +592,17 @@ void CpuWidget::contextRemoveSearchResult()
delete rowToRemove;
}
void CpuWidget::contextCopySearchResultAddress()
{
if (!m_ui.listSearchResults->selectionModel()->hasSelection())
return;
const u32 selectedResultIndex = m_ui.listSearchResults->row(m_ui.listSearchResults->selectedItems().first());
const u32 rowAddress = m_ui.listSearchResults->item(selectedResultIndex)->data(Qt::UserRole).toUInt();
const QString addressString = FilledQStringFromValue(rowAddress, 16);
QApplication::clipboard()->setText(addressString);
}
void CpuWidget::updateFunctionList(bool whenEmpty)
{
if (!m_cpu.isAlive())
@@ -958,6 +905,10 @@ void CpuWidget::onListSearchResultsContextMenu(QPoint pos)
if (selModel->hasSelection())
{
QAction* copyAddressAction = new QAction(tr("Copy Address"), m_ui.listSearchResults);
connect(copyAddressAction, &QAction::triggered, this, &CpuWidget::contextCopySearchResultAddress);
contextMenu->addAction(copyAddressAction);
QAction* goToDisassemblyAction = new QAction(tr("Go to in Disassembly"), m_ui.listSearchResults);
connect(goToDisassemblyAction, &QAction::triggered, this, &CpuWidget::contextSearchResultGoToDisassembly);
contextMenu->addAction(goToDisassemblyAction);
@@ -1392,3 +1343,12 @@ void CpuWidget::loadSearchResults()
}
}
void CpuWidget::saveBreakpointsToDebuggerSettings()
{
DebuggerSettingsManager::saveGameSettings(&m_bpModel);
}
void CpuWidget::saveSavedAddressesToDebuggerSettings()
{
DebuggerSettingsManager::saveGameSettings(&m_savedAddressesModel);
}
+4
View File
@@ -116,8 +116,12 @@ public slots:
void loadSearchResults();
void contextSearchResultGoToDisassembly();
void contextRemoveSearchResult();
void contextCopySearchResultAddress();
void onListSearchResultsContextMenu(QPoint pos);
void saveBreakpointsToDebuggerSettings();
void saveSavedAddressesToDebuggerSettings();
private:
std::vector<QTableWidget*> m_registerTableViews;
std::vector<u32> m_searchResults;
@@ -0,0 +1,164 @@
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#include "DebuggerSettingsManager.h"
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonArray>
#include <QtCore/QFile>
#include "common/Console.h"
#include "fmt/core.h"
#include "VMManager.h"
#include "Models/BreakpointModel.h"
std::mutex DebuggerSettingsManager::writeLock;
const QString DebuggerSettingsManager::settingsFileVersion = "0.00";
QJsonObject DebuggerSettingsManager::loadGameSettingsJSON() {
std::string path = VMManager::GetDebuggerSettingsFilePathForCurrentGame();
QFile file(QString::fromStdString(path));
if (!file.open(QIODevice::ReadOnly))
{
Console.WriteLnFmt("Debugger Settings Manager: No Debugger Settings file found for game at: '{}'", path);
return QJsonObject();
}
QByteArray fileContent = file.readAll();
file.close();
const QJsonDocument jsonDoc(QJsonDocument::fromJson(fileContent));
if (jsonDoc.isNull() || !jsonDoc.isObject())
{
Console.WriteLnFmt("Debugger Settings Manager: Failed to load contents of settings file for file at: '{}'", path);
return QJsonObject();
}
return jsonDoc.object();
}
void DebuggerSettingsManager::writeJSONToPath(std::string path, QJsonDocument jsonDocument)
{
QFile file(QString::fromStdString(path));
if (!file.open(QIODevice::WriteOnly))
{
Console.WriteLnFmt("Debugger Settings Manager: Failed to write Debugger Settings file to path: '{}'", path);
return;
}
file.write(jsonDocument.toJson(QJsonDocument::Indented));
file.close();
}
void DebuggerSettingsManager::loadGameSettings(BreakpointModel* bpModel)
{
const std::string path = VMManager::GetDebuggerSettingsFilePathForCurrentGame();
if (path.empty())
return;
const QJsonValue breakpointsValue = loadGameSettingsJSON().value("Breakpoints");
const QString valueToLoad = breakpointsValue.toString();
if (breakpointsValue.isUndefined() || !breakpointsValue.isArray())
{
Console.WriteLnFmt("Debugger Settings Manager: Failed to read Breakpoints array from settings file: '{}'", path);
return;
}
const QJsonArray breakpointsArray = breakpointsValue.toArray();
for (u32 row = 0; row < breakpointsArray.size(); row++)
{
const QJsonValue rowValue = breakpointsArray.at(row);
if (rowValue.isUndefined() || !rowValue.isObject())
{
Console.WriteLn("Debugger Settings Manager: Failed to load invalid Breakpoint object.");
continue;
}
const QJsonObject rowObject = rowValue.toObject();
QStringList fields;
u32 col = 0;
for (auto iter = rowObject.begin(); iter != rowObject.end(); iter++, col++)
{
QString headerColKey = bpModel->headerData(col, Qt::Horizontal, Qt::UserRole).toString();
fields << rowObject.value(headerColKey).toString();
}
bpModel->loadBreakpointFromFieldList(fields);
}
}
void DebuggerSettingsManager::loadGameSettings(SavedAddressesModel* savedAddressesModel)
{
const std::string path = VMManager::GetDebuggerSettingsFilePathForCurrentGame();
if (path.empty())
return;
const QJsonValue savedAddressesValue = loadGameSettingsJSON().value("SavedAddresses");
QString valueToLoad = savedAddressesValue.toString();
if (savedAddressesValue.isUndefined() || !savedAddressesValue.isArray())
{
Console.WriteLnFmt("Debugger Settings Manager: Failed to read Saved Addresses array from settings file: '{}'", path);
return;
}
const QJsonArray breakpointsArray = savedAddressesValue.toArray();
for (u32 row = 0; row < breakpointsArray.size(); row++)
{
const QJsonValue rowValue = breakpointsArray.at(row);
if (rowValue.isUndefined() || !rowValue.isObject())
{
Console.WriteLn("Debugger Settings Manager: Failed to load invalid Breakpoint object.");
continue;
}
const QJsonObject rowObject = rowValue.toObject();
QStringList fields;
u32 col = 0;
for (auto iter = rowObject.begin(); iter != rowObject.end(); iter++, col++)
{
QString headerColKey = savedAddressesModel->headerData(col, Qt::Horizontal, Qt::UserRole).toString();
fields << rowObject.value(headerColKey).toString();
}
savedAddressesModel->loadSavedAddressFromFieldList(fields);
}
}
void DebuggerSettingsManager::saveGameSettings(BreakpointModel* bpModel)
{
saveGameSettings(bpModel, "Breakpoints", BreakpointModel::ExportRole);
}
void DebuggerSettingsManager::saveGameSettings(SavedAddressesModel* savedAddressesModel)
{
saveGameSettings(savedAddressesModel, "SavedAddresses", Qt::DisplayRole);
}
void DebuggerSettingsManager::saveGameSettings(QAbstractTableModel* abstractTableModel, QString settingsKey, u32 role)
{
const std::string path = VMManager::GetDebuggerSettingsFilePathForCurrentGame();
if (path.empty())
return;
const std::lock_guard<std::mutex> lock(writeLock);
QJsonObject loadedSettings = loadGameSettingsJSON();
QJsonArray rowsArray;
QStringList keys;
for (int col = 0; col < abstractTableModel->columnCount(); ++col)
{
keys << abstractTableModel->headerData(col, Qt::Horizontal, Qt::UserRole).toString();
}
for (int row = 0; row < abstractTableModel->rowCount(); row++)
{
QJsonObject rowObject;
for (int col = 0; col < abstractTableModel->columnCount(); col++)
{
const QModelIndex index = abstractTableModel->index(row, col);
const QString data = abstractTableModel->data(index, role).toString();
rowObject.insert(keys[col], QJsonValue::fromVariant(data));
}
rowsArray.append(rowObject);
}
loadedSettings.insert(settingsKey, rowsArray);
loadedSettings.insert("Version", settingsFileVersion);
QJsonDocument doc(loadedSettings);
writeJSONToPath(path, doc);
}
@@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#pragma once
#include <QtWidgets/QDialog>
#include <mutex>
#include "Models/BreakpointModel.h"
#include "Models/SavedAddressesModel.h"
class DebuggerSettingsManager final
{
public:
DebuggerSettingsManager(QWidget* parent = nullptr);
~DebuggerSettingsManager();
static void loadGameSettings(BreakpointModel* bpModel);
static void loadGameSettings(SavedAddressesModel* savedAddressesModel);
static void saveGameSettings(BreakpointModel* bpModel);
static void saveGameSettings(SavedAddressesModel* savedAddressesModel);
static void saveGameSettings(QAbstractTableModel* abstractTableModel, QString settingsKey, u32 role);
private:
static std::mutex writeLock;
static void writeJSONToPath(std::string path, QJsonDocument jsonDocument);
static QJsonObject loadGameSettingsJSON();
const static QString settingsFileVersion;
};
+3
View File
@@ -95,6 +95,9 @@
</property>
</action>
<action name="actionOnTop">
<property name="icon">
<iconset theme="pin-filled"/>
</property>
<property name="checkable">
<bool>true</bool>
</property>
@@ -6,6 +6,7 @@
#include "DebugTools/DebugInterface.h"
#include "DebugTools/Breakpoints.h"
#include "DebugTools/DisassemblyManager.h"
#include "common/Console.h"
#include "QtHost.h"
#include "QtUtils.h"
@@ -226,6 +227,28 @@ QVariant BreakpointModel::headerData(int section, Qt::Orientation orientation, i
return QVariant();
}
}
if (role == Qt::UserRole && orientation == Qt::Horizontal)
{
switch (section)
{
case BreakpointColumns::TYPE:
return "TYPE";
case BreakpointColumns::OFFSET:
return "OFFSET";
case BreakpointColumns::SIZE_LABEL:
return "SIZE / LABEL";
case BreakpointColumns::OPCODE:
return "INSTRUCTION";
case BreakpointColumns::CONDITION:
return "CONDITION";
case BreakpointColumns::HITS:
return "HITS";
case BreakpointColumns::ENABLED:
return "X";
default:
return QVariant();
}
}
return QVariant();
}
@@ -402,3 +425,106 @@ void BreakpointModel::refreshData()
endResetModel();
}
void BreakpointModel::loadBreakpointFromFieldList(QStringList fields)
{
bool ok;
if (fields.size() != BreakpointModel::BreakpointColumns::COLUMN_COUNT)
{
Console.WriteLn("Debugger Breakpoint Model: Invalid number of columns, skipping");
return;
}
const int type = fields[BreakpointModel::BreakpointColumns::TYPE].toUInt(&ok);
if (!ok)
{
Console.WriteLn("Debugger Breakpoint Model: Failed to parse type '%s', skipping", fields[BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
return;
}
// This is how we differentiate between breakpoints and memchecks
if (type == MEMCHECK_INVALID)
{
BreakPoint bp;
// Address
bp.addr = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16);
if (!ok)
{
Console.WriteLn("Debugger Breakpoint Model: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData());
return;
}
// Condition
if (!fields[BreakpointModel::BreakpointColumns::CONDITION].isEmpty())
{
PostfixExpression expr;
bp.hasCond = true;
bp.cond.debug = &m_cpu;
if (!m_cpu.initExpression(fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), expr))
{
Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond '%s', skipping", fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData());
return;
}
bp.cond.expression = expr;
strncpy(&bp.cond.expressionString[0], fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), sizeof(bp.cond.expressionString));
}
// Enabled
bp.enabled = fields[BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
if (!ok)
{
Console.WriteLn("Debugger Breakpoint Model: Failed to parse enable flag '%s', skipping", fields[BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData());
return;
}
insertBreakpointRows(0, 1, {bp});
}
else
{
MemCheck mc;
// Mode
if (type >= MEMCHECK_INVALID)
{
Console.WriteLn("Debugger Breakpoint Model: Failed to parse cond type '%s', skipping", fields[BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
return;
}
mc.cond = static_cast<MemCheckCondition>(type);
// Address
QString test = fields[BreakpointModel::BreakpointColumns::OFFSET];
mc.start = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16);
if (!ok)
{
Console.WriteLn("Debugger Breakpoint Model: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData());
return;
}
// Size
mc.end = fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUInt(&ok) + mc.start;
if (!ok)
{
Console.WriteLn("Debugger Breakpoint Model: Failed to parse length '%s', skipping", fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUtf8().constData());
return;
}
// Result
const int result = fields[BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
if (!ok)
{
Console.WriteLn("Debugger Breakpoint Model: Failed to parse result flag '%s', skipping", fields[BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData());
return;
}
mc.result = static_cast<MemCheckResult>(result);
insertBreakpointRows(0, 1, {mc});
}
}
void BreakpointModel::clear()
{
beginResetModel();
m_breakpoints.clear();
endResetModel();
}
@@ -55,10 +55,12 @@ public:
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
bool removeRows(int row, int count, const QModelIndex& index = QModelIndex()) override;
bool insertBreakpointRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index = QModelIndex());
void loadBreakpointFromFieldList(QStringList breakpointFields);
BreakpointMemcheck at(int row) const { return m_breakpoints.at(row); };
void refreshData();
void clear();
private:
DebugInterface& m_cpu;
@@ -4,6 +4,8 @@
#include "PrecompiledHeader.h"
#include "SavedAddressesModel.h"
#include "common/Console.h"
SavedAddressesModel::SavedAddressesModel(DebugInterface& cpu, QObject* parent)
: QAbstractTableModel(parent)
, m_cpu(cpu)
@@ -96,20 +98,38 @@ bool SavedAddressesModel::setData(const QModelIndex& index, const QVariant& valu
QVariant SavedAddressesModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if ((role != Qt::DisplayRole && role != Qt::EditRole) || orientation != Qt::Horizontal)
if (orientation != Qt::Horizontal)
return QVariant();
switch (section)
if (role == Qt::DisplayRole)
{
case SavedAddressesModel::ADDRESS:
return tr("MEMORY ADDRESS");
case SavedAddressesModel::LABEL:
return tr("LABEL");
case SavedAddressesModel::DESCRIPTION:
return tr("DESCRIPTION");
default:
return QVariant();
switch (section)
{
case SavedAddressesModel::ADDRESS:
return tr("MEMORY ADDRESS");
case SavedAddressesModel::LABEL:
return tr("LABEL");
case SavedAddressesModel::DESCRIPTION:
return tr("DESCRIPTION");
default:
return QVariant();
}
}
if (role == Qt::UserRole)
{
switch (section)
{
case SavedAddressesModel::ADDRESS:
return "MEMORY ADDRESS";
case SavedAddressesModel::LABEL:
return "LABEL";
case SavedAddressesModel::DESCRIPTION:
return "DESCRIPTION";
default:
return QVariant();
}
}
return QVariant();
}
Qt::ItemFlags SavedAddressesModel::flags(const QModelIndex& index) const
@@ -150,3 +170,32 @@ int SavedAddressesModel::columnCount(const QModelIndex&) const
{
return HeaderColumns::COLUMN_COUNT;
}
void SavedAddressesModel::loadSavedAddressFromFieldList(QStringList fields)
{
if (fields.size() != SavedAddressesModel::HeaderColumns::COLUMN_COUNT)
{
Console.WriteLn("Debugger Saved Addresses Model: Invalid number of columns, skipping");
return;
}
bool ok;
const u32 address = fields[SavedAddressesModel::HeaderColumns::ADDRESS].toUInt(&ok, 16);
if (!ok)
{
Console.WriteLn("Debugger Saved Addresses Model: Failed to parse address '%s', skipping", fields[SavedAddressesModel::HeaderColumns::ADDRESS].toUtf8().constData());
return;
}
const QString label = fields[SavedAddressesModel::HeaderColumns::LABEL];
const QString description = fields[SavedAddressesModel::HeaderColumns::DESCRIPTION];
const SavedAddressesModel::SavedAddress importedAddress = {address, label, description};
addRow(importedAddress);
}
void SavedAddressesModel::clear()
{
beginResetModel();
m_savedAddresses.clear();
endResetModel();
}
@@ -20,7 +20,7 @@ public:
QString description;
};
enum HeaderColumns : int
enum HeaderColumns: int
{
ADDRESS = 0,
LABEL,
@@ -45,6 +45,8 @@ public:
void addRow(SavedAddress addresstoSave);
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
void loadSavedAddressFromFieldList(QStringList fields);
void clear();
private:
DebugInterface& m_cpu;
+4 -2
View File
@@ -6,6 +6,7 @@
#include "QtHost.h"
#include "QtUtils.h"
#include "pcsx2/ImGui/FullscreenUI.h"
#include "pcsx2/ImGui/ImGuiManager.h"
#include "common/Assertions.h"
@@ -323,8 +324,9 @@ bool DisplayWidget::event(QEvent* event)
// don't toggle fullscreen when we're bound.. that wouldn't end well.
if (event->type() == QEvent::MouseButtonDblClick &&
static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton &&
QtHost::IsVMValid() && !QtHost::IsVMPaused() &&
!InputManager::HasAnyBindingsForKey(InputManager::MakePointerButtonKey(0, 0)) &&
QtHost::IsVMValid() && !FullscreenUI::HasActiveWindow() &&
((!QtHost::IsVMPaused() && !InputManager::HasAnyBindingsForKey(InputManager::MakePointerButtonKey(0, 0))) ||
(QtHost::IsVMPaused() && !ImGuiManager::WantsMouseInput())) &&
Host::GetBoolSettingValue("UI", "DoubleClickTogglesFullscreen", true))
{
g_emu_thread->toggleFullscreen();
+43 -21
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#include "AboutDialog.h"
@@ -16,6 +16,7 @@
#include "Settings/ControllerSettingsWindow.h"
#include "Settings/GameListSettingsWidget.h"
#include "Settings/InterfaceSettingsWidget.h"
#include "Settings/MemoryCardCreateDialog.h"
#include "Tools/InputRecording/InputRecordingViewer.h"
#include "Tools/InputRecording/NewInputRecordingDlg.h"
#include "svnrev.h"
@@ -178,11 +179,8 @@ QWidget* MainWindow::getContentParent()
void MainWindow::setupAdditionalUi()
{
const bool show_advanced_settings = QtHost::ShouldShowAdvancedSettings();
makeIconsMasks(menuBar());
m_ui.menuDebug->menuAction()->setVisible(show_advanced_settings);
updateAdvancedSettingsVisibility();
const bool toolbar_visible = Host::GetBaseBoolSettingValue("UI", "ShowToolbar", false);
m_ui.actionViewToolbar->setChecked(toolbar_visible);
@@ -367,14 +365,18 @@ void MainWindow::connectSignals()
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionViewStatusBarVerbose, "UI", "VerboseStatusBar", false);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableSystemConsole, "Logging", "EnableSystemConsole", false);
#ifdef _WIN32
// Debug console only exists on Windows.
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableDebugConsole, "Logging", "EnableDebugConsole", false);
#else
m_ui.menuTools->removeAction(m_ui.actionEnableDebugConsole);
m_ui.actionEnableDebugConsole->deleteLater();
m_ui.actionEnableDebugConsole = nullptr;
#endif
if (Log::IsDebugOutputAvailable())
{
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableDebugConsole, "Logging", "EnableDebugConsole", false);
}
else
{
m_ui.menuTools->removeAction(m_ui.actionEnableDebugConsole);
m_ui.actionEnableDebugConsole->deleteLater();
m_ui.actionEnableDebugConsole = nullptr;
}
#ifndef PCSX2_DEVBUILD
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableVerboseLogging, "Logging", "EnableVerbose", false);
#else
@@ -438,6 +440,7 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
connect(thread, &EmuThread::onAchievementsLoginSucceeded, this, &MainWindow::onAchievementsLoginSucceeded);
connect(thread, &EmuThread::onAchievementsHardcoreModeChanged, this, &MainWindow::onAchievementsHardcoreModeChanged);
connect(thread, &EmuThread::onCoverDownloaderOpenRequested, this, &MainWindow::onToolsCoverDownloaderTriggered);
connect(thread, &EmuThread::onCreateMemoryCardOpenRequested, this, &MainWindow::onCreateMemoryCardOpenRequested);
connect(m_ui.actionReset, &QAction::triggered, this, &MainWindow::requestReset);
connect(m_ui.actionPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
@@ -613,13 +616,13 @@ void MainWindow::onBlockDumpActionToggled(bool checked)
if (!checked)
return;
std::string old_directory(Host::GetBaseStringSettingValue("EmuCore", "BlockDumpSaveDirectory", ""));
std::string old_directory = Host::GetBaseStringSettingValue("EmuCore", "BlockDumpSaveDirectory", "");
if (old_directory.empty())
old_directory = FileSystem::GetWorkingDirectory();
// prompt for a location to save
const QString new_dir(
QFileDialog::getExistingDirectory(this, tr("Select location to save block dump:"), QString::fromStdString(old_directory)));
const QString new_dir(QDir::toNativeSeparators(
QFileDialog::getExistingDirectory(this, tr("Select location to save block dump:"), QString::fromStdString(old_directory))));
if (new_dir.isEmpty())
{
// disable it again
@@ -669,13 +672,25 @@ void MainWindow::onShowAdvancedSettingsToggled(bool checked)
Host::SetBaseBoolSettingValue("UI", "ShowAdvancedSettings", checked);
Host::CommitBaseSettingChanges();
m_ui.menuDebug->menuAction()->setVisible(checked);
updateAdvancedSettingsVisibility();
// just recreate the entire settings window, it's easier.
if (m_settings_window)
recreateSettings();
}
void MainWindow::updateAdvancedSettingsVisibility()
{
const bool enabled = QtHost::ShouldShowAdvancedSettings();
m_ui.menuDebug->menuAction()->setVisible(enabled);
m_ui.actionEnableSystemConsole->setVisible(enabled);
if (m_ui.actionEnableDebugConsole)
m_ui.actionEnableDebugConsole->setVisible(enabled);
m_ui.actionEnableVerboseLogging->setVisible(enabled);
}
void MainWindow::onToolsVideoCaptureToggled(bool checked)
{
if (!s_vm_valid)
@@ -1303,11 +1318,10 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
});
}
//: Refers to the directory where a game is contained.
action = menu.addAction(tr("Open Containing Directory..."));
action = menu.addAction(QtUtils::GetShowInFileExplorerMessage());
connect(action, &QAction::triggered, [this, entry]() {
const QFileInfo fi(QString::fromStdString(entry->path));
QtUtils::OpenURL(this, QUrl::fromLocalFile(fi.absolutePath()));
QtUtils::ShowInFileExplorer(this, fi);
});
action = menu.addAction(tr("Set Cover Image..."));
@@ -1627,7 +1641,7 @@ void MainWindow::onToolsCoverDownloaderTriggered()
{
// This can be invoked via big picture, so exit fullscreen.
VMLock lock(pauseAndLockVM());
CoverDownloadDialog dlg(this);
CoverDownloadDialog dlg(lock.getDialogParent());
connect(&dlg, &CoverDownloadDialog::coverRefreshRequested, m_game_list_widget, &GameListWidget::refreshGridCovers);
dlg.exec();
}
@@ -1658,6 +1672,14 @@ void MainWindow::onToolsEditCheatsPatchesTriggered(bool cheats)
QtUtils::OpenURL(this, QUrl::fromLocalFile(QString::fromStdString(path)));
}
void MainWindow::onCreateMemoryCardOpenRequested()
{
// This can be invoked via big picture, so exit fullscreen.
VMLock lock(pauseAndLockVM());
MemoryCardCreateDialog dlg(lock.getDialogParent());
dlg.exec();
}
void MainWindow::updateTheme()
{
QtHost::UpdateApplicationTheme();
+2
View File
@@ -158,6 +158,7 @@ private Q_SLOTS:
void onToolsOpenDataDirectoryTriggered();
void onToolsCoverDownloaderTriggered();
void onToolsEditCheatsPatchesTriggered(bool cheats);
void onCreateMemoryCardOpenRequested();
void updateTheme();
void reloadThemeSpecificImages();
void updateLanguage();
@@ -222,6 +223,7 @@ private:
void updateDisplayRelatedActions(bool has_surface, bool render_to_main, bool fullscreen);
void updateGameDependentActions();
void updateStatusBarWidgetVisibility();
void updateAdvancedSettingsVisibility();
void updateWindowTitle();
void updateWindowState(bool force_visible = false);
void setProgressBar(int current, int total);
+8
View File
@@ -1089,11 +1089,19 @@
<property name="text">
<string>Edit Cheats...</string>
</property>
<property name="icon">
<iconset theme="pencil-line">
<normaloff>.</normaloff>.</iconset>
</property>
</action>
<action name="actionEditPatches">
<property name="text">
<string>Edit Patches...</string>
</property>
<property name="icon">
<iconset theme="pencil-line">
<normaloff>.</normaloff>.</iconset>
</property>
</action>
</widget>
<resources>
+15 -25
View File
@@ -29,7 +29,6 @@
#include "pcsx2/Input/InputManager.h"
#include "pcsx2/MTGS.h"
#include "pcsx2/PerformanceMetrics.h"
#include "pcsx2/SysForwardDefs.h"
#include "pcsx2/VMManager.h"
#include "common/Assertions.h"
@@ -88,6 +87,7 @@ static bool s_start_fullscreen_ui = false;
static bool s_start_fullscreen_ui_fullscreen = false;
static bool s_test_config_and_exit = false;
static bool s_run_setup_wizard = false;
static bool s_cleanup_after_update = false;
static bool s_boot_and_debug = false;
//////////////////////////////////////////////////////////////////////////
@@ -497,7 +497,7 @@ void EmuThread::setFullscreen(bool fullscreen, bool allow_render_to_main)
MTGS::WaitGS();
// If we're using exclusive fullscreen, the refresh rate may have changed.
UpdateVSyncRate(true);
VMManager::UpdateTargetSpeed();
}
void EmuThread::setSurfaceless(bool surfaceless)
@@ -1117,7 +1117,12 @@ void Host::OnCoverDownloaderOpenRequested()
emit g_emu_thread->onCoverDownloaderOpenRequested();
}
void Host::VSyncOnCPUThread()
void Host::OnCreateMemoryCardOpenRequested()
{
emit g_emu_thread->onCreateMemoryCardOpenRequested();
}
void Host::PumpMessagesOnCPUThread()
{
g_emu_thread->getEventLoop()->processEvents(QEventLoop::AllEvents);
}
@@ -1336,24 +1341,7 @@ bool Host::RequestResetSettings(bool folders, bool core, bool controllers, bool
QString QtHost::GetAppNameAndVersion()
{
QString ret;
if constexpr (!PCSX2_isReleaseVersion && GIT_TAGGED_COMMIT)
{
ret = QStringLiteral("PCSX2 Nightly - " GIT_TAG);
}
else if constexpr (PCSX2_isReleaseVersion)
{
#define APPNAME_STRINGIZE(x) #x
ret = QStringLiteral(
"PCSX2 " APPNAME_STRINGIZE(PCSX2_VersionHi) "." APPNAME_STRINGIZE(PCSX2_VersionMid) "." APPNAME_STRINGIZE(PCSX2_VersionLo));
#undef APPNAME_STRINGIZE
}
else
{
return QStringLiteral("PCSX2 " GIT_REV);
}
return ret;
return QStringLiteral("PCSX2 " GIT_REV);
}
QString QtHost::GetAppConfigSuffix()
@@ -1398,7 +1386,7 @@ std::optional<bool> QtHost::DownloadFile(QWidget* parent, const QString& title,
QtModalProgressCallback progress(parent);
progress.GetDialog().setLabelText(
qApp->translate("EmuThread", "Downloading %1...").arg(QtUtils::StringViewToQString(
std::string_view(url).substr((url_file_part_pos >= 0) ? (url_file_part_pos + 1) : 0))));
std::string_view(url).substr((url_file_part_pos != std::string::npos) ? (url_file_part_pos + 1) : 0))));
progress.GetDialog().setWindowTitle(title);
progress.GetDialog().setWindowIcon(GetAppIcon());
progress.SetCancellable(true);
@@ -1778,9 +1766,7 @@ bool QtHost::ParseCommandLineOptions(const QStringList& args, std::shared_ptr<VM
}
else if (CHECK_ARG(QStringLiteral("-updatecleanup")))
{
if (AutoUpdaterDialog::isSupported())
AutoUpdaterDialog::cleanupAfterUpdate();
s_cleanup_after_update = AutoUpdaterDialog::isSupported();
continue;
}
#ifdef ENABLE_RAINTEGRATION
@@ -1911,6 +1897,10 @@ int main(int argc, char* argv[])
if (s_test_config_and_exit)
return EXIT_SUCCESS;
// Remove any previous-version remanants.
if (s_cleanup_after_update)
AutoUpdaterDialog::cleanupAfterUpdate();
// Set theme before creating any windows.
QtHost::UpdateApplicationTheme();
+2 -1
View File
@@ -168,8 +168,9 @@ Q_SIGNALS:
/// Called when hardcore mode is enabled or disabled.
void onAchievementsHardcoreModeChanged(bool enabled);
/// Called when cover download is requested.
/// Big Picture UI requests.
void onCoverDownloaderOpenRequested();
void onCreateMemoryCardOpenRequested();
/// Called when video capture starts/stops.
void onCaptureStarted(const QString& filename);
+41 -2
View File
@@ -4,6 +4,7 @@
#include "QtUtils.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QFileInfo>
#include <QtCore/QMetaObject>
#include <QtGui/QAction>
#include <QtGui/QGuiApplication>
@@ -26,10 +27,12 @@
#include <array>
#include <map>
#include "common/CocoaTools.h"
#include "common/Console.h"
#if defined(_WIN32)
#include "common/RedtapeWindows.h"
#include <Shlobj.h>
#elif !defined(APPLE)
#include <qpa/qplatformnativeinterface.h>
#endif
@@ -129,12 +132,48 @@ namespace QtUtils
ResizeColumnsForView(view, widths);
}
void ShowInFileExplorer(QWidget* parent, const QFileInfo& file)
{
#if defined(_WIN32)
std::wstring wstr = QDir::toNativeSeparators(file.absoluteFilePath()).toStdWString();
bool ok = false;
if (PIDLIST_ABSOLUTE pidl = ILCreateFromPath(wstr.c_str()))
{
ok = SUCCEEDED(SHOpenFolderAndSelectItems(pidl, 0, nullptr, 0));
ILFree(pidl);
}
#elif defined(__APPLE__)
bool ok = CocoaTools::ShowInFinder(file.absoluteFilePath().toStdString());
#else
bool ok = QDesktopServices::openUrl(QUrl::fromLocalFile(file.absolutePath()));
#endif
if (!ok)
{
QMessageBox::critical(parent, QCoreApplication::translate("FileOperations", "Failed to show file"),
QCoreApplication::translate("FileOperations", "Failed to show file in file explorer.\n\nThe file was: %1").arg(file.absoluteFilePath()));
}
}
QString GetShowInFileExplorerMessage()
{
#if defined(_WIN32)
//: Windows action to show a file in Windows Explorer
return QCoreApplication::translate("FileOperations", "Show in Folder");
#elif defined(__APPLE__)
//: macOS action to show a file in Finder
return QCoreApplication::translate("FileOperations", "Show in Finder");
#else
//: Opens the system file manager to the directory containing a selected file
return QCoreApplication::translate("FileOperations", "Open Containing Directory");
#endif
}
void OpenURL(QWidget* parent, const QUrl& qurl)
{
if (!QDesktopServices::openUrl(qurl))
{
QMessageBox::critical(parent, QObject::tr("Failed to open URL"),
QObject::tr("Failed to open URL.\n\nThe URL was: %1").arg(qurl.toString()));
QMessageBox::critical(parent, QCoreApplication::translate("FileOperations", "Failed to open URL"),
QCoreApplication::translate("FileOperations", "Failed to open URL.\n\nThe URL was: %1").arg(qurl.toString()));
}
}
+7
View File
@@ -18,6 +18,7 @@ class ByteStream;
class QAction;
class QComboBox;
class QFileInfo;
class QFrame;
class QKeyEvent;
class QTableView;
@@ -49,6 +50,12 @@ namespace QtUtils
/// NOTE: Defined in QtKeyCodes.cpp, not QtUtils.cpp.
u32 KeyEventToCode(const QKeyEvent* ev);
/// Shows a file, or the containing folder if unsupported, with the system file explorer
void ShowInFileExplorer(QWidget* parent, const QFileInfo& file);
/// Get the context menu name for the action performed by ShowInFileExplorer
QString GetShowInFileExplorerMessage();
/// Opens a URL with the default handler.
void OpenURL(QWidget* parent, const QUrl& qurl);
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#include "Settings/ControllerGlobalSettingsWidget.h"
@@ -40,7 +40,6 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
#ifdef _WIN32
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableXInputSource, "InputSources", "XInput", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableDInputSource, "InputSources", "DInput", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.ignoreDInputInversion, "InputSources", "IgnoreDInputInversion", false);
#else
m_ui.mainLayout->removeWidget(m_ui.xinputGroup);
m_ui.xinputGroup->deleteLater();
@@ -176,3 +175,19 @@ ControllerMouseSettingsDialog::ControllerMouseSettingsDialog(QWidget* parent, Co
}
ControllerMouseSettingsDialog::~ControllerMouseSettingsDialog() = default;
ControllerMappingSettingsDialog::ControllerMappingSettingsDialog(ControllerSettingsWindow* parent)
: QDialog(parent)
{
m_ui.setupUi(this);
SettingsInterface* sif = parent->getProfileSettingsInterface();
m_ui.icon->setPixmap(QIcon::fromTheme(QStringLiteral("settings-3-line")).pixmap(32, 32));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.ignoreInversion, "InputSources", "IgnoreInversion", false);
connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept);
}
ControllerMappingSettingsDialog::~ControllerMappingSettingsDialog() = default;
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#pragma once
@@ -12,6 +12,7 @@
#include "ui_ControllerGlobalSettingsWidget.h"
#include "ui_ControllerLEDSettingsDialog.h"
#include "ui_ControllerMappingSettingsDialog.h"
#include "ui_ControllerMouseSettingsDialog.h"
class ControllerSettingsWindow;
@@ -66,3 +67,15 @@ public:
private:
Ui::ControllerMouseSettingsDialog m_ui;
};
class ControllerMappingSettingsDialog : public QDialog
{
Q_OBJECT
public:
ControllerMappingSettingsDialog(ControllerSettingsWindow* parent);
~ControllerMappingSettingsDialog();
private:
Ui::ControllerMappingSettingsDialog m_ui;
};
@@ -82,16 +82,6 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="ignoreDInputInversion">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Some third party controllers incorrectly flag their analog sticks as inverted on the positive component, but not negative.&lt;/p&gt;&lt;p&gt;As a result, the analog stick will be &amp;quot;stuck on&amp;quot; even while resting at neutral position. &lt;/p&gt;&lt;p&gt;Enabling this setting will tell PCSX2 to ignore inversion flags when creating mappings, allowing such controllers to function normally.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Ignore Inversion</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_9">
<property name="text">
@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ControllerMappingSettingsDialog</class>
<widget class="QDialog" name="ControllerMappingSettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>654</width>
<height>275</height>
</rect>
</property>
<property name="windowTitle">
<string>Controller Mapping Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="icon">
<property name="minimumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:700;&quot;&gt;Controller Mapping Settings&lt;/span&gt;&lt;br/&gt;These settings fine-tune the behavior when mapping physical controllers to the emulated controllers.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="ignoreInversion">
<property name="text">
<string>Ignore Inversion</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Some third party controllers incorrectly flag their analog sticks as inverted on the positive component, but not negative.&lt;/p&gt;&lt;p&gt;As a result, the analog stick will be &amp;quot;stuck on&amp;quot; even while resting at neutral position. &lt;/p&gt;&lt;p&gt;Enabling this setting will tell PCSX2 to ignore inversion flags when creating mappings, allowing such controllers to function normally.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>28</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>
@@ -39,6 +39,7 @@ ControllerSettingsWindow::ControllerSettingsWindow()
connect(m_ui.newProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onNewProfileClicked);
connect(m_ui.loadProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onLoadProfileClicked);
connect(m_ui.deleteProfile, &QPushButton::clicked, this, &ControllerSettingsWindow::onDeleteProfileClicked);
connect(m_ui.mappingSettings, &QPushButton::clicked, this, &ControllerSettingsWindow::onMappingSettingsClicked);
connect(m_ui.restoreDefaults, &QPushButton::clicked, this, &ControllerSettingsWindow::onRestoreDefaultsClicked);
connect(g_emu_thread, &EmuThread::onInputDevicesEnumerated, this, &ControllerSettingsWindow::onInputDevicesEnumerated);
@@ -186,6 +187,12 @@ void ControllerSettingsWindow::onDeleteProfileClicked()
switchProfile({});
}
void ControllerSettingsWindow::onMappingSettingsClicked()
{
ControllerMappingSettingsDialog dialog(this);
dialog.exec();
}
void ControllerSettingsWindow::onRestoreDefaultsClicked()
{
if (QMessageBox::question(this, tr("Restore Defaults"),
@@ -76,6 +76,7 @@ private Q_SLOTS:
void onNewProfileClicked();
void onLoadProfileClicked();
void onDeleteProfileClicked();
void onMappingSettingsClicked();
void onRestoreDefaultsClicked();
void onInputDevicesEnumerated(const QList<QPair<QString, QString>>& devices);
@@ -123,6 +123,16 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="mappingSettings">
<property name="text">
<string>Mapping Settings</string>
</property>
<property name="icon">
<iconset theme="settings-3-line"/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="restoreDefaults">
<property name="text">
+20
View File
@@ -253,6 +253,8 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsWindow* dialog, QWidget* parent)
else
m_ui.hddFile->setText(QString::fromUtf8(m_dialog->getStringValue("DEV9/Hdd", "HddFile", "DEV9hdd.raw").value().c_str()));
connect(m_ui.hddLBA48, QOverload<int>::of(&QCheckBox::stateChanged), this, &DEV9SettingsWidget::onHddLBA48Changed);
UpdateHddSizeUIValues();
connect(m_ui.hddFile, &QLineEdit::textChanged, this, &DEV9SettingsWidget::onHddFileTextChange);
@@ -720,6 +722,19 @@ void DEV9SettingsWidget::onHddSizeAccessorSpin()
m_ui.hddSizeSlider->setValue(m_ui.hddSizeSpinBox->value());
}
void DEV9SettingsWidget::onHddLBA48Changed(int state)
{
m_ui.hddSizeSlider->setMaximum(state ? 2000 : 120);
m_ui.hddSizeSpinBox->setMaximum(state ? 2000 : 120);
m_ui.hddSizeMaxLabel->setText(state ? tr("2000") : tr("120"));
// Bump up min size to have ticks align with 100GiB sizes
m_ui.hddSizeSlider->setMinimum(state ? 100 : 40);
m_ui.hddSizeSpinBox->setMinimum(state ? 100 : 40);
m_ui.hddSizeMinLabel->setText(state ? tr("100") : tr("40"));
m_ui.hddSizeSlider->setTickInterval(state ? 100 : 5);
}
void DEV9SettingsWidget::onHddCreateClicked()
{
//Do the thing
@@ -800,6 +815,11 @@ void DEV9SettingsWidget::UpdateHddSizeUIValues()
if (size < 0)
return;
if (size > static_cast<s64>(120) * 1024 * 1024 * 1024)
m_ui.hddLBA48->setChecked(true);
else
m_ui.hddLBA48->setChecked(false);
const int sizeGB = size / 1024 / 1024 / 1024;
QSignalBlocker sb1(m_ui.hddSizeSpinBox);
QSignalBlocker sb2(m_ui.hddSizeSlider);
+1
View File
@@ -39,6 +39,7 @@ private Q_SLOTS:
void onHddFileEdit();
void onHddSizeSlide(int i);
void onHddSizeAccessorSpin();
void onHddLBA48Changed(int state);
void onHddCreateClicked();
public:
+14
View File
@@ -365,6 +365,20 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="hddLBA48Label">
<property name="text">
<string>48-bit LBA:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="hddLBA48">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -32,6 +32,9 @@ GameCheatSettingsWidget::GameCheatSettingsWidget(SettingsWindow* dialog, QWidget
connect(m_ui.enableAll, &QPushButton::clicked, this, [this]() { setStateForAll(true); });
connect(m_ui.disableAll, &QPushButton::clicked, this, [this]() { setStateForAll(false); });
connect(m_ui.allCRCsCheckbox, &QCheckBox::stateChanged, this, &GameCheatSettingsWidget::onReloadClicked);
dialog->registerWidgetHelp(m_ui.allCRCsCheckbox, tr("Show Cheats For All CRCs"), tr("Checked"),
tr("Toggles scanning patch files for all CRCs of the game. With this enabled available patches for the game serial with different CRCs will also be loaded."));
}
GameCheatSettingsWidget::~GameCheatSettingsWidget() = default;
@@ -63,6 +63,9 @@ GamePatchSettingsWidget::GamePatchSettingsWidget(SettingsWindow* dialog, QWidget
connect(m_ui.reload, &QPushButton::clicked, this, &GamePatchSettingsWidget::onReloadClicked);
connect(m_ui.allCRCsCheckbox, &QCheckBox::stateChanged, this, &GamePatchSettingsWidget::reloadList);
dialog->registerWidgetHelp(m_ui.allCRCsCheckbox, tr("Show Patches For All CRCs"), tr("Checked"),
tr("Toggles scanning patch files for all CRCs of the game. With this enabled available patches for the game serial with different CRCs will also be loaded."));
reloadList();
}
+21 -1
View File
@@ -300,6 +300,26 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
}
#endif
// Get rid of widescreen/no-interlace checkboxes from per-game settings, unless the user previously had them set.
if (m_dialog->isPerGameSettings())
{
if ((m_dialog->containsSettingValue("EmuCore", "EnableWideScreenPatches") || m_dialog->containsSettingValue("EmuCore", "EnableNoInterlacingPatches")) &&
QMessageBox::question(QtUtils::GetRootWidget(this), tr("Remove Unsupported Settings"),
tr("You currently have the <strong>Enable Widescreen Patches</strong> or <strong>Enable No-Interlacing Patches</strong> options enabled for this game.<br><br>"
"We no longer support these options, instead <strong>you should select the \"Patches\" section, and explicitly enable the patches you want.</strong><br><br>"
"Do you want to remove these options from your game configuration now?"),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
{
m_dialog->removeSettingValue("EmuCore", "EnableWideScreenPatches");
m_dialog->removeSettingValue("EmuCore", "EnableNoInterlacingPatches");
}
m_ui.gridLayout->removeWidget(m_ui.widescreenPatches);
m_ui.gridLayout->removeWidget(m_ui.noInterlacingPatches);
safe_delete(m_ui.widescreenPatches);
safe_delete(m_ui.noInterlacingPatches);
}
// Hide advanced options by default.
if (!QtHost::ShouldShowAdvancedSettings())
{
@@ -714,7 +734,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
"<b>If unsure, leave it on default.<b>"));
dialog->registerWidgetHelp(m_ui.audioCaptureBitrate, tr("Audio Bitrate"), tr("160 Kbps"), tr("Sets the audio bitrate to be used."));
dialog->registerWidgetHelp(m_ui.audioCaptureBitrate, tr("Audio Bitrate"), tr("160 kbps"), tr("Sets the audio bitrate to be used."));
dialog->registerWidgetHelp(m_ui.enableAudioCaptureArguments, tr("Enable Extra Audio Arguments"), tr("Unchecked"), tr("Allows you to pass arguments to the selected audio codec."));
+1 -1
View File
@@ -324,7 +324,7 @@
</layout>
</item>
<item row="8" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_5">
<layout class="QGridLayout" name="displayGridLayout">
<item row="3" column="0">
<widget class="QCheckBox" name="PCRTCOffsets">
<property name="text">
+11 -5
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#include "common/FileSystem.h"
@@ -36,7 +36,13 @@ MemoryCardCreateDialog::MemoryCardCreateDialog(QWidget* parent /* = nullptr */)
connect(m_ui.buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &MemoryCardCreateDialog::restoreDefaults);
#ifndef _WIN32
m_ui.ntfsCompression->setEnabled(false);
m_ui.ntfsCompressionLayout->removeWidget(m_ui.ntfsCompression);
safe_delete(m_ui.ntfsCompression);
m_ui.ntfsCompressionLayout->removeWidget(m_ui.ntfsCompressionLabel);
safe_delete(m_ui.ntfsCompressionLabel);
m_ui.mainLayout->removeItem(m_ui.ntfsCompressionLayout);
safe_delete(m_ui.ntfsCompressionLayout);
resize(600, 480);
#endif
updateState();
@@ -117,10 +123,10 @@ void MemoryCardCreateDialog::createCard()
}
#ifdef _WIN32
if (m_ui.ntfsCompression->isChecked() && m_type == MemoryCardType::File)
if (m_type == MemoryCardType::File)
{
const std::string fullPath(Path::Combine(EmuFolders::MemoryCards, name_str));
FileSystem::SetPathCompression(fullPath.c_str(), true);
const std::string fullPath = Path::Combine(EmuFolders::MemoryCards, name_str);
FileSystem::SetPathCompression(fullPath.c_str(), m_ui.ntfsCompression->isChecked());
}
#endif
+9 -9
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>593</width>
<height>545</height>
<width>600</width>
<height>535</height>
</rect>
</property>
<property name="windowTitle">
@@ -16,13 +16,13 @@
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<layout class="QVBoxLayout" name="mainLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
<property name="bottomMargin">
<property name="spacing">
<number>10</number>
</property>
<property name="spacing">
<property name="bottomMargin">
<number>10</number>
</property>
<item>
@@ -39,8 +39,8 @@
<height>48</height>
</size>
</property>
<property name="pixmap">
<pixmap resource="resources/resources.qrc">:/icons/black/svg/memcard-line.svg</pixmap>
<property name="pixmap">
<pixmap resource="../resources/resources.qrc">:/icons/black/svg/memcard-line.svg</pixmap>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
@@ -227,7 +227,7 @@
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_8">
<layout class="QVBoxLayout" name="ntfsCompressionLayout">
<item>
<widget class="QCheckBox" name="ntfsCompression">
<property name="text">
@@ -239,7 +239,7 @@
</widget>
</item>
<item>
<widget class="QLabel" name="label_10">
<widget class="QLabel" name="ntfsCompressionLabel">
<property name="text">
<string>NTFS compression is built-in, fast, and completely reliable. Typically compresses Memory Cards (highly recommended).</string>
</property>
+7 -19
View File
@@ -54,7 +54,6 @@ MemoryCardSettingsWidget::MemoryCardSettingsWidget(SettingsWindow* dialog, QWidg
connect(m_ui.refreshCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::refresh);
connect(m_ui.createCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::createCard);
connect(m_ui.duplicateCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::duplicateCard);
connect(m_ui.renameCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::renameCard);
connect(m_ui.convertCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::convertCard);
connect(m_ui.deleteCard, &QPushButton::clicked, this, &MemoryCardSettingsWidget::deleteCard);
@@ -89,22 +88,22 @@ void MemoryCardSettingsWidget::setupAdditionalUi()
createSlotWidgets(&m_slots[i], i);
// button to swap Memory Cards
QToolButton* swap_button = new QToolButton(m_ui.portGroupBox);
QToolButton* swap_button = new QToolButton(m_ui.slotGroupBox);
swap_button->setIcon(QIcon::fromTheme("arrow-left-right-line"));
swap_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
swap_button->setToolTip(tr("Swap Memory Cards"));
connect(swap_button, &QToolButton::clicked, this, &MemoryCardSettingsWidget::swapCards);
static_cast<QGridLayout*>(m_ui.portGroupBox->layout())->addWidget(swap_button, 0, 1);
static_cast<QGridLayout*>(m_ui.slotGroupBox->layout())->addWidget(swap_button, 0, 1);
}
void MemoryCardSettingsWidget::createSlotWidgets(SlotGroup* port, u32 slot)
{
const bool perGame = m_dialog->isPerGameSettings();
port->root = new QWidget(m_ui.portGroupBox);
port->root = new QWidget(m_ui.slotGroupBox);
SettingsInterface* sif = m_dialog->getSettingsInterface();
port->enable = new QCheckBox(tr("Port %1").arg(slot + 1), port->root);
port->enable = new QCheckBox(tr("Slot %1").arg(slot + 1), port->root);
SettingWidgetBinder::BindWidgetToBoolSetting(
sif, port->enable, CONFIG_SECTION, StringUtil::StdStringFromFormat("Slot%u_Enable", slot + 1), true);
connect(port->enable, &QCheckBox::stateChanged, this, &MemoryCardSettingsWidget::refresh);
@@ -129,7 +128,7 @@ void MemoryCardSettingsWidget::createSlotWidgets(SlotGroup* port, u32 slot)
vert_layout->addWidget(port->enable, 0);
vert_layout->addLayout(bottom_layout, 1);
static_cast<QGridLayout*>(m_ui.portGroupBox->layout())->addWidget(port->root, 0, (slot != 0) ? 2 : 0);
static_cast<QGridLayout*>(m_ui.slotGroupBox->layout())->addWidget(port->root, 0, (slot != 0) ? 2 : 0);
}
void MemoryCardSettingsWidget::autoSizeUI()
@@ -193,20 +192,10 @@ void MemoryCardSettingsWidget::updateCardActions()
bool isPS1 = (cardInfo.has_value() ? cardInfo.value().file_type == MemoryCardFileType::PS1 : false);
m_ui.convertCard->setEnabled(hasSelection && !isPS1);
m_ui.duplicateCard->setEnabled(hasSelection);
m_ui.renameCard->setEnabled(hasSelection);
m_ui.deleteCard->setEnabled(hasSelection);
}
void MemoryCardSettingsWidget::duplicateCard()
{
const QString selectedCard(getSelectedCard());
if (selectedCard.isEmpty())
return;
QMessageBox::critical(this, tr("Error"), tr("Not yet implemented."));
}
void MemoryCardSettingsWidget::deleteCard()
{
const QString selectedCard(getSelectedCard());
@@ -289,12 +278,11 @@ void MemoryCardSettingsWidget::listContextMenuRequested(const QPoint& pos)
{
for (u32 slot = 0; slot < MAX_SLOTS; slot++)
{
connect(menu.addAction(tr("Use for Port %1").arg(slot + 1)), &QAction::triggered, this,
connect(menu.addAction(tr("Use for Slot %1").arg(slot + 1)), &QAction::triggered, this,
[this, &selectedCard, slot]() { tryInsertCard(slot, selectedCard); });
}
menu.addSeparator();
connect(menu.addAction(tr("Duplicate")), &QAction::triggered, this, &MemoryCardSettingsWidget::duplicateCard);
connect(menu.addAction(tr("Rename")), &QAction::triggered, this, &MemoryCardSettingsWidget::renameCard);
connect(menu.addAction(tr("Convert")), &QAction::triggered, this, &MemoryCardSettingsWidget::convertCard);
connect(menu.addAction(tr("Delete")), &QAction::triggered, this, &MemoryCardSettingsWidget::deleteCard);
@@ -336,7 +324,7 @@ void MemoryCardSettingsWidget::swapCards()
if (!card1Name.has_value() || card1Name->empty() || !card2Name.has_value() || card2Name->empty())
{
QMessageBox::critical(
QtUtils::GetRootWidget(this), tr("Error"), tr("Both ports must have a card selected to swap."));
QtUtils::GetRootWidget(this), tr("Error"), tr("Both slots must have a card selected to swap."));
return;
}
@@ -98,7 +98,6 @@ private:
QString getSelectedCard() const;
void updateCardActions();
void duplicateCard();
void deleteCard();
void renameCard();
void convertCard();
@@ -24,7 +24,7 @@
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="portGroupBox">
<widget class="QGroupBox" name="slotGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -44,7 +44,7 @@
</size>
</property>
<property name="title">
<string>Console Ports</string>
<string>Memory Card Slots</string>
</property>
<layout class="QGridLayout" name="gridLayout"/>
</widget>
@@ -146,13 +146,6 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="duplicateCard">
<property name="text">
<string>Duplicate</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="renameCard">
<property name="text">
+41 -10
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#include "MainWindow.h"
@@ -32,7 +32,9 @@
#include "common/Path.h"
#include "common/StringUtil.h"
#include <QtGui/QWheelEvent>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QScrollBar>
#include <QtWidgets/QTextEdit>
static QList<SettingsWindow*> s_open_game_properties_dialogs;
@@ -110,7 +112,7 @@ void SettingsWindow::setupUi(const GameList::Entry* game)
addWidget(m_interface_settings = new InterfaceSettingsWidget(this, m_ui.settingsContainer), tr("Interface"),
QStringLiteral("interface-line"),
tr("<strong>Interface Settings</strong><hr>These options control how the software looks and behaves.<br><br>Mouse over an option "
"for additional information."));
"for additional information, and Shift+Wheel to scroll this panel."));
// We don't include game list/bios settings in per-game settings.
if (!isPerGameSettings())
@@ -120,14 +122,15 @@ void SettingsWindow::setupUi(const GameList::Entry* game)
tr("<strong>Game List Settings</strong><hr>The list above shows the directories which will be searched by PCSX2 to populate "
"the game list. Search directories can be added, removed, and switched to recursive/non-recursive."));
addWidget(m_bios_settings = new BIOSSettingsWidget(this, m_ui.settingsContainer), tr("BIOS"), QStringLiteral("chip-line"),
tr("<strong>BIOS Settings</strong><hr>Configure your BIOS here.<br><br>Mouse over an option for additional information."));
tr("<strong>BIOS Settings</strong><hr>Configure your BIOS here.<br><br>Mouse over an option for additional information, "
"and Shift+Wheel to scroll this panel."));
}
// Common to both per-game and global settings.
addWidget(m_emulation_settings = new EmulationSettingsWidget(this, m_ui.settingsContainer), tr("Emulation"),
QStringLiteral("emulation-line"),
tr("<strong>Emulation Settings</strong><hr>These options determine the configuration of frame pacing and game "
"settings.<br><br>Mouse over an option for additional information."));
"settings.<br><br>Mouse over an option for additional information, and Shift+Wheel to scroll this panel."));
if (isPerGameSettings())
{
@@ -153,19 +156,19 @@ void SettingsWindow::setupUi(const GameList::Entry* game)
addWidget(m_graphics_settings = new GraphicsSettingsWidget(this, m_ui.settingsContainer), tr("Graphics"), QStringLiteral("image-fill"),
tr("<strong>Graphics Settings</strong><hr>These options determine the configuration of the graphical output.<br><br>Mouse over an "
"option for additional information."));
"option for additional information, and Shift+Wheel to scroll this panel."));
addWidget(m_audio_settings = new AudioSettingsWidget(this, m_ui.settingsContainer), tr("Audio"), QStringLiteral("volume-up-line"),
tr("<strong>Audio Settings</strong><hr>These options control the audio output of the console.<br><br>Mouse over an option for "
"additional information."));
"additional information, and Shift+Wheel to scroll this panel."));
addWidget(m_memory_card_settings = new MemoryCardSettingsWidget(this, m_ui.settingsContainer), tr("Memory Cards"),
QStringLiteral("memcard-line"),
tr("<strong>Memory Card Settings</strong><hr>Create and configure Memory Cards here.<br><br>Mouse over an option for "
"additional information."));
"additional information, and Shift+Wheel to scroll this panel."));
addWidget(m_dev9_settings = new DEV9SettingsWidget(this, m_ui.settingsContainer), tr("Network & HDD"), QStringLiteral("global-line"),
tr("<strong>Network & HDD Settings</strong><hr>These options control the network connectivity and internal HDD storage of the "
"console.<br><br>Mouse over an option for additional information."));
"console.<br><br>Mouse over an option for additional information, and Shift+Wheel to scroll this panel."));
if (!isPerGameSettings())
{
@@ -199,9 +202,9 @@ void SettingsWindow::setupUi(const GameList::Entry* game)
addWidget(m_advanced_settings = new AdvancedSettingsWidget(this, m_ui.settingsContainer), tr("Advanced"),
QStringLiteral("warning-line"),
tr("<strong>Advanced Settings</strong><hr>These are advanced options to determine the configuration of the simulated "
"console.<br><br>Mouse over an option for additional information."));
"console.<br><br>Mouse over an option for additional information, and Shift+Wheel to scroll this panel."));
addWidget(m_debug_settings = new DebugSettingsWidget(this, m_ui.settingsContainer), tr("Debug"),
QStringLiteral("heart-monitor-line"),
QStringLiteral("debugger-line"),
tr("<strong>Debug Settings</strong><hr>These are options which can be used to log internal information about the application. "
"<strong>Do not modify unless you know what you are doing</strong>, it will cause significant slowdown, and can waste large "
"amounts of disk space."));
@@ -399,10 +402,38 @@ bool SettingsWindow::eventFilter(QObject* object, QEvent* event)
m_ui.helpText->setText(m_category_help_text[m_ui.settingsCategory->currentRow()]);
}
}
else if (event->type() == QEvent::Wheel)
{
if (handleWheelEvent(static_cast<QWheelEvent*>(event)))
return true;
}
return QWidget::eventFilter(object, event);
}
bool SettingsWindow::handleWheelEvent(QWheelEvent* event)
{
if (!(event->modifiers() & Qt::ShiftModifier))
return false;
const int amount = event->hasPixelDelta() ? event->pixelDelta().y() : (event->angleDelta().y() / 20);
QScrollBar* sb = m_ui.helpText->verticalScrollBar();
if (!sb)
return false;
sb->setSliderPosition(std::max(sb->sliderPosition() - amount, 0));
return true;
}
void SettingsWindow::wheelEvent(QWheelEvent* event)
{
if (handleWheelEvent(event))
return;
QWidget::wheelEvent(event);
}
void SettingsWindow::setWindowTitle(const QString& title)
{
if (m_filename.isEmpty())
+6 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#pragma once
@@ -9,12 +9,14 @@
#include <array>
#include <memory>
class QWheelEvent;
class INISettingsInterface;
class SettingsInterface;
namespace GameList
{
struct Entry;
struct Entry;
}
class InterfaceSettingsWidget;
@@ -103,6 +105,7 @@ private Q_SLOTS:
protected:
void closeEvent(QCloseEvent*) override;
void wheelEvent(QWheelEvent* event) override;
private:
enum : u32
@@ -113,6 +116,7 @@ private:
void setupUi(const GameList::Entry* game);
void addWidget(QWidget* widget, QString title, QString icon, QString help_text);
bool handleWheelEvent(QWheelEvent* event);
SettingsWindow* reopen();
+13 -1
View File
@@ -151,7 +151,7 @@
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<enum>Qt::TextBrowserInteraction</enum>
<set>Qt::TextBrowserInteraction</set>
</property>
</widget>
</item>
@@ -233,6 +233,12 @@
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextBrowserInteraction</set>
</property>
</widget>
</item>
<item>
@@ -344,6 +350,12 @@
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextBrowserInteraction</set>
</property>
</widget>
</item>
<item>
@@ -43,7 +43,7 @@ QTableWidgetItem* InputRecordingViewer::createRowItem(std::tuple<bool, u8> butto
void InputRecordingViewer::loadTable()
{
static const auto headers = QStringList({tr("Left Analog"), tr("Right Analog"), tr("Cross"), tr("Square"), tr("Triangle"), tr("Circle"), tr("L1"), tr("R1"), tr("L2"), tr("R2"), tr("D-Pad Down"), tr("D-Pad Right"), tr("D-Pad Up"), tr("D-Pad Left"), tr("L3"), tr("R3"), tr("Select"), tr("Start")});
static const auto headers = QStringList({tr("Left Analog"), tr("Right Analog"), tr("Cross"), tr("Square"), tr("Triangle"), tr("Circle"), tr("L1"), tr("R1"), tr("L2"), tr("R2"), tr("D-Pad Down"), tr("D-Pad Right"), tr("D-Pad Up"), tr("D-Pad Left"), tr("L3"), tr("R3"), tr("Select"), tr("Start")});
m_ui.tableWidget->setColumnCount(headers.length());
m_ui.tableWidget->setHorizontalHeaderLabels(headers);
@@ -111,4 +111,4 @@ void InputRecordingViewer::closeFile()
}
} // TODO else error
m_ui.actionClose->setEnabled(m_file_open);
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More