Compare commits

...

111 Commits

Author SHA1 Message Date
bitiutsm
9162f176a2 GameDB: Fix names 2023-07-07 20:32:36 +01:00
JordanTheToaster
3c140c2ef4 GameDB: NFS U2 Name fix
Quick fix for an incorrect name for NFS U2
2023-07-07 14:10:17 +01:00
JordanTheToaster
511d37e7c3 GameDB: X Squad Fixes
Fixes for crusty textures by using Full mipmapping and trilinear filtering.
2023-07-07 12:55:50 +01:00
Stenzek
10a5ea2a29 3rdparty/SDL2: Bump to v2.28.1 2023-07-07 21:06:53 +10:00
Stenzek
c049f6814b Input/SDL: Load controller DB after init
Tries to lock a non-existant mutex on Windows otherwise.
2023-07-07 21:06:53 +10:00
Sanjay Govind
0716abdbf8 USB: Fix DJ Hero Turntable Labels 2023-07-07 17:25:46 +10:00
Stenzek
989f2bbbb0 GameDB: Enable preload frame for Rocky Legends 2023-07-07 12:35:19 +10:00
Stenzek
45c564749c GS/HW: Improve striped double clear detection
Co-authored-by: refractionpcsx2 <refraction@gmail.com>
2023-07-07 12:35:19 +10:00
Stenzek
a62737b244 GS/HW: Be more strict with double half clear detection
And less strict with letting depth mem clears go through.
2023-07-07 12:35:19 +10:00
Stenzek
1fa3111e67 Qt: Sync video capture state 2023-07-07 12:34:58 +10:00
Stenzek
0e78f3f3bc GS: Improve capture robustness
Automatically restart capture on renderer or hardware reset.
2023-07-07 12:34:58 +10:00
Berylskid
6bf07086a0 GameDB: Various fixes for Armored Core games 2023-07-07 01:41:18 +01:00
JordanTheToaster
b3f8f4e8ec GameDB: Some fixes
Fixes for Redump lying to me and for a black screen in Giant Robot The Animation.
2023-07-07 00:58:16 +01:00
lightningterror
65ee7e82aa gitignore: Remove no longer used files.
wx era.
2023-07-06 13:16:49 +02:00
lightningterror
c78f3b4e24 Savestate: Fix Wsign-compare warning. 2023-07-06 12:58:48 +02:00
lightningterror
51aa7c8ecf GS-hw: Fix warnings.
Wunused-variable,
Wunused-lambda-capture.
2023-07-06 12:58:48 +02:00
Stenzek
64ab92ced6 Qt: Update base translation 2023-07-06 12:30:35 +10:00
Stenzek
8f9f351940 Qt: Don't allow creation of memory cards with invalid names 2023-07-06 12:30:35 +10:00
Stenzek
a9a1af7307 FileSystem: Add IsValidFileName()
And associated tests.
2023-07-06 12:30:35 +10:00
Stenzek
5057dfedba Qt: Rename CreateMemoryCardDialog to MemoryCardCreateDialog
Consistency.
2023-07-06 12:30:35 +10:00
Stenzek
ecabadbf95 CMake: Use FindWayland from ECM
Fixes previously-broken FindWayland.cmake which had local modifications
that prevented PCSX2 from being compiled on OpenSUSE.
2023-07-06 12:30:05 +10:00
Stenzek
97630039d8 CMake: Bump minimum version to 3.16
Required for ECM FindWayland.
2023-07-06 12:30:05 +10:00
forrvalhalla
e7f1178469 GameDB: Various fixes
GameDB: Various fixes
2023-07-06 00:42:08 +01:00
Stenzek
87245ef978 GameDB: Add auto flush for Okage 2023-07-05 12:19:58 +10:00
Stenzek
455aa28724 GS/HW: Use minimum UV as a channel shuffle heuristic
Used by Ape Escape 2, Everybody's Tennis/Golf, Okage, and Valkyrie
Profile 2.
2023-07-05 12:19:58 +10:00
JordanTheToaster
92f70228c9 GameDB: Various fixes 2023-07-04 11:56:04 +01:00
Stenzek
5fa862b346 GS: Fix uninitialized data in deinterlacing 2023-07-04 19:45:48 +10:00
Stenzek
d5c6c318ba GS: Move VSync flush to caller 2023-07-04 19:45:33 +10:00
refractionpcsx2
02133a0290 GS/HW: Missed a Div 0 in previous push. 2023-07-04 10:32:38 +01:00
refractionpcsx2
92b6c1c08d GS/HW: avoid divide by zero's in draw rect calculations 2023-07-04 10:26:38 +01:00
Stenzek
08649b7aa8 GS/Vulkan: Work around NVIDIA driver clear issue
NVIDIA drivers appear to return random garbage when sampling the
RT via a feedback loop, if the load op for the render pass is CLEAR.
Using vkCmdClearAttachments() doesn't work, so we have to clear the
image instead.

I'm not sure if this is a spec violation, or what we're doing just
happens to be undefined. Given attachment clear doesn't work, I'm
inclined to go with the former.
2023-07-04 18:53:11 +10:00
Stenzek
9e19ef0d03 GS/DX12: Fix initial state of expand index buffer 2023-07-04 18:53:11 +10:00
Stenzek
33af3392aa GS: Move clear functions to base GSDevice class 2023-07-04 18:53:11 +10:00
Stenzek
e5a5cf0ef0 GS/Vulkan: Fix merging non-black cleared target 2023-07-04 18:53:11 +10:00
Stenzek
c1ca3888ec GS/HW: Handle more edge cases in double-half clears
Fixes Siren, God of War 2.
2023-07-04 17:33:17 +10:00
Stenzek
1b76bf59a1 GS/HW: Improve accuracy of PrimitiveCoversWithoutGaps() 2023-07-04 17:33:17 +10:00
Stenzek
699c6bf13d GS/HW: Detect one-page-offset RT+Z clear
Gran Turismo 4 Online uses it.
2023-07-03 00:52:33 +01:00
RedDevilus
d9dbf2c5e9 Qt: Add Polish flag
Polish were neglected, that ends now. Flag will be used when it sees a Polish entry in the gamelist.

Fixes https://github.com/PCSX2/pcsx2/issues/9137

Bumps the gamelist cache version from 32 to 33
Adds to enumeration
And make it visible in both gamelist and per-game summary view

Update GameList.cpp
2023-07-02 21:14:40 +01:00
RedDevilus
c22f794a20 Qt: Fix wrongly labeled strings Translations
Bahasa Indonesia and Norsk were wrongly labeled, also marked English as the Default language.
2023-07-02 21:15:59 +10:00
Stenzek
972135e184 GS/Vulkan: Use attachment clear for clears when inside render pass 2023-07-02 13:00:16 +10:00
Stenzek
96fad124ac GS/HW: Improve detection of clears
- Detect "normal" target clears and HLE accordingly
 - Rewrite double-half clears to mask Z or FRAME, reducing false target creation.
 - Handle split single-page-wide clears, and attempt to get a real FBW.
 - Propogate clear values between targets, instead of blitting.
2023-07-02 13:00:16 +10:00
Stenzek
ce7c466041 GS/HW: Fix mem clear when width != fbw 2023-07-02 13:00:16 +10:00
Berylskid
db0c7ca907 GameDB: Various fixes for Armored Core games
- Remove unnecessary CPU Sprite Render Size
- Add HPO Normal for fixing blur
2023-07-01 20:57:33 +01:00
Mrlinkwii
9f62ecdb33 GameDB: add more missing demos 2023-07-01 20:56:18 +01:00
Sanjay Govind
f91f257a7d USB: Add DJ hero turntable emulation 2023-07-01 20:42:48 +10:00
Bartłomiej Piotrowski
28a197b8cd flatpak: Fix the location of mirrored screenshots 2023-07-01 19:55:00 +10:00
Stenzek
9d2d8c0713 CI/Linux: Hopefully fix Flathub release versioning 2023-07-01 14:17:29 +10:00
Stenzek
b431f1dc0d Qt: Update base translation 2023-07-01 14:17:29 +10:00
Stenzek
67eb2975f6 Qt: Make achievements login dialog resizeable 2023-07-01 14:17:29 +10:00
Stenzek
4192de7dac USB: Fix some default strings not being translatable 2023-07-01 14:17:29 +10:00
Stenzek
82cecc89e2 Qt: Fix dropdowns in DEV9 not translating 2023-07-01 14:17:29 +10:00
Stenzek
113e264617 Qt: Fix theme names not being translatable 2023-07-01 14:17:29 +10:00
Stenzek
a705a69022 Qt: Make memory card convert dialog translatable 2023-07-01 14:17:29 +10:00
Stenzek
d757360f4e Qt: Remove some unused Form strings 2023-07-01 14:17:29 +10:00
Stenzek
cc978daeef Qt: Disambiguate toolbar and menu bar items 2023-07-01 14:17:29 +10:00
lightningterror
d38ad1df94 GS-hw: Change some blend operations in hw blend table.
Change the operations for Cs in table to CONST_ZERO as we want it to be 0.
2023-06-30 20:10:12 +02:00
refractionpcsx2
1fd7bcf9a9 GS: Update draw number on combined EE transfers 2023-06-30 16:31:12 +01:00
refractionpcsx2
06abb70624 GS/HW: Don't use unsigned values when calculating rect 2023-06-30 16:31:12 +01:00
Stenzek
78e20868df GS/OpenGL: Fix potentially-incorrect line width 2023-06-30 23:06:51 +10:00
Stenzek
e52766d047 Misc: Fix a few warnings 2023-06-30 21:37:44 +10:00
Stenzek
224460e62d CMake: Remove no-builtin-*cmp, fpmath=sse
The former was for a gcc bug which was long fixed (and we don't use gcc).
The latter is irrelevant with 64-bit builds.
2023-06-30 21:37:44 +10:00
Stenzek
3c408de5c9 Build: Disable exceptions in the compiler 2023-06-30 21:37:44 +10:00
Stenzek
ea803ff2d4 Build: Always use bundled soundtouch
Because we're disabling exceptions in it.

Might gain a bit of speed by -Ofast as well.
2023-06-30 21:37:44 +10:00
Stenzek
14a0786982 3rdparty/soundtouch: Add missing overrides 2023-06-30 21:37:44 +10:00
Stenzek
1dbccb5e3d 3rdparty: Remove exception usage 2023-06-30 21:37:44 +10:00
Stenzek
adca796d94 Common: Remove SafeArray
And replace with std::vector.
2023-06-30 21:37:44 +10:00
Stenzek
732aa96656 Common: Remove AlignedBuffer
And replace its one use site (texture dumping).
2023-06-30 21:37:44 +10:00
Stenzek
6beaec8ba1 Common: Remove Exceptions
The satisfaction is immeasurable.
2023-06-30 21:37:44 +10:00
Stenzek
2ae78f6e2f Misc: Clean up the last places exceptions were used 2023-06-30 21:37:44 +10:00
Stenzek
a889acb332 GS: Remove exceptions 2023-06-30 21:37:44 +10:00
Stenzek
81236209db SaveState: Remove exceptions 2023-06-30 21:37:44 +10:00
Stenzek
52266d7ac0 CDVD: Remove exceptions (completely this time)
The actual reads are still missing error checking...
2023-06-30 21:37:44 +10:00
Stenzek
ab4592b8e9 Common: Add Error class 2023-06-30 21:37:44 +10:00
Connor McLaughlin
7cda571d72 CI/Linux: Enable daily Flathub builds 2023-06-30 20:00:32 +10:00
Stenzek
d0ce4c52b0 GS/Vulkan: Set line width unconditionally on line draw 2023-06-30 14:16:35 +10:00
Stenzek
64ed6f5572 VMManager: Fix cheats warning showing with per-game HC mode 2023-06-29 20:30:10 +01:00
Stenzek
987bebffc7 GS/Vulkan: Make line width dynamic 2023-06-29 20:29:59 +01:00
Stenzek
e9c3807509 CI/Linux: Publish Flathub builds daily [disabled for now] 2023-06-30 02:41:29 +10:00
Stenzek
db642b05c0 CI/Linux: Add manifest to AppStream XML 2023-06-30 02:41:29 +10:00
Stenzek
7da904aa00 CI/Linux: Use add-extensions for ffmpeg in Flatpak 2023-06-30 02:41:29 +10:00
lightningterror
8c09daa22d Revert "Sio: Fix Wunused-variable warning."
This reverts commit 9254403a51.
Apparently there were new changes that made use of the variable.
2023-06-28 23:11:39 +02:00
lightningterror
7ebc04bc34 Interpreter: Cleanup constants, casts, formatting. 2023-06-28 22:59:58 +02:00
lightningterror
9254403a51 Sio: Fix Wunused-variable warning. 2023-06-28 22:59:58 +02:00
Connor McLaughlin
b4250965e6 ElfObject: Fix inverted condition 2023-06-29 00:32:06 +10:00
Stenzek
3fbe704e21 Sio: Replace reinsert spam with a single message 2023-06-28 22:44:54 +10:00
Stenzek
4bfbc355a2 R5900: Fully get rid of exceptions 2023-06-28 22:44:54 +10:00
Stenzek
4d22102fd1 Interpreter: Use local variables for action PCs 2023-06-28 22:44:54 +10:00
Mrlinkwii
129efbda40 GameDB: general clean up 2023-06-28 13:37:54 +01:00
Stenzek
828fb8972c GS/HW: Use range erase instead of vector swap for draw transfers 2023-06-28 20:59:18 +10:00
Stenzek
29b97209fe GS/HW: Split LookupTarget() and CreateTarget() 2023-06-28 20:59:18 +10:00
Berylskid
9c71bec4a0 UI: Remove outdated info from descritption 2023-06-28 15:56:51 +10:00
TellowKrinkle
1bc24c8d7c GHActions:MacOS: Update to macOS 13
Newer clang fixes fun compiler bugs
2023-06-27 20:22:11 -05:00
kamfretoz
76ae5f3b12 Qt: Adjust hyperlink color for Cobalt and Pizza theme 2023-06-27 21:13:12 +01:00
kamfretoz
7a6c0c6b4b Qt: Update main PCSX2 icon 2023-06-27 21:13:12 +01:00
Stenzek
db42792abf GS/HW: When page aligned, dirty page rects instead of SO
Fixes broken scrolling effects in Onimusha 3.
2023-06-27 17:50:04 +10:00
Stenzek
131f16b731 Qt: Update base translation sources 2023-06-27 09:21:23 +02:00
Stenzek
16e47f1d6b Qt: Move audio backend names to core and allow translation 2023-06-27 09:21:23 +02:00
PCSX2 Bot
79e1fd1ea4 PAD: Update to latest controller database. 2023-06-26 23:06:35 +01:00
Mrlinkwii
0c3cc59228 GameDB: fixes for WRC4 demos & update patches 2023-06-26 23:02:11 +01:00
Mrlinkwii
15db9e1778 GameDB: add missing demos 2023-06-26 20:13:02 +01:00
Stenzek
19cf29e5cf CI/Linux: Push to Flathub beta 2023-06-27 01:50:15 +10:00
refractionpcsx2
d51d51b3cc Memcard: Stop Folder memcards double reindexing 2023-06-26 14:45:50 +01:00
refractionpcsx2
c40e132284 SIO/MCD: hugely improved memcard swapping + reinsertion 2023-06-26 14:45:50 +01:00
Connor McLaughlin
f8f54bd892 Qt: Adjust cache folder help text 2023-06-26 20:40:18 +10:00
Stenzek
5302cdcf2b Qt: Remove renderer title from top group box
Save a little vertical space.
2023-06-26 17:52:39 +10:00
Stenzek
8fe9282bd9 Qt: De-duplicate AppIcon 2023-06-26 17:52:39 +10:00
refractionpcsx2
07ed213b1f GameDB: Add blending for Clannad and Clover Heart's VNs 2023-06-25 17:08:22 +01:00
JordanTheToaster
8a1b8d2091 GameDB: Add missing WRC 3 serial
God help me.
2023-06-25 15:30:36 +01:00
IlDucci
034ef5692c Qt: Updating language names
Correcting or expanding language names for both variants of Spanish and Portuguese.
2023-06-25 21:14:46 +10:00
Stenzek
b9b9405c35 Qt: Hook up current translations 2023-06-25 16:45:37 +10:00
JordanTheToaster
ca8d4f9ff0 GameDB: Add missing WRC II Fixes
Adds missing demos and fixes to fix SPS on demos.
2023-06-25 04:09:43 +01:00
224 changed files with 6682 additions and 5164 deletions

View File

@@ -0,0 +1,41 @@
name: 📦 Publish Flathub Release
on:
schedule:
- cron: "0 0 * * *" # Every day at 12am UTC.
workflow_dispatch: # As well as manually.
jobs:
check:
if: github.repository == 'PCSX2/pcsx2'
name: "Check if release is needed"
runs-on: ubuntu-latest
outputs:
PCSX2_RELEASE: ${{ steps.getinfo.outputs.PCSX2_RELEASE }}
FLATHUB_RELEASE: ${{ steps.getinfo.outputs.FLATHUB_RELEASE }}
steps:
- name: Get latest tag and Flathub release
id: getinfo
env:
GH_TOKEN: ${{ github.token }}
run: |
PCSX2_RELEASE=$(gh api -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' /repos/PCSX2/pcsx2/releases | jq -r '.[0].tag_name')
FLATHUB_RELEASE=$(curl -L -s https://flathub.org/api/v2/appstream/net.pcsx2.PCSX2 | jq -r '.releases | max_by(.version) | .version')
echo "Latest PCSX2 release is: '${PCSX2_RELEASE}'"
echo "Latest Flathub release is: '${FLATHUB_RELEASE}'"
echo "PCSX2_RELEASE=${PCSX2_RELEASE}" >> "$GITHUB_OUTPUT"
echo "FLATHUB_RELEASE=${FLATHUB_RELEASE}" >> "$GITHUB_OUTPUT"
build:
needs: check
if: needs.check.outputs.FLATHUB_RELEASE < needs.check.outputs.PCSX2_RELEASE
name: "Build and publish Flatpak"
uses: ./.github/workflows/linux_build_flatpak.yml
with:
jobName: "Qt"
compiler: clang
cmakeflags: ""
publish: true
branch: stable
secrets: inherit

View File

@@ -20,6 +20,10 @@ on:
cmakeflags:
required: true
type: string
branch:
required: false
type: string
default: "stable"
publish:
required: false
type: boolean
@@ -45,6 +49,13 @@ jobs:
with:
submodules: recursive
# Hackity hack. When running the workflow on a schedule, we don't have the tag,
# it doesn't fetch tags, therefore we don't get a version. So grab them manually.
- name: Fetch tags
if: inputs.publish == true
id: fetch-tags
run: git fetch --tags --no-recurse-submodules
- name: Prepare Artifact Metadata
id: artifact-metadata
shell: bash
@@ -73,7 +84,7 @@ jobs:
run: |
./.github/workflows/scripts/linux/generate-metainfo.sh .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml
cat .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml
appstream-util validate .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml
flatpak run org.freedesktop.appstream-glib validate .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml
- name: Build Flatpak
uses: flatpak/flatpak-github-actions/flatpak-builder@v6.1
@@ -84,13 +95,28 @@ jobs:
build-bundle: true
verbose: true
mirror-screenshots-url: https://dl.flathub.org/repo/screenshots
branch: stable
branch: ${{ inputs.branch }}
cache: true
restore-cache: true
cache-key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} flatpak ${{ hashFiles('.github/workflows/scripts/linux/flatpak/**/*.json') }}
- name: Commit screenshots to OSTree
run: |
ostree commit --repo=repo --canonical-permissions --branch=screenshots/x86_64 .github/workflows/scripts/linux/flatpak/screenshots
ostree commit --repo=repo --canonical-permissions --branch=screenshots/x86_64 flatpak_app/screenshots
- name: Push to Flathub beta
if: inputs.publish == true && inputs.branch == 'beta'
uses: flatpak/flatpak-github-actions/flat-manager@v6.1
with:
flat-manager-url: https://hub.flathub.org/
repository: beta
token: ${{ secrets.FLATHUB_BETA_TOKEN }}
- name: Push to Flathub stable
if: inputs.publish == true && inputs.branch == 'stable'
uses: flatpak/flatpak-github-actions/flat-manager@v6.1
with:
flat-manager-url: https://hub.flathub.org/
repository: stable
token: ${{ secrets.FLATHUB_TOKEN }}
# TODO: Push to flathub

View File

@@ -28,3 +28,4 @@ jobs:
compiler: clang
cmakeflags: ""
publish: false
secrets: inherit

View File

@@ -9,7 +9,7 @@ on:
os:
required: false
type: string
default: macos-11.0
default: macos-13
platform:
required: false
type: string
@@ -42,6 +42,9 @@ jobs:
with:
submodules: recursive
- name: Use Xcode 14.3.1
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
- name: Prepare Artifact Metadata
id: artifact-metadata
shell: bash

View File

@@ -26,7 +26,8 @@ jobs:
jobName: "Flatpak"
compiler: clang
cmakeflags: ""
publish: true
branch: "stable"
publish: false
secrets: inherit
# Windows

View File

@@ -61,7 +61,6 @@ declare -a SYSLIBS=(
"libwrap.so.0"
"libharfbuzz.so.0"
"libFLAC.so.8"
"libSoundTouch.so.1"
"libXau.so.6"
"libXcomposite.so.1"
"libXcursor.so.1"
@@ -287,7 +286,7 @@ Plugins = ../lib/plugins
EOF
echo "Copy desktop/icon..."
cp "$PCSX2DIR/pcsx2/Resources/AppIcon64.png" "$OUTDIR/PCSX2.png"
cp "$PCSX2DIR/bin/resources/icons/AppIconLarge.png" "$OUTDIR/PCSX2.png"
cp "$SCRIPTDIR/pcsx2-qt.desktop" "$OUTDIR/PCSX2.desktop"
cp "$SCRIPTDIR/AppRun-qt" "$OUTDIR/AppRun"

View File

@@ -4,7 +4,7 @@ set -e
INSTALLDIR="$HOME/deps"
NPROCS="$(getconf _NPROCESSORS_ONLN)"
SDL=SDL2-2.26.5
SDL=SDL2-2.28.1
QT=6.5.0
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
@@ -12,7 +12,7 @@ mkdir -p deps-build
cd deps-build
cat > SHASUMS <<EOF
ad8fea3da1be64c83c45b1d363a6b4ba8fd60f5bde3b23ec73855709ec5eabf7 $SDL.tar.gz
4977ceba5c0054dbe6c2f114641aced43ce3bf2b41ea64b6a372d6ba129cb15d $SDL.tar.gz
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
fde1aa7b4fbe64ec1b4fc576a57f4688ad1453d2fab59cbadd948a10a6eaf5ef qtbase-everywhere-src-$QT.tar.xz
64ca7e61f44d51e28bcbb4e0509299b53a9a7e38879e00a7fe91643196067a4f qtsvg-everywhere-src-$QT.tar.xz

View File

@@ -1,25 +0,0 @@
{
"name": "soundtouch",
"buildsystem": "cmake-ninja",
"build-options": {
"strip": true
},
"sources": [
{
"type": "git",
"url": "https://codeberg.org/soundtouch/soundtouch.git",
"tag": "2.3.2",
"commit": "29fba832a7920a04eab956b3990c50e13d8c93f9"
}
],
"cleanup": [
"/bin",
"/include",
"/lib/*.a",
"/lib/*.la",
"/lib/cmake",
"/lib/pkgconfig",
"/share/doc"
]
}

View File

@@ -28,8 +28,8 @@
"sources": [
{
"type": "archive",
"url": "https://libsdl.org/release/SDL2-2.26.5.tar.gz",
"sha256": "ad8fea3da1be64c83c45b1d363a6b4ba8fd60f5bde3b23ec73855709ec5eabf7"
"url": "https://libsdl.org/release/SDL2-2.28.1.tar.gz",
"sha256": "4977ceba5c0054dbe6c2f114641aced43ce3bf2b41ea64b6a372d6ba129cb15d"
}
],
"cleanup": [

View File

@@ -6,11 +6,12 @@
"sdk-extensions": [
"org.freedesktop.Sdk.Extension.llvm16"
],
"add-build-extensions": {
"add-extensions": {
"org.freedesktop.Platform.ffmpeg-full": {
"directory": "lib/ffmpeg",
"version": "22.08",
"add-ld-path": "."
"add-ld-path": ".",
"autodownload": true
}
},
"command": "pcsx2-qt",
@@ -26,7 +27,6 @@
"modules": [
"modules/10-libpcap.json",
"modules/11-libaio.json",
"modules/12-soundtouch.json",
"modules/20-sdl2.json",
"modules/21-libbacktrace.json",
{
@@ -56,7 +56,7 @@
"cd build && ninja unittests && cd .."
],
"post-install": [
"install -Dm644 bin/resources/icons/AppIconLarge.png ${FLATPAK_DEST}/share/icons/hicolor/256x256/apps/net.pcsx2.PCSX2.png",
"install -Dm644 bin/resources/icons/AppIconLarge.png ${FLATPAK_DEST}/share/icons/hicolor/512x512/apps/net.pcsx2.PCSX2.png",
"install -Dm644 .github/workflows/scripts/linux/pcsx2-qt.desktop ${FLATPAK_DEST}/share/applications/net.pcsx2.PCSX2.desktop",
"desktop-file-edit --set-key=Icon --set-value=net.pcsx2.PCSX2 ${FLATPAK_DEST}/share/applications/net.pcsx2.PCSX2.desktop",
"install -Dm644 .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.metainfo.xml ${FLATPAK_DEST}/share/metainfo/net.pcsx2.PCSX2.metainfo.xml"

View File

@@ -3,22 +3,30 @@
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
if [[ $# -lt 1 ]]; then
echo "Output file must be provided as a parameter"
exit 1
echo "Output file must be provided as a parameter"
exit 1
fi
OUTFILE=$1
GIT_DATE=$(git log -1 --pretty=%cd --date=short)
GIT_VERSION=$(git tag --points-at HEAD)
GIT_HASH=$(git rev-parse HEAD)
if [[ "${GIT_VERSION}" == "" ]]; then
GIT_VERSION=$(git rev-parse HEAD)
# In the odd event that we run this script before the release gets tagged.
GIT_VERSION=$(git describe --tags)
if [[ "${GIT_VERSION}" == "" ]]; then
GIT_VERSION=$(git rev-parse HEAD)
fi
fi
echo "GIT_DATE: ${GIT_DATE}"
echo "GIT_VERSION: ${GIT_VERSION}"
echo "GIT_HASH: ${GIT_HASH}"
cp "${SCRIPTDIR}"/pcsx2-qt.metainfo.xml.in "${OUTFILE}"
sed -i -e "s/@GIT_VERSION@/${GIT_VERSION}/" "${OUTFILE}"
sed -i -e "s/@GIT_DATE@/${GIT_DATE}/" "${OUTFILE}"
sed -i -e "s/@GIT_HASH@/${GIT_HASH}/" "${OUTFILE}"

View File

@@ -8,12 +8,21 @@ set -e
ARCH=x86_64
KDE_BRANCH=6.5
BRANCH=22.08
FLAT_MANAGER_CLIENT_DIR="$HOME/.local/bin"
# Build packages.
# Build packages. Mostly needed for flat-manager-client.
declare -a BUILD_PACKAGES=(
"flatpak"
"flatpak-builder"
"appstream-util"
"python3-aiohttp"
"python3-tenacity"
"python3-gi"
"gobject-introspection"
"libappstream-glib8"
"libappstream-glib-dev"
"libappstream-dev"
"gir1.2-ostree-1.0"
)
# Flatpak runtimes and SDKs.
@@ -22,6 +31,7 @@ declare -a FLATPAK_PACKAGES=(
"org.kde.Sdk/${ARCH}/${KDE_BRANCH}"
"org.freedesktop.Platform.ffmpeg-full/${ARCH}/${BRANCH}"
"org.freedesktop.Sdk.Extension.llvm16/${ARCH}/${BRANCH}"
"org.freedesktop.appstream-glib/${ARCH}/stable"
)
retry_command sudo apt-get -qq update
@@ -36,3 +46,10 @@ sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub
echo "Will install the following packages for building - ${FLATPAK_PACKAGES[*]}"
retry_command sudo flatpak -y install "${FLATPAK_PACKAGES[@]}"
echo "Downloading flat-manager-client"
mkdir -p "$FLAT_MANAGER_CLIENT_DIR"
pushd "$FLAT_MANAGER_CLIENT_DIR"
aria2c -Z "https://raw.githubusercontent.com/flatpak/flat-manager/master/flat-manager-client"
chmod +x flat-manager-client
echo "$FLAT_MANAGER_CLIENT_DIR" >> $GITHUB_PATH
popd

View File

@@ -37,6 +37,7 @@ declare -a BUILD_PACKAGES=(
# Packages - PCSX2
declare -a PCSX2_PACKAGES=(
"extra-cmake-modules"
"libaio-dev"
"libasound2-dev"
"libbz2-dev"
@@ -52,7 +53,6 @@ declare -a PCSX2_PACKAGES=(
"libpulse-dev"
"librsvg2-dev"
"libsamplerate0-dev"
"libsoundtouch-dev"
"libudev-dev"
"libx11-xcb-dev"
"libavcodec-dev"

View File

@@ -22,8 +22,11 @@
</screenshot>
</screenshots>
<content_rating type="oars-1.1"/>
<update_contact>pcsx2_AT_pcsx2.net</update_contact>
<update_contact>stenzek_AT_gmail.com</update_contact>
<releases>
<release version="@GIT_VERSION@" date="@GIT_DATE@" />
</releases>
<custom>
<value key="flathub::manifest">https://raw.githubusercontent.com/PCSX2/pcsx2/@GIT_HASH@/.github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json</value>
</custom>
</component>

View File

@@ -6,7 +6,7 @@ export MACOSX_DEPLOYMENT_TARGET=10.14
INSTALLDIR="$HOME/deps"
NPROCS="$(getconf _NPROCESSORS_ONLN)"
SDL=SDL2-2.26.5
SDL=SDL2-2.28.1
PNG=1.6.37
JPG=9e
SOUNDTOUCH=soundtouch-2.3.1
@@ -21,7 +21,7 @@ export CFLAGS="-I$INSTALLDIR/include -Os $CFLAGS"
export CXXFLAGS="-I$INSTALLDIR/include -Os $CXXFLAGS"
cat > SHASUMS <<EOF
ad8fea3da1be64c83c45b1d363a6b4ba8fd60f5bde3b23ec73855709ec5eabf7 $SDL.tar.gz
4977ceba5c0054dbe6c2f114641aced43ce3bf2b41ea64b6a372d6ba129cb15d $SDL.tar.gz
505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca libpng-$PNG.tar.xz
4077d6a6a75aeb01884f708919d25934c93305e49f7e3f36db9129320e6f4f3d jpegsrc.v$JPG.tar.gz
6900996607258496ce126924a19fe9d598af9d892cf3f33d1e4daaa9b42ae0b1 $SOUNDTOUCH.tar.gz

2
.gitignore vendored
View File

@@ -90,8 +90,6 @@ oprofile_data/
/ipch
!/3rdparty/libjpeg/change.log
/pcsx2/gui/Resources/*.h
!/pcsx2/gui/Resources/EmbeddedImage.h
/tools/bin
.vs

View File

@@ -9,9 +9,10 @@
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__WIN32__;WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__WIN32__;WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_HAS_EXCEPTIONS=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<ExceptionHandling>false</ExceptionHandling>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>

View File

@@ -4764,23 +4764,9 @@ void cGram::demangleClassName(const std::string& input, cName* retvalue, cGram::
std::string sLength = match[1];
std::string name = match[2];
unsigned long length = 0;
bool ok = true;
try {
length = std::stoul(sLength);
}
catch (const std::invalid_argument&) {
ok = false;
}
catch (const std::out_of_range&) {
ok = false;
}
if (ok) {
if (name.length() == length) {
className = name;
}
unsigned long length = std::stoul(sLength);
if (name.length() == length) {
className = name;
}
}
}

View File

@@ -989,11 +989,11 @@ void RA_Shutdown()
// Call shutdown on toolchain
if (_RA_Shutdown != nullptr)
{
#ifdef __cplusplus
#if defined(__cplusplus) && _HAS_EXCEPTIONS
try {
#endif
_RA_Shutdown();
#ifdef __cplusplus
#if defined(__cplusplus) && _HAS_EXCEPTIONS
}
catch (std::runtime_error&) {
}

View File

@@ -1,4 +1,4 @@
add_library(soundtouch
add_library(pcsx2-soundtouch
source/SoundStretch/WavFile.cpp
source/SoundTouch/AAFilter.cpp
source/SoundTouch/BPMDetect.cpp
@@ -30,5 +30,19 @@ add_library(soundtouch
source/SoundTouch/RateTransposer.h
source/SoundTouch/TDStretch.h
)
target_include_directories(soundtouch PUBLIC soundtouch)
add_library(PkgConfig::SOUNDTOUCH ALIAS soundtouch)
target_include_directories(pcsx2-soundtouch PUBLIC soundtouch)
target_compile_definitions(pcsx2-soundtouch PUBLIC SOUNDTOUCH_FLOAT_SAMPLES ST_NO_EXCEPTION_HANDLING)
set_property(TARGET pcsx2-soundtouch PROPERTY CXX_STANDARD 17)
set_property(TARGET pcsx2-soundtouch PROPERTY CXX_STANDARD_REQUIRED ON)
if(NOT "${CMAKE_BUILD_TYPE}" MATCHES "Debug")
if(MSVC)
target_compile_options(pcsx2-soundtouch PRIVATE /O2 /fp:fast)
else()
target_compile_options(pcsx2-soundtouch PRIVATE -Ofast)
endif()
endif()
add_library(SoundTouch::SoundTouch ALIAS pcsx2-soundtouch)

View File

@@ -31,6 +31,7 @@
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>ST_NO_EXCEPTION_HANDLING;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(ProjectDir)soundtouch;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>

View File

@@ -91,7 +91,7 @@ public:
);
/// destructor
~FIFOSampleBuffer();
~FIFOSampleBuffer() override;
/// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly.
@@ -100,7 +100,7 @@ public:
/// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin();
virtual SAMPLETYPE *ptrBegin() override;
/// Returns a pointer to the end of the used part of the sample buffer (i.e.
/// where the new samples are to be inserted). This function may be used for
@@ -121,7 +121,7 @@ public:
/// the sample buffer.
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
uint numSamples ///< Number of samples to insert.
);
) override;
/// Adjusts the book-keeping to increase number of samples in the buffer without
/// copying any actual samples.
@@ -139,7 +139,7 @@ public:
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
);
) override;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
@@ -147,10 +147,10 @@ public:
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
);
) override;
/// Returns number of samples currently available.
virtual uint numSamples() const;
virtual uint numSamples() const override;
/// Sets number of channels, 1 = mono, 2 = stereo.
void setChannels(int numChannels);
@@ -162,14 +162,14 @@ public:
}
/// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const;
virtual int isEmpty() const override;
/// Clears all the samples.
virtual void clear();
virtual void clear() override;
/// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples
uint adjustAmountOfSamples(uint numSamples);
uint adjustAmountOfSamples(uint numSamples) override;
/// Add silence to end of buffer
void addSilent(uint nSamples);

View File

@@ -164,7 +164,7 @@ protected:
}
/// Destructor.
virtual ~FIFOProcessor()
virtual ~FIFOProcessor() override
{
}
@@ -175,7 +175,7 @@ protected:
/// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin()
virtual SAMPLETYPE *ptrBegin() override
{
return output->ptrBegin();
}
@@ -189,7 +189,7 @@ public:
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
)
) override
{
return output->receiveSamples(outBuffer, maxSamples);
}
@@ -200,26 +200,26 @@ public:
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
)
) override
{
return output->receiveSamples(maxSamples);
}
/// Returns number of samples currently available.
virtual uint numSamples() const
virtual uint numSamples() const override
{
return output->numSamples();
}
/// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const
virtual int isEmpty() const override
{
return output->isEmpty();
}
/// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples
virtual uint adjustAmountOfSamples(uint numSamples)
virtual uint adjustAmountOfSamples(uint numSamples) override
{
return output->adjustAmountOfSamples(numSamples);
}

View File

@@ -209,7 +209,7 @@ protected :
public:
SoundTouch();
virtual ~SoundTouch();
virtual ~SoundTouch() override;
/// Get SoundTouch library version string
static const char *getVersionString();
@@ -287,7 +287,7 @@ public:
uint numSamples ///< Number of samples in buffer. Notice
///< that in case of stereo-sound a single sample
///< contains data for both channels.
);
) override;
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
@@ -296,7 +296,7 @@ public:
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
);
) override;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
@@ -304,11 +304,11 @@ public:
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
);
) override;
/// Clears all the samples in the object's output and internal processing
/// buffers.
virtual void clear();
virtual void clear() override;
/// Changes a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's.

View File

@@ -0,0 +1,3 @@
// autotools configuration step replaces this file with a configured version.
// this empty file stub is provided to avoid error about missing include file
// when not using autotools build

View File

@@ -106,12 +106,12 @@ public:
short *filterCoeffsUnalign;
short *filterCoeffsAlign;
virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const;
virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const override;
public:
FIRFilterMMX();
~FIRFilterMMX();
virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor);
virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) override;
};
#endif // SOUNDTOUCH_ALLOW_MMX
@@ -125,12 +125,12 @@ public:
float *filterCoeffsUnalign;
float *filterCoeffsAlign;
virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const;
virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const override;
public:
FIRFilterSSE();
~FIRFilterSSE();
virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor);
virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) override;
};
#endif // SOUNDTOUCH_ALLOW_SSE

View File

@@ -43,20 +43,20 @@ class InterpolateCubic : public TransposerBase
protected:
virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples);
int &srcSamples) override;
virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples);
int &srcSamples) override;
virtual int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples);
int &srcSamples) override;
double fract;
public:
InterpolateCubic();
virtual void resetRegisters();
virtual void resetRegisters() override;
int getLatency() const
{

View File

@@ -47,21 +47,21 @@ protected:
virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples);
int &srcSamples) override;
virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples);
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples);
int &srcSamples) override;
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) override;
public:
InterpolateLinearInteger();
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates.
virtual void setRate(double newRate);
virtual void setRate(double newRate) override;
virtual void resetRegisters();
virtual void resetRegisters() override;
int getLatency() const
int getLatency() const override
{
return 0;
}
@@ -87,7 +87,7 @@ public:
virtual void resetRegisters();
int getLatency() const
int getLatency() const override
{
return 0;
}

View File

@@ -48,20 +48,20 @@ class InterpolateShannon : public TransposerBase
protected:
int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples);
int &srcSamples) override;
int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples);
int &srcSamples) override;
int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples);
int &srcSamples) override;
double fract;
public:
InterpolateShannon();
void resetRegisters();
void resetRegisters() override;
int getLatency() const
{

View File

@@ -124,7 +124,7 @@ protected:
public:
RateTransposer();
virtual ~RateTransposer();
virtual ~RateTransposer() override;
/// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; };
@@ -147,13 +147,13 @@ public:
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
/// the input of the object.
void putSamples(const SAMPLETYPE *samples, uint numSamples);
void putSamples(const SAMPLETYPE *samples, uint numSamples) override;
/// Clears all the samples in the object
void clear();
void clear() override;
/// Returns nonzero if there aren't any samples available for outputting.
int isEmpty() const;
int isEmpty() const override;
/// Return approximate initial input-output latency
int getLatency() const;

View File

@@ -165,7 +165,7 @@ protected:
public:
TDStretch();
virtual ~TDStretch();
virtual ~TDStretch() override;
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we've a MMX/SSE/etc-capable CPU available or not.
@@ -187,7 +187,7 @@ public:
void setTempo(double newTempo);
/// Returns nonzero if there aren't any samples available for outputting.
virtual void clear();
virtual void clear() override;
/// Clears the input buffer
void clearInput();
@@ -227,7 +227,7 @@ public:
const SAMPLETYPE *samples, ///< Input sample data
uint numSamples ///< Number of samples in 'samples' so that one sample
///< contains both channels if stereo
);
) override;
/// return nominal input sample requirement for triggering a processing batch
int getInputSampleReq() const
@@ -256,10 +256,10 @@ public:
class TDStretchMMX : public TDStretch
{
protected:
double calcCrossCorr(const short *mixingPos, const short *compare, double &norm);
double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm);
virtual void overlapStereo(short *output, const short *input) const;
virtual void clearCrossCorrState();
double calcCrossCorr(const short *mixingPos, const short *compare, double &norm) override;
double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm) override;
virtual void overlapStereo(short *output, const short *input) const override;
virtual void clearCrossCorrState() override;
};
#endif /// SOUNDTOUCH_ALLOW_MMX
@@ -269,8 +269,8 @@ public:
class TDStretchSSE : public TDStretch
{
protected:
double calcCrossCorr(const float *mixingPos, const float *compare, double &norm);
double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm);
double calcCrossCorr(const float *mixingPos, const float *compare, double &norm) override;
double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm) override;
};
#endif /// SOUNDTOUCH_ALLOW_SSE

View File

@@ -1,6 +1,6 @@
# Setting it to a range tells it that it supports the features on the newer
# versions as well, avoiding setting policies.
cmake_minimum_required(VERSION 3.12...3.24)
cmake_minimum_required(VERSION 3.16...3.24)
#Enabling this cmake policy gets rid of warnings regarding LTO.
cmake_policy(SET CMP0069 NEW)
@@ -62,8 +62,6 @@ endif()
# tests
if(ACTUALLY_ENABLE_TESTS)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(3rdparty/gtest EXCLUDE_FROM_ALL)
add_subdirectory(tests/ctest)
endif()

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,7 @@
03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000290000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
03000000c82d00003038000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
03000000c82d00006928000000000000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,platform:Windows,
030000003512000012ab000000000000,8BitDo NES30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Windows,
03000000c82d000012ab000000000000,8BitDo NES30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000022000000090000000000000,8BitDo NES30 Pro,a:b1,b:b0,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
@@ -68,8 +69,11 @@
03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001230000000000000,8BitDo Ultimate,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,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001530000000000000,8BitDo Ultimate C,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001630000000000000,8BitDo Ultimate C,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001730000000000000,8BitDo Ultimate C,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001130000000000000,8BitDo Ultimate Wired,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,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001230000000000000,8BitDo Ultimate Wireless,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001330000000000000,8BitDo Ultimate Wireless,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,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000121000000000000,8BitDo Xbox One SN30 Pro,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
@@ -386,6 +390,7 @@
03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
0300000079000000d218000000000000,Mayflash Magic NS,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:Windows,
03000000d620000010a7000000000000,Mayflash Magic NS,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,
03000000242f0000f400000000000000,Mayflash N64 Controller 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:a5,start:b9,platform:Windows,
03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows,
030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
@@ -784,6 +789,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d000012ab000001000000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00002028000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -807,6 +813,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000260000001000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001230000000010000,8BitDo Ultimate,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,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001530000001000000,8BitDo Ultimate C,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:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001630000001000000,8BitDo Ultimate C,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:Mac OS X,
03000000c82d00001730000001000000,8BitDo Ultimate C,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:Mac OS X,
03000000c82d00001130000000020000,8BitDo Ultimate Wired,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,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001330000001000000,8BitDo Ultimate Wireless,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,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001330000000020000,8BitDo Ultimate Wireless Controller,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,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -1045,6 +1055,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,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:b4,y:b3,platform:Linux,
05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,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:b4,y:b3,platform:Linux,
05000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux,
03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,
@@ -1082,6 +1093,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000260000011010000,8BitDo SN30 Pro Plus,a:b1,b:b0,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:b4,y:b3,platform:Linux,
05000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,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:b4,y:b3,platform:Linux,
05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001230000000010000,8BitDo Ultimate,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,
03000000c82d00001730000011010000,8BitDo Ultimate 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,
03000000c82d00001530000011010000,8BitDo Ultimate C,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,
03000000c82d00001630000011010000,8BitDo Ultimate C,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,
03000000c82d00001130000011010000,8BitDo Ultimate Wired,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,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000760000011010000,8BitDo Ultimate Wireless,a:b1,b:b0,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:b4,y:b3,platform:Linux,
03000000c82d00001230000011010000,8BitDo Ultimate Wireless,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,
@@ -1294,8 +1309,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000ea02000008040000,Microsoft Xbox One,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,
060000005e040000120b000009050000,Microsoft Xbox One,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,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000e302000003020000,Microsoft Xbox One Elite,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,
030000005e040000000b000007040000,Microsoft Xbox One Elite 2,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,paddle1:b12,paddle3:b13,paddle2,b14,paddle4:b15,platform:Linux,
030000005e040000000b000008040000,Microsoft Xbox One Elite 2,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,paddle1:b12,paddle3:b13,paddle2,b14,paddle4:b15,platform:Linux,
030000005e040000000b000007040000,Microsoft Xbox One Elite 2,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,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000000b000008040000,Microsoft Xbox One Elite 2,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,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e040000120b00000b050000,Microsoft Xbox Series Controller,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,
03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
@@ -1516,7 +1531,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
03000000591c00002600000010010000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,leftshoulder:b4,rightshoulder:b5,x:b3,y:b0,start:b7,platform:Linux,
03000000591c00002600000010010000,THEGamepad,a:b2,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,
030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,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:Linux,
030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,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:Linux,
030000004f04000020b3000010010000,Thrustmaster Dual Trigger,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:Linux,
@@ -1542,7 +1557,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
030000005f140000c501000010010000,Trust 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,
06000000f51000000870000003010000,Turtle Beach Recon,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
06000000f51000000870000003010000,Turtle Beach Recon,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,
03000000100800000100000010010000,Twin PS2 Adapter,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:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000151900005678000010010000,Uniplay U6,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:Linux,
03000000100800000300000010010000,USB Gamepad,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:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

View File

@@ -134,8 +134,6 @@ add_compile_options("${ARCH_FLAG_LIST}")
option(USE_PGO_GENERATE "Enable PGO optimization (generate profile)")
option(USE_PGO_OPTIMIZE "Enable PGO optimization (use profile)")
# Note1: Builtin strcmp/memcmp was proved to be slower on Mesa than stdlib version.
# Note2: float operation SSE is impacted by the PCSX2 SSE configuration. In particular, flush to zero denormal.
if(MSVC AND NOT USE_CLANG_CL)
add_compile_options(
"$<$<COMPILE_LANGUAGE:CXX>:/Zc:externConstexpr>"
@@ -144,8 +142,20 @@ if(MSVC AND NOT USE_CLANG_CL)
"/Zo"
"/utf-8"
)
elseif(NOT MSVC)
add_compile_options(-pipe -fvisibility=hidden -pthread -fno-builtin-strcmp -fno-builtin-memcmp -mfpmath=sse)
endif()
if(MSVC)
# Disable RTTI
string(REPLACE "/GR" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
# Disable Exceptions
string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
else()
add_compile_options(-pipe -fvisibility=hidden -pthread)
add_compile_options(
"$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>"
"$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>"
)
endif()
set(CONFIG_REL_NO_DEB $<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>>)
@@ -156,8 +166,9 @@ if(WIN32)
$<$<CONFIG:Debug>:_ITERATOR_DEBUG_LEVEL=2>
$<$<CONFIG:Devel>:_ITERATOR_DEBUG_LEVEL=1>
$<${CONFIG_ANY_REL}:_ITERATOR_DEBUG_LEVEL=0>
_HAS_EXCEPTIONS=0
)
list(APPEND PCSX2_DEFS TIXML_USE_STL _SCL_SECURE_NO_WARNINGS _UNICODE UNICODE)
list(APPEND PCSX2_DEFS _SCL_SECURE_NO_WARNINGS _UNICODE UNICODE)
endif()
# Enable debug information in release builds for Linux.

View File

@@ -1,68 +0,0 @@
# Try to find Wayland on a Unix system
#
# This will define:
#
# Wayland_FOUND - True if Wayland is found
#
# The following imported targets:
# Wayland::Client - Imported Client
# Wayland::Server - Imported Server
# Wayland::Egl - Imported Egl
# Wayland::Cursor - Imported Cursor
#
# Copyright (c) 2013 Martin Gräßlin <mgraesslin@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
IF (NOT WIN32)
IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES)
# In the cache already
SET(WAYLAND_FIND_QUIETLY TRUE)
ENDIF ()
FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h)
FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h)
FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h)
FIND_PATH(WAYLAND_CURSOR_INCLUDE_DIR NAMES wayland-cursor.h)
FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client)
FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server)
FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl)
FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor)
include(FindPackageHandleStandardArgs)
# FIND_PACKAGE_HANDLE_STANDARD_ARGS is just meant to find the main package and set package found. Not set variables or find individual libs
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Wayland REQUIRED_VARS
WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR
WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR
WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR
WAYLAND_CURSOR_LIBRARIES WAYLAND_CURSOR_INCLUDE_DIR
)
if (WAYLAND_CLIENT_INCLUDE_DIR AND WAYLAND_CLIENT_LIBRARIES AND NOT TARGET Wayland::Client)
add_library(Wayland::Client UNKNOWN IMPORTED)
set_target_properties(Wayland::Client PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_CLIENT_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_CLIENT_LIBRARIES}")
endif()
if (WAYLAND_SERVER_INCLUDE_DIR AND WAYLAND_SERVER_LIBRARIES AND NOT TARGET Wayland::Server)
add_library(Wayland::Server UNKNOWN IMPORTED)
set_target_properties(Wayland::Server PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_SERVER_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_SERVER_LIBRARIES}")
endif()
if (WAYLAND_EGL_INCLUDE_DIR AND WAYLAND_EGL_LIBRARIES AND NOT TARGET Wayland::Egl)
add_library(Wayland::Egl UNKNOWN IMPORTED)
set_target_properties(Wayland::Egl PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_EGL_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_EGL_LIBRARIES}")
endif()
if (WAYLAND_CURSOR_INCLUDE_DIR AND WAYLAND_CURSOR_LIBRARIES AND NOT TARGET Wayland::Cursor)
add_library(Wayland::Cursor UNKNOWN IMPORTED)
set_target_properties(Wayland::Cursor PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_CURSOR_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_CURSOR_LIBRARIES}")
endif()
MARK_AS_ADVANCED(
WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
WAYLAND_CURSOR_INCLUDE_DIR WAYLAND_CURSOR_LIBRARIES
)
ENDIF ()

View File

@@ -9,7 +9,6 @@ if (WIN32)
add_subdirectory(3rdparty/zlib EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/libpng EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/libjpeg EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/soundtouch EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/wil EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/xz EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/D3D12MemAlloc EXCLUDE_FROM_ALL)
@@ -74,8 +73,6 @@ else()
endif()
endif()
check_lib(SOUNDTOUCH SoundTouch SoundTouch.h PATH_SUFFIXES soundtouch)
if(NOT QT_BUILD)
find_optional_system_library(SDL2 3rdparty/sdl2 2.0.12)
endif()
@@ -85,7 +82,9 @@ else()
make_imported_target_if_missing(X11::X11 X11)
if(WAYLAND_API)
find_package(Wayland REQUIRED)
find_package(ECM REQUIRED NO_MODULE)
list(APPEND CMAKE_MODULE_PATH "${ECM_MODULE_PATH}")
find_package(Wayland REQUIRED Egl)
endif()
find_package(Libbacktrace)
@@ -165,6 +164,7 @@ endif()
add_subdirectory(3rdparty/lzma EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/libchdr EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/soundtouch EXCLUDE_FROM_ALL)
# rapidyaml includes fast_float as a submodule, saves us pulling it in directly.
# Normally, we'd just pull in the cmake project, and link to it, but... it seems to enable

View File

@@ -42,116 +42,3 @@ extern void _aligned_free(void* pmem);
#define pcsx2_aligned_realloc(handle, new_size, align, old_size) \
_aligned_realloc(handle, new_size, align)
#endif
// --------------------------------------------------------------------------------------
// AlignedBuffer
// --------------------------------------------------------------------------------------
// A simple container class for an aligned allocation. By default, no bounds checking is
// performed, and there is no option for enabling bounds checking. If bounds checking and
// other features are needed, use the more robust SafeArray<> instead.
//
template <typename T, uint align>
class AlignedBuffer
{
static_assert(std::is_pod<T>::value, "Must use a POD type");
struct Deleter
{
void operator()(T* ptr)
{
_aligned_free(ptr);
}
};
std::unique_ptr<T[], Deleter> m_buffer;
std::size_t m_size;
public:
AlignedBuffer(size_t size = 0)
{
Alloc(size);
}
AlignedBuffer(const AlignedBuffer& copy)
{
Alloc(copy.m_size);
if (copy.m_size > 0)
std::memcpy(m_buffer.get(), copy.m_buffer.get(), copy.m_size);
}
AlignedBuffer(AlignedBuffer&& move)
: m_buffer(std::move(move.m_buffer))
, m_size(move.m_size)
{
move.m_size = 0;
}
size_t GetSize() const { return m_size; }
size_t GetLength() const { return m_size; }
void Alloc(size_t newsize)
{
m_size = newsize;
m_buffer.reset();
if (!m_size)
return;
m_buffer.reset(reinterpret_cast<T*>(_aligned_malloc(this->m_size * sizeof(T), align)));
if (!m_buffer)
throw std::bad_alloc();
}
void Resize(size_t newsize)
{
m_buffer.reset(reinterpret_cast<T*>(pcsx2_aligned_realloc(m_buffer.release(), newsize * sizeof(T), align, m_size * sizeof(T))));
m_size = newsize;
if (!m_buffer)
throw std::bad_alloc();
}
void Free()
{
Alloc(0);
}
// Makes enough room for the requested size. Existing data in the array is retained.
void MakeRoomFor(uint size)
{
if (size <= m_size)
return;
Resize(size);
}
AlignedBuffer& operator=(const AlignedBuffer& copy)
{
Alloc(copy.m_size);
if (copy.m_size > 0)
std::memcpy(m_buffer.get(), copy.m_buffer.get(), copy.m_size);
return *this;
}
AlignedBuffer& operator=(AlignedBuffer&& move)
{
m_buffer = std::move(move.m_buffer);
m_size = move.m_size;
move.m_size = 0;
return *this;
}
T* GetPtr(uint idx = 0) const
{
return &m_buffer[idx];
}
T& operator[](uint idx)
{
return m_buffer[idx];
}
const T& operator[](uint idx) const
{
return m_buffer[idx];
}
};

133
common/Assertions.cpp Normal file
View File

@@ -0,0 +1,133 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "Threading.h"
#include "General.h"
#include "Assertions.h"
#include "CrashHandler.h"
#include <mutex>
#include "fmt/core.h"
#ifdef _WIN32
#include "RedtapeWindows.h"
#include <intrin.h>
#include <tlhelp32.h>
#endif
#ifdef __UNIX__
#include <signal.h>
#endif
static std::mutex s_assertion_failed_mutex;
static inline void FreezeThreads(void** handle)
{
#if defined(_WIN32)
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (snapshot != INVALID_HANDLE_VALUE)
{
THREADENTRY32 threadEntry;
if (Thread32First(snapshot, &threadEntry))
{
do
{
if (threadEntry.th32ThreadID == GetCurrentThreadId())
continue;
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, threadEntry.th32ThreadID);
if (hThread != nullptr)
{
SuspendThread(hThread);
CloseHandle(hThread);
}
} while (Thread32Next(snapshot, &threadEntry));
}
}
*handle = static_cast<void*>(snapshot);
#else
* handle = nullptr;
#endif
}
static inline void ResumeThreads(void* handle)
{
#if defined(_WIN32)
if (handle != INVALID_HANDLE_VALUE)
{
THREADENTRY32 threadEntry;
if (Thread32First(reinterpret_cast<HANDLE>(handle), &threadEntry))
{
do
{
if (threadEntry.th32ThreadID == GetCurrentThreadId())
continue;
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, threadEntry.th32ThreadID);
if (hThread != nullptr)
{
ResumeThread(hThread);
CloseHandle(hThread);
}
} while (Thread32Next(reinterpret_cast<HANDLE>(handle), &threadEntry));
}
CloseHandle(reinterpret_cast<HANDLE>(handle));
}
#else
#endif
}
void pxOnAssertFail(const char* file, int line, const char* func, const char* msg)
{
std::unique_lock guard(s_assertion_failed_mutex);
void* handle;
FreezeThreads(&handle);
char full_msg[512];
std::snprintf(full_msg, sizeof(full_msg), "%s:%d: assertion failed in function %s: %s\n", file, line, func, msg);
#if defined(_WIN32)
HANDLE error_handle = GetStdHandle(STD_ERROR_HANDLE);
if (error_handle != INVALID_HANDLE_VALUE)
WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), full_msg, static_cast<DWORD>(std::strlen(full_msg)), NULL, NULL);
OutputDebugStringA(full_msg);
std::snprintf(
full_msg, sizeof(full_msg),
"Assertion failed in function %s (%s:%d):\n\n%s\n\nPress Abort to exit, Retry to break to debugger, or Ignore to attempt to continue.",
func, file, line, msg);
int result = MessageBoxA(NULL, full_msg, NULL, MB_ABORTRETRYIGNORE | MB_ICONERROR);
if (result == IDRETRY)
{
__debugbreak();
}
else if (result != IDIGNORE)
{
// try to save a crash dump before exiting
CrashHandler::WriteDumpForCaller();
TerminateProcess(GetCurrentProcess(), 0xBAADC0DE);
}
#else
fputs(full_msg, stderr);
fputs("\nAborting application.\n", stderr);
fflush(stderr);
AbortWithMessage(full_msg);
#endif
ResumeThreads(handle);
}

View File

@@ -10,11 +10,11 @@ add_library(common)
# x86emitter sources
target_sources(common PRIVATE
AlignedMalloc.cpp
SafeArray.inl
Assertions.cpp
Console.cpp
CrashHandler.cpp
DynamicLibrary.cpp
Exceptions.cpp
Error.cpp
FastJmp.cpp
FileSystem.cpp
General.cpp
@@ -70,7 +70,7 @@ target_sources(common PRIVATE
DynamicLibrary.h
Easing.h
EnumOps.h
Exceptions.h
Error.h
FastJmp.h
FileSystem.h
General.h
@@ -89,7 +89,6 @@ target_sources(common PRIVATE
ReadbackSpinManager.h
RedtapeWilCom.h
RedtapeWindows.h
SafeArray.h
ScopedGuard.h
SettingsInterface.h
SettingsWrapper.h

192
common/Error.cpp Normal file
View File

@@ -0,0 +1,192 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "Error.h"
#include <cstdlib>
#include <cstring>
#include <type_traits>
#include "fmt/format.h"
// Platform-specific includes
#if defined(_WIN32)
#include "RedtapeWindows.h"
static_assert(std::is_same<DWORD, unsigned long>::value, "DWORD is unsigned long");
static_assert(std::is_same<HRESULT, long>::value, "HRESULT is long");
#endif
Error::Error() = default;
Error::Error(const Error& c) = default;
Error::Error(Error&& e) = default;
Error::~Error() = default;
void Error::Clear()
{
m_description = {};
}
void Error::SetErrno(int err)
{
m_type = Type::Errno;
#ifdef _MSC_VER
char buf[128];
if (strerror_s(buf, sizeof(buf), err) != 0)
m_description = fmt::format("errno {}: {}", err, buf);
else
m_description = fmt::format("errno {}: <Could not get error message>", err);
#else
const char* buf = std::strerror(err);
if (buf)
m_description = fmt::format("errno {}: {}", err, buf);
else
m_description = fmt::format("errno {}: <Could not get error message>", err);
#endif
}
void Error::SetErrno(Error* errptr, int err)
{
if (errptr)
errptr->SetErrno(err);
}
void Error::SetString(std::string description)
{
m_type = Type::User;
m_description = std::move(description);
}
void Error::SetString(Error* errptr, std::string description)
{
if (errptr)
errptr->SetString(std::move(description));
}
#ifdef _WIN32
void Error::SetWin32(unsigned long err)
{
m_type = Type::Win32;
char buf[128];
const DWORD r = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, 0, buf, sizeof(buf), nullptr);
if (r > 0)
m_description = fmt::format("Win32 Error {}: {}", err, std::string_view(buf, r));
else
m_description = fmt::format("Win32 Error {}: <Could not resolve system error ID>");
}
void Error::SetWin32(Error* errptr, unsigned long err)
{
if (errptr)
errptr->SetWin32(err);
}
void Error::SetHResult(long err)
{
m_type = Type::HResult;
char buf[128];
const DWORD r = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, 0, buf, sizeof(buf), nullptr);
if (r > 0)
m_description = fmt::format("HRESULT {:08X}: {}", err, std::string_view(buf, r));
else
m_description = fmt::format("HRESULT {:08X}: <Could not resolve system error ID>");
}
void Error::SetHResult(Error* errptr, long err)
{
if (errptr)
errptr->SetHResult(err);
}
#endif
void Error::SetSocket(int err)
{
// Socket errors are win32 errors on windows
#ifdef _WIN32
SetWin32(err);
#else
SetErrno(err);
#endif
m_type = Type::Socket;
}
void Error::SetSocket(Error* errptr, int err)
{
if (errptr)
errptr->SetSocket(err);
}
Error Error::CreateNone()
{
return Error();
}
Error Error::CreateErrno(int err)
{
Error ret;
ret.SetErrno(err);
return ret;
}
Error Error::CreateSocket(int err)
{
Error ret;
ret.SetSocket(err);
return ret;
}
Error Error::CreateString(std::string description)
{
Error ret;
ret.SetString(std::move(description));
return ret;
}
#ifdef _WIN32
Error Error::CreateWin32(unsigned long err)
{
Error ret;
ret.SetWin32(err);
return ret;
}
Error Error::CreateHResult(long err)
{
Error ret;
ret.SetHResult(err);
return ret;
}
#endif
Error& Error::operator=(const Error& e) = default;
Error& Error::operator=(Error&& e) = default;
bool Error::operator==(const Error& e) const
{
return (m_type == e.m_type && m_description == e.m_description);
}
bool Error::operator!=(const Error& e) const
{
return (m_type != e.m_type || m_description != e.m_description);
}

84
common/Error.h Normal file
View File

@@ -0,0 +1,84 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "Pcsx2Defs.h"
#include <string>
class Error
{
public:
Error();
Error(const Error& e);
Error(Error&& e);
~Error();
enum class Type
{
None = 0,
Errno = 1,
Socket = 2,
User = 3,
Win32 = 4,
HResult = 5,
};
__fi Type GetType() const { return m_type; }
__fi const std::string& GetDescription() const { return m_description; }
void Clear();
/// Error that is set by system functions, such as open().
void SetErrno(int err);
/// Error that is set by socket functions, such as socket(). On Unix this is the same as errno.
void SetSocket(int err);
/// Set both description and message.
void SetString(std::string description);
#ifdef _WIN32
/// Error that is returned by some Win32 functions, such as RegOpenKeyEx. Also used by other APIs through GetLastError().
void SetWin32(unsigned long err);
/// Error that is returned by Win32 COM methods, e.g. S_OK.
void SetHResult(long err);
#endif
static Error CreateNone();
static Error CreateErrno(int err);
static Error CreateSocket(int err);
static Error CreateString(std::string description);
#ifdef _WIN32
static Error CreateWin32(unsigned long err);
static Error CreateHResult(long err);
#endif
// helpers for setting
static void SetErrno(Error* errptr, int err);
static void SetSocket(Error* errptr, int err);
static void SetString(Error* errptr, std::string description);
static void SetWin32(Error* errptr, unsigned long err);
static void SetHResult(Error* errptr, long err);
Error& operator=(const Error& e);
Error& operator=(Error&& e);
bool operator==(const Error& e) const;
bool operator!=(const Error& e) const;
private:
Type m_type = Type::None;
std::string m_description;
};

View File

@@ -1,346 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "Threading.h"
#include "General.h"
#include "Exceptions.h"
#include "CrashHandler.h"
#include <mutex>
#include "fmt/core.h"
#ifdef _WIN32
#include "RedtapeWindows.h"
#include <intrin.h>
#include <tlhelp32.h>
#endif
#ifdef __UNIX__
#include <signal.h>
#endif
static std::mutex s_assertion_failed_mutex;
static inline void FreezeThreads(void** handle)
{
#if defined(_WIN32)
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (snapshot != INVALID_HANDLE_VALUE)
{
THREADENTRY32 threadEntry;
if (Thread32First(snapshot, &threadEntry))
{
do
{
if (threadEntry.th32ThreadID == GetCurrentThreadId())
continue;
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, threadEntry.th32ThreadID);
if (hThread != nullptr)
{
SuspendThread(hThread);
CloseHandle(hThread);
}
} while (Thread32Next(snapshot, &threadEntry));
}
}
*handle = static_cast<void*>(snapshot);
#else
* handle = nullptr;
#endif
}
static inline void ResumeThreads(void* handle)
{
#if defined(_WIN32)
if (handle != INVALID_HANDLE_VALUE)
{
THREADENTRY32 threadEntry;
if (Thread32First(reinterpret_cast<HANDLE>(handle), &threadEntry))
{
do
{
if (threadEntry.th32ThreadID == GetCurrentThreadId())
continue;
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, threadEntry.th32ThreadID);
if (hThread != nullptr)
{
ResumeThread(hThread);
CloseHandle(hThread);
}
} while (Thread32Next(reinterpret_cast<HANDLE>(handle), &threadEntry));
}
CloseHandle(reinterpret_cast<HANDLE>(handle));
}
#else
#endif
}
void pxOnAssertFail(const char* file, int line, const char* func, const char* msg)
{
std::unique_lock guard(s_assertion_failed_mutex);
void* handle;
FreezeThreads(&handle);
char full_msg[512];
std::snprintf(full_msg, sizeof(full_msg), "%s:%d: assertion failed in function %s: %s\n", file, line, func, msg);
#if defined(_WIN32)
HANDLE error_handle = GetStdHandle(STD_ERROR_HANDLE);
if (error_handle != INVALID_HANDLE_VALUE)
WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), full_msg, static_cast<DWORD>(std::strlen(full_msg)), NULL, NULL);
OutputDebugStringA(full_msg);
std::snprintf(
full_msg, sizeof(full_msg),
"Assertion failed in function %s (%s:%d):\n\n%s\n\nPress Abort to exit, Retry to break to debugger, or Ignore to attempt to continue.",
func, file, line, msg);
int result = MessageBoxA(NULL, full_msg, NULL, MB_ABORTRETRYIGNORE | MB_ICONERROR);
if (result == IDRETRY)
{
__debugbreak();
}
else if (result != IDIGNORE)
{
// try to save a crash dump before exiting
CrashHandler::WriteDumpForCaller();
TerminateProcess(GetCurrentProcess(), 0xBAADC0DE);
}
#else
fputs(full_msg, stderr);
fputs("\nAborting application.\n", stderr);
fflush(stderr);
AbortWithMessage(full_msg);
#endif
ResumeThreads(handle);
}
// --------------------------------------------------------------------------------------
// BaseException (implementations)
// --------------------------------------------------------------------------------------
BaseException& BaseException::SetBothMsgs(const char* msg_diag)
{
m_message_user = msg_diag ? std::string(msg_diag) : std::string();
return SetDiagMsg(msg_diag);
}
BaseException& BaseException::SetDiagMsg(std::string msg_diag)
{
m_message_diag = std::move(msg_diag);
return *this;
}
BaseException& BaseException::SetUserMsg(std::string msg_user)
{
m_message_user = std::move(msg_user);
return *this;
}
std::string BaseException::FormatDiagnosticMessage() const
{
return m_message_diag;
}
std::string BaseException::FormatDisplayMessage() const
{
return m_message_user.empty() ? m_message_diag : m_message_user;
}
// --------------------------------------------------------------------------------------
// Exception::RuntimeError (implementations)
// --------------------------------------------------------------------------------------
Exception::RuntimeError::RuntimeError(const std::runtime_error& ex, const char* prefix /* = nullptr */)
{
IsSilent = false;
const bool has_prefix = prefix && prefix[0] != 0;
SetDiagMsg(fmt::format("STL Runtime Error{}{}{}: {}",
has_prefix ? " (" : "", prefix ? prefix : "", has_prefix ? ")" : "",
ex.what()));
}
Exception::RuntimeError::RuntimeError(const std::exception& ex, const char* prefix /* = nullptr */)
{
IsSilent = false;
const bool has_prefix = prefix && prefix[0] != 0;
SetDiagMsg(fmt::format("STL Exception{}{}{}: {}",
has_prefix ? " (" : "", prefix ? prefix : "", has_prefix ? ")" : "",
ex.what()));
}
// --------------------------------------------------------------------------------------
// Exception::BadStream (implementations)
// --------------------------------------------------------------------------------------
std::string Exception::BadStream::FormatDiagnosticMessage() const
{
std::string retval;
_formatDiagMsg(retval);
return retval;
}
std::string Exception::BadStream::FormatDisplayMessage() const
{
std::string retval;
_formatUserMsg(retval);
return retval;
}
void Exception::BadStream::_formatDiagMsg(std::string& dest) const
{
fmt::format_to(std::back_inserter(dest), "Path: ");
if (!StreamName.empty())
fmt::format_to(std::back_inserter(dest), "{}", StreamName);
else
dest += "[Unnamed or unknown]";
if (!m_message_diag.empty())
fmt::format_to(std::back_inserter(dest), "\n{}", m_message_diag);
}
void Exception::BadStream::_formatUserMsg(std::string& dest) const
{
fmt::format_to(std::back_inserter(dest), "Path: ");
if (!StreamName.empty())
fmt::format_to(std::back_inserter(dest), "{}", StreamName);
else
dest += "[Unnamed or unknown]";
if (!m_message_user.empty())
fmt::format_to(std::back_inserter(dest), "\n{}", m_message_user);
}
// --------------------------------------------------------------------------------------
// Exception::CannotCreateStream (implementations)
// --------------------------------------------------------------------------------------
std::string Exception::CannotCreateStream::FormatDiagnosticMessage() const
{
std::string retval;
retval = "File could not be created.";
_formatDiagMsg(retval);
return retval;
}
std::string Exception::CannotCreateStream::FormatDisplayMessage() const
{
std::string retval;
retval = "A file could not be created.\n";
_formatUserMsg(retval);
return retval;
}
// --------------------------------------------------------------------------------------
// Exception::FileNotFound (implementations)
// --------------------------------------------------------------------------------------
std::string Exception::FileNotFound::FormatDiagnosticMessage() const
{
std::string retval;
retval = "File not found.\n";
_formatDiagMsg(retval);
return retval;
}
std::string Exception::FileNotFound::FormatDisplayMessage() const
{
std::string retval;
retval = "File not found.\n";
_formatUserMsg(retval);
return retval;
}
// --------------------------------------------------------------------------------------
// Exception::AccessDenied (implementations)
// --------------------------------------------------------------------------------------
std::string Exception::AccessDenied::FormatDiagnosticMessage() const
{
std::string retval;
retval = "Permission denied to file.\n";
_formatDiagMsg(retval);
return retval;
}
std::string Exception::AccessDenied::FormatDisplayMessage() const
{
std::string retval;
retval = "Permission denied while trying to open file, likely due to insufficient user account rights.\n";
_formatUserMsg(retval);
return retval;
}
// --------------------------------------------------------------------------------------
// Exception::EndOfStream (implementations)
// --------------------------------------------------------------------------------------
std::string Exception::EndOfStream::FormatDiagnosticMessage() const
{
std::string retval;
retval = "Unexpected end of file or stream.\n";
_formatDiagMsg(retval);
return retval;
}
std::string Exception::EndOfStream::FormatDisplayMessage() const
{
std::string retval;
retval = "Unexpected end of file or stream encountered. File is probably truncated or corrupted.\n";
_formatUserMsg(retval);
return retval;
}
// --------------------------------------------------------------------------------------
// Exceptions from Errno (POSIX)
// --------------------------------------------------------------------------------------
// Translates an Errno code into an exception.
// Throws an exception based on the given error code (usually taken from ANSI C's errno)
std::unique_ptr<BaseException> Exception::FromErrno(std::string streamname, int errcode)
{
pxAssumeDev(errcode != 0, "Invalid NULL error code? (errno)");
switch (errcode)
{
case EINVAL:
pxFailDev("Invalid argument");
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg("Invalid argument? (likely caused by an unforgivable programmer error!)"));
case EACCES: // Access denied!
return std::unique_ptr<BaseException>(new Exception::AccessDenied(streamname));
case EMFILE: // Too many open files!
return std::unique_ptr<BaseException>(&(new Exception::CannotCreateStream(streamname))->SetDiagMsg("Too many open files")); // File handle allocation failure
case EEXIST:
return std::unique_ptr<BaseException>(&(new Exception::CannotCreateStream(streamname))->SetDiagMsg("File already exists"));
case ENOENT: // File not found!
return std::unique_ptr<BaseException>(new Exception::FileNotFound(streamname));
case EPIPE:
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg("Broken pipe"));
case EBADF:
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg("Bad file number"));
default:
return std::unique_ptr<BaseException>(&(new Exception::BadStream(streamname))->SetDiagMsg(fmt::format("General file/stream error [errno: {}]", errcode)));
}
}

View File

@@ -1,255 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <memory>
#include <stdexcept>
#include "common/Assertions.h"
#include "common/Pcsx2Defs.h"
namespace Exception
{
class BaseException;
std::unique_ptr<BaseException> FromErrno(std::string streamname, int errcode);
// --------------------------------------------------------------------------------------
// BaseException
// --------------------------------------------------------------------------------------
// std::exception sucks, and isn't entirely cross-platform reliable in its implementation,
// so I made a replacement. The internal messages are non-const, which means that a
// catch clause can optionally modify them and then re-throw to a top-level handler.
//
// Note, this class is "abstract" which means you shouldn't use it directly like, ever.
// Use Exception::RuntimeError instead for generic exceptions.
//
// Because exceptions are the (only!) really useful example of multiple inheritance,
// this class has only a trivial constructor, and must be manually initialized using
// InitBaseEx() or by individual member assignments. This is because C++ multiple inheritence
// is, by design, a lot of fail, especially when class initializers are mixed in.
//
// [TODO] : Add an InnerException component, and Clone() facility.
//
class BaseException
{
protected:
std::string m_message_diag; // (untranslated) a "detailed" message of what disastrous thing has occurred!
std::string m_message_user; // (translated) a "detailed" message of what disastrous thing has occurred!
public:
virtual ~BaseException() = default;
const std::string& DiagMsg() const { return m_message_diag; }
const std::string& UserMsg() const { return m_message_user; }
std::string& DiagMsg() { return m_message_diag; }
std::string& UserMsg() { return m_message_user; }
BaseException& SetBothMsgs(const char* msg_diag);
BaseException& SetDiagMsg(std::string msg_diag);
BaseException& SetUserMsg(std::string msg_user);
// Returns a message suitable for diagnostic / logging purposes.
// This message is always in English, and includes a full stack trace.
virtual std::string FormatDiagnosticMessage() const;
// Returns a message suitable for end-user display.
// This message is usually meant for display in a user popup or such.
virtual std::string FormatDisplayMessage() const;
virtual void Rethrow() const = 0;
virtual BaseException* Clone() const = 0;
};
// Some helper macros for defining the standard constructors of internationalized constructors
// Parameters:
// classname - Yeah, the name of this class being defined. :)
//
// defmsg - default message (in english), which will be used for both english and i18n messages.
// The text string will be passed through the translator, so if it's int he gettext database
// it will be optionally translated.
//
// BUGZ?? I'd rather use 'classname' on the Clone() prototype, but for some reason it generates
// ambiguity errors on virtual inheritance (it really shouldn't!). So I have to force it to the
// BaseException base class. Not sure if this is Stupid Standard Tricks or Stupid MSVC Tricks. --air
//
// (update: web searches indicate it's MSVC specific -- happens in 2008, not sure about 2010).
//
#define DEFINE_EXCEPTION_COPYTORS(classname, parent) \
private: \
typedef parent _parent; \
\
public: \
virtual ~classname() = default; \
\
virtual void Rethrow() const override \
{ \
throw *this; \
} \
\
virtual classname* Clone() const override \
{ \
return new classname(*this); \
}
#define DEFINE_EXCEPTION_MESSAGES(classname) \
public: \
classname& SetBothMsgs(const char* msg_diag) \
{ \
BaseException::SetBothMsgs(msg_diag); \
return *this; \
} \
\
classname& SetDiagMsg(std::string msg_diag) \
{ \
m_message_diag = msg_diag; \
return *this; \
} \
\
classname& SetUserMsg(std::string msg_user) \
{ \
m_message_user = std::move(msg_user); \
return *this; \
}
#define DEFINE_RUNTIME_EXCEPTION(classname, parent, message) \
DEFINE_EXCEPTION_COPYTORS(classname, parent) \
classname() \
{ \
SetDiagMsg(message); \
} \
DEFINE_EXCEPTION_MESSAGES(classname)
// ---------------------------------------------------------------------------------------
// RuntimeError - Generalized Exceptions with Recoverable Traits!
// ---------------------------------------------------------------------------------------
class RuntimeError : public BaseException
{
DEFINE_EXCEPTION_COPYTORS(RuntimeError, BaseException)
DEFINE_EXCEPTION_MESSAGES(RuntimeError)
public:
bool IsSilent;
RuntimeError() { IsSilent = false; }
RuntimeError(const std::runtime_error& ex, const char* prefix = nullptr);
RuntimeError(const std::exception& ex, const char* prefix = nullptr);
};
// ---------------------------------------------------------------------------------------
// Streaming (file) Exceptions:
// Stream / BadStream / CannotCreateStream / FileNotFound / AccessDenied / EndOfStream
// ---------------------------------------------------------------------------------------
#define DEFINE_STREAM_EXCEPTION(classname, parent) \
DEFINE_RUNTIME_EXCEPTION(classname, parent, "") \
classname(std::string filename) \
{ \
StreamName = filename; \
} \
virtual classname& SetStreamName(std::string name) override \
{ \
StreamName = std::move(name); \
return *this; \
} \
\
virtual classname& SetStreamName(const char* name) override \
{ \
StreamName = name; \
return *this; \
}
// A generic base error class for bad streams -- corrupted data, sudden closures, loss of
// connection, or anything else that would indicate a failure to open a stream or read the
// data after the stream was successfully opened.
//
class BadStream : public RuntimeError
{
DEFINE_RUNTIME_EXCEPTION(BadStream, RuntimeError, "")
public:
BadStream(std::string filename)
: StreamName(std::move(filename))
{
}
virtual BadStream& SetStreamName(std::string name)
{
StreamName = std::move(name);
return *this;
}
virtual BadStream& SetStreamName(const char* name)
{
StreamName = name;
return *this;
}
std::string StreamName; // name of the stream (if applicable)
virtual std::string FormatDiagnosticMessage() const override;
virtual std::string FormatDisplayMessage() const override;
protected:
void _formatDiagMsg(std::string& dest) const;
void _formatUserMsg(std::string& dest) const;
};
// A generic exception for odd-ball stream creation errors.
//
class CannotCreateStream : public BadStream
{
DEFINE_STREAM_EXCEPTION(CannotCreateStream, BadStream)
virtual std::string FormatDiagnosticMessage() const override;
virtual std::string FormatDisplayMessage() const override;
};
// Exception thrown when an attempt to open a non-existent file is made.
// (this exception can also mean file permissions are invalid)
//
class FileNotFound : public CannotCreateStream
{
public:
DEFINE_STREAM_EXCEPTION(FileNotFound, CannotCreateStream)
virtual std::string FormatDiagnosticMessage() const override;
virtual std::string FormatDisplayMessage() const override;
};
class AccessDenied : public CannotCreateStream
{
public:
DEFINE_STREAM_EXCEPTION(AccessDenied, CannotCreateStream)
virtual std::string FormatDiagnosticMessage() const override;
virtual std::string FormatDisplayMessage() const override;
};
// EndOfStream can be used either as an error, or used just as a shortcut for manual
// feof checks.
//
class EndOfStream : public BadStream
{
public:
DEFINE_STREAM_EXCEPTION(EndOfStream, BadStream)
virtual std::string FormatDiagnosticMessage() const override;
virtual std::string FormatDisplayMessage() const override;
};
} // namespace Exception
using Exception::BaseException;

View File

@@ -14,12 +14,14 @@
*/
#include "FileSystem.h"
#include "Error.h"
#include "Path.h"
#include "Assertions.h"
#include "Console.h"
#include "StringUtil.h"
#include "Path.h"
#include <algorithm>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <limits>
@@ -188,6 +190,27 @@ void Path::SanitizeFileName(std::string* str, bool strip_slashes /* = true */)
#endif
}
bool Path::IsValidFileName(const std::string_view& str, bool allow_slashes)
{
const size_t len = str.length();
size_t pos = 0;
while (pos < len)
{
char32_t ch;
pos += StringUtil::DecodeUTF8(str.data() + pos, pos - len, &ch);
if (!FileSystemCharacterIsSane(ch, !allow_slashes))
return false;
}
#ifdef _WIN32
// Windows: Can't end filename with a period.
if (len > 0 && str.back() == '.')
return false;
#endif
return true;
}
bool Path::IsAbsolute(const std::string_view& path)
{
#ifdef _WIN32
@@ -596,7 +619,7 @@ std::string Path::Combine(const std::string_view& base, const std::string_view&
return ret;
}
std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode)
std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode, Error* error)
{
#ifdef _WIN32
const std::wstring wfilename(StringUtil::UTF8StringToWideString(filename));
@@ -604,23 +627,34 @@ std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode)
if (!wfilename.empty() && !wmode.empty())
{
std::FILE* fp;
if (_wfopen_s(&fp, wfilename.c_str(), wmode.c_str()) != 0)
const errno_t err = _wfopen_s(&fp, wfilename.c_str(), wmode.c_str());
if (err != 0)
{
Error::SetErrno(error, err);
return nullptr;
}
return fp;
}
std::FILE* fp;
if (fopen_s(&fp, filename, mode) != 0)
const errno_t err = fopen_s(&fp, filename, mode);
if (err != 0)
{
Error::SetErrno(error, err);
return nullptr;
}
return fp;
#else
return std::fopen(filename, mode);
std::FILE* fp = std::fopen(filename, mode);
if (!fp)
Error::SetErrno(error, errno);
return fp;
#endif
}
int FileSystem::OpenFDFile(const char* filename, int flags, int mode)
int FileSystem::OpenFDFile(const char* filename, int flags, int mode, Error* error)
{
#ifdef _WIN32
const std::wstring wfilename(StringUtil::UTF8StringToWideString(filename));
@@ -629,16 +663,19 @@ int FileSystem::OpenFDFile(const char* filename, int flags, int mode)
return -1;
#else
return open(filename, flags, mode);
const int fd = open(filename, flags, mode);
if (fd < 0)
Error::SetErrno(error, errno);
return fd;
#endif
}
FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFile(const char* filename, const char* mode)
FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFile(const char* filename, const char* mode, Error* error)
{
return ManagedCFilePtr(OpenCFile(filename, mode), [](std::FILE* fp) { std::fclose(fp); });
return ManagedCFilePtr(OpenCFile(filename, mode, error), [](std::FILE* fp) { std::fclose(fp); });
}
std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode)
std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error)
{
#ifdef _WIN32
const std::wstring wfilename(StringUtil::UTF8StringToWideString(filename));
@@ -668,15 +705,19 @@ std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, F
if (fp)
return fp;
Error::SetErrno(error, errno);
return nullptr;
#else
return std::fopen(filename, mode);
std::FILE* fp = std::fopen(filename, mode);
if (!fp)
Error::SetErrno(error, errno);
return fp;
#endif
}
FileSystem::ManagedCFilePtr FileSystem::OpenManagedSharedCFile(const char* filename, const char* mode, FileShareMode share_mode)
FileSystem::ManagedCFilePtr FileSystem::OpenManagedSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error)
{
return ManagedCFilePtr(OpenSharedCFile(filename, mode, share_mode), [](std::FILE* fp) { std::fclose(fp); });
return ManagedCFilePtr(OpenSharedCFile(filename, mode, share_mode, error), [](std::FILE* fp) { std::fclose(fp); });
}
int FileSystem::FSeek64(std::FILE* fp, s64 offset, int whence)

View File

@@ -23,6 +23,8 @@
#include <vector>
#include <sys/stat.h>
class Error;
#ifdef _WIN32
#define FS_OSPATH_SEPARATOR_CHARACTER '\\'
#define FS_OSPATH_SEPARATOR_STR "\\"
@@ -102,13 +104,13 @@ namespace FileSystem
/// open files
using ManagedCFilePtr = std::unique_ptr<std::FILE, void (*)(std::FILE*)>;
ManagedCFilePtr OpenManagedCFile(const char* filename, const char* mode);
std::FILE* OpenCFile(const char* filename, const char* mode);
ManagedCFilePtr OpenManagedCFile(const char* filename, const char* mode, Error* error = nullptr);
std::FILE* OpenCFile(const char* filename, const char* mode, Error* error = nullptr);
int FSeek64(std::FILE* fp, s64 offset, int whence);
s64 FTell64(std::FILE* fp);
s64 FSize64(std::FILE* fp);
int OpenFDFile(const char* filename, int flags, int mode);
int OpenFDFile(const char* filename, int flags, int mode, Error* error = nullptr);
/// Sharing modes for OpenSharedCFile().
enum class FileShareMode
@@ -121,8 +123,8 @@ namespace FileSystem
/// Opens a file in shareable mode (where other processes can access it concurrently).
/// Only has an effect on Windows systems.
ManagedCFilePtr OpenManagedSharedCFile(const char* filename, const char* mode, FileShareMode share_mode);
std::FILE* OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode);
ManagedCFilePtr OpenManagedSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error = nullptr);
std::FILE* OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error = nullptr);
std::optional<std::vector<u8>> ReadBinaryFile(const char* filename);
std::optional<std::vector<u8>> ReadBinaryFile(std::FILE* fp);

View File

@@ -28,7 +28,6 @@
#include "common/Align.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/Exceptions.h"
#include "common/General.h"
// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean

View File

@@ -41,6 +41,9 @@ namespace Path
std::string SanitizeFileName(const std::string_view& str, bool strip_slashes = true);
void SanitizeFileName(std::string* str, bool strip_slashes = true);
/// Returns true if the specified filename is valid on this operating system.
bool IsValidFileName(const std::string_view& str, bool allow_slashes = false);
/// Returns true if the specified path is an absolute path (C:\Path on Windows or /path on Unix).
bool IsAbsolute(const std::string_view& path);

View File

@@ -1,99 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
// Microsoft Windows only macro, useful for freeing out COM objects:
#define safe_release(ptr) \
((void)((((ptr) != NULL) && ((ptr)->Release(), !!0)), (ptr) = NULL))
// --------------------------------------------------------------------------------------
// SafeArray
// --------------------------------------------------------------------------------------
// Handy little class for allocating a resizable memory block, complete with exception
// error handling and automatic cleanup. A lightweight alternative to std::vector.
//
template <typename T>
class SafeArray
{
DeclareNoncopyableObject(SafeArray);
public:
static const int DefaultChunkSize = 0x1000 * sizeof(T);
public:
std::string Name; // user-assigned block name
int ChunkSize;
protected:
T* m_ptr;
int m_size; // size of the allocation of memory
protected:
SafeArray(std::string name, T* allocated_mem, int initSize);
virtual T* _virtual_realloc(int newsize);
// A safe array index fetcher. Asserts if the index is out of bounds (dev and debug
// builds only -- no bounds checking is done in release builds).
T* _getPtr(uint i) const;
public:
virtual ~SafeArray();
explicit SafeArray(std::string name = "Unnamed");
explicit SafeArray(int initialSize, std::string name = "Unnamed");
void Dispose();
void ExactAlloc(int newsize);
void MakeRoomFor(int newsize)
{
if (newsize > m_size)
ExactAlloc(newsize);
}
bool IsDisposed() const { return (m_ptr == NULL); }
// Returns the size of the memory allocation, as according to the array type.
int GetLength() const { return m_size; }
// Returns the size of the memory allocation in bytes.
int GetSizeInBytes() const { return m_size * sizeof(T); }
// Extends the containment area of the array. Extensions are performed
// in chunks.
void GrowBy(int items)
{
MakeRoomFor(m_size + ChunkSize + items + 1);
}
// Gets a pointer to the requested allocation index.
// DevBuilds : Generates assertion if the index is invalid.
T* GetPtr(uint idx = 0) { return _getPtr(idx); }
const T* GetPtr(uint idx = 0) const { return _getPtr(idx); }
// Gets a pointer to the element directly after the last element in the array.
// This is equivalent to doing GetPtr(GetLength()), except that this call *avoids*
// the out-of-bounds assertion check that typically occurs when you do that. :)
T* GetPtrEnd() { return &m_ptr[m_size]; }
const T* GetPtrEnd() const { return &m_ptr[m_size]; }
// Gets an element of this memory allocation much as if it were an array.
// DevBuilds : Generates assertion if the index is invalid.
T& operator[](int idx) { return *_getPtr((uint)idx); }
const T& operator[](int idx) const { return *_getPtr((uint)idx); }
virtual SafeArray<T>* Clone() const;
};

View File

@@ -1,121 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Assertions.h"
#include "common/SafeArray.h"
// Internal constructor for use by derived classes. This allows a derived class to
// use its own memory allocation (with an aligned memory, for example).
// Throws:
// Exception::OutOfMemory if the allocated_mem pointer is NULL.
template <typename T>
SafeArray<T>::SafeArray(std::string name, T* allocated_mem, int initSize)
: Name(std::move(name))
{
ChunkSize = DefaultChunkSize;
m_ptr = allocated_mem;
m_size = initSize;
if (m_ptr == NULL)
pxFailRel("SafeArray memory assignment failed");
}
template <typename T>
T* SafeArray<T>::_virtual_realloc(int newsize)
{
T* retval = (T*)((m_ptr == NULL) ?
malloc(newsize * sizeof(T)) :
realloc(m_ptr, newsize * sizeof(T)));
if (IsDebugBuild && (retval != NULL))
{
// Zero everything out to 0xbaadf00d, so that its obviously uncleared
// to a debuggee
u32* fill = (u32*)&retval[m_size];
const u32* end = (u32*)((((uptr)&retval[newsize - 1]) - 3) & ~0x3);
for (; fill < end; ++fill)
*fill = 0xbaadf00d;
}
return retval;
}
template <typename T>
SafeArray<T>::~SafeArray()
{
safe_free(m_ptr);
}
template <typename T>
SafeArray<T>::SafeArray(std::string name)
: Name(std::move(name))
{
ChunkSize = DefaultChunkSize;
m_ptr = NULL;
m_size = 0;
}
template <typename T>
SafeArray<T>::SafeArray(int initialSize, std::string name)
: Name(std::move(name))
{
ChunkSize = DefaultChunkSize;
m_ptr = (initialSize == 0) ? NULL : (T*)malloc(initialSize * sizeof(T));
m_size = initialSize;
if ((initialSize != 0) && (m_ptr == NULL))
pxFailRel("SafeArray memory allocation failed");
}
// Clears the contents of the array to zero, and frees all memory allocations.
template <typename T>
void SafeArray<T>::Dispose()
{
m_size = 0;
safe_free(m_ptr);
}
template <typename T>
T* SafeArray<T>::_getPtr(uint i) const
{
pxAssumeDev(i < static_cast<uint>(m_size), "Array index in bounds");
return &m_ptr[i];
}
// reallocates the array to the explicit size. Can be used to shrink or grow an
// array, and bypasses the internal threshold growth indicators.
template <typename T>
void SafeArray<T>::ExactAlloc(int newsize)
{
if (newsize == m_size)
return;
m_ptr = _virtual_realloc(newsize);
if (m_ptr == NULL)
pxFailRel("SafeArray exact alloc failed");
m_size = newsize;
}
template <typename T>
SafeArray<T>* SafeArray<T>::Clone() const
{
SafeArray<T>* retval = new SafeArray<T>(m_size);
memcpy(retval->GetPtr(), m_ptr, sizeof(T) * m_size);
return retval;
}

View File

@@ -19,7 +19,6 @@
#include "common/RedtapeWindows.h"
#include "common/Console.h"
#include "common/General.h"
#include "common/Exceptions.h"
#include "common/StringUtil.h"
#include "common/AlignedMalloc.h"
#include "common/Assertions.h"

View File

@@ -17,7 +17,6 @@
#include "common/Pcsx2Defs.h"
#include "common/RedtapeWindows.h"
#include "common/Exceptions.h"
#include "common/StringUtil.h"
#include "common/Threading.h"
#include "common/General.h"

View File

@@ -46,10 +46,11 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AlignedMalloc.cpp" />
<ClCompile Include="Assertions.cpp" />
<ClCompile Include="Console.cpp" />
<ClCompile Include="CrashHandler.cpp" />
<ClCompile Include="DynamicLibrary.cpp" />
<ClCompile Include="Exceptions.cpp" />
<ClCompile Include="Error.cpp" />
<ClCompile Include="FastJmp.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
@@ -109,6 +110,7 @@
<ClInclude Include="DynamicLibrary.h" />
<ClInclude Include="Easing.h" />
<ClInclude Include="boost_spsc_queue.hpp" />
<ClInclude Include="Error.h" />
<ClInclude Include="FastJmp.h" />
<ClInclude Include="FileSystem.h" />
<ClInclude Include="HashCombine.h" />
@@ -131,7 +133,6 @@
<ClInclude Include="SettingsWrapper.h" />
<ClInclude Include="Assertions.h" />
<ClInclude Include="Console.h" />
<ClInclude Include="Exceptions.h" />
<ClInclude Include="General.h" />
<ClInclude Include="MathUtils.h" />
<ClInclude Include="Path.h" />

View File

@@ -13,9 +13,6 @@
<ClCompile Include="emitter\cpudetect.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Exceptions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="emitter\fpu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -139,6 +136,12 @@
<ClCompile Include="General.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Error.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Assertions.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlignedMalloc.h">
@@ -159,9 +162,6 @@
<ClInclude Include="emitter\implement\dwshift.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Exceptions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="General.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -351,6 +351,9 @@
<ClInclude Include="WrappedMemCopy.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Error.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Source Files">
@@ -365,4 +368,4 @@
<Filter>Source Files</Filter>
</MASM>
</ItemGroup>
</Project>
</Project>

View File

@@ -19,19 +19,19 @@
<ClCompile>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(SolutionDir);$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__WIN32__;WIN32;_WINDOWS;WIN32_LEAN_AND_MEAN;NOMINMAX;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;WINVER=0x0A00;_WIN32_WINNT=0x0A00;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__WIN32__;WIN32;_WINDOWS;WIN32_LEAN_AND_MEAN;NOMINMAX;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;_HAS_EXCEPTIONS=0;WINVER=0x0A00;_WIN32_WINNT=0x0A00;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Debug))">PCSX2_DEBUG;PCSX2_DEVBUILD;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Devel))">PCSX2_DEVEL;PCSX2_DEVBUILD;NDEBUG;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Release))">NDEBUG;_SECURE_SCL_=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<ExceptionHandling>false</ExceptionHandling>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4063;4100;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ExceptionHandling>Async</ExceptionHandling>
<MinimalRebuild>false</MinimalRebuild>
<ConformanceMode>true</ConformanceMode>
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>

View File

@@ -28,7 +28,6 @@
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/Exceptions.h"
#include "common/FileSystem.h"
#include "common/MemorySettingsInterface.h"
#include "common/Path.h"
@@ -335,6 +334,14 @@ void Host::SetFullscreen(bool enabled)
{
}
void Host::OnCaptureStarted(const std::string& filename)
{
}
void Host::OnCaptureStopped()
{
}
void Host::RequestExit(bool allow_confirm)
{
}

View File

@@ -68,9 +68,6 @@ target_sources(pcsx2-qt PRIVATE
Settings/ControllerSettingsDialog.h
Settings/ControllerSettingsDialog.ui
Settings/ControllerSettingWidgetBinder.h
Settings/CreateMemoryCardDialog.cpp
Settings/CreateMemoryCardDialog.h
Settings/CreateMemoryCardDialog.ui
Settings/DebugSettingsWidget.cpp
Settings/DebugSettingsWidget.h
Settings/DebugSettingsWidget.ui
@@ -114,6 +111,9 @@ target_sources(pcsx2-qt PRIVATE
Settings/MemoryCardConvertDialog.ui
Settings/MemoryCardConvertWorker.cpp
Settings/MemoryCardConvertWorker.h
Settings/MemoryCardCreateDialog.cpp
Settings/MemoryCardCreateDialog.h
Settings/MemoryCardCreateDialog.ui
Settings/MemoryCardSettingsWidget.cpp
Settings/MemoryCardSettingsWidget.h
Settings/MemoryCardSettingsWidget.ui
@@ -177,9 +177,7 @@ if(USE_ACHIEVEMENTS)
)
endif()
set(TS_FILES
Translations/pcsx2-qt_en.ts
)
file(GLOB TS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Translations/*.ts)
target_precompile_headers(pcsx2-qt PRIVATE PrecompiledHeader.h)
@@ -199,6 +197,9 @@ target_link_libraries(pcsx2-qt PRIVATE
Qt6::Network
)
# Our Qt builds may have exceptions on, so force them off.
target_compile_definitions(pcsx2-qt PRIVATE QT_NO_EXCEPTIONS)
if(WIN32)
set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_SOURCE_DIR}/bin/translations")
qt_add_lrelease(pcsx2-qt TS_FILES ${TS_FILES})

View File

@@ -183,7 +183,6 @@ void MainWindow::setupAdditionalUi()
{
const bool show_advanced_settings = QtHost::ShouldShowAdvancedSettings();
setWindowIcon(QIcon(QStringLiteral("%1/icons/AppIconLarge.png").arg(QtHost::GetResourcesBasePath())));
makeIconsMasks(menuBar());
m_ui.menuDebug->menuAction()->setVisible(show_advanced_settings);
@@ -294,7 +293,6 @@ void MainWindow::connectSignals()
connect(m_ui.actionStartFile, &QAction::triggered, this, &MainWindow::onStartFileActionTriggered);
connect(m_ui.actionStartDisc, &QAction::triggered, this, &MainWindow::onStartDiscActionTriggered);
connect(m_ui.actionStartBios, &QAction::triggered, this, &MainWindow::onStartBIOSActionTriggered);
connect(m_ui.actionChangeDisc, &QAction::triggered, [this] { m_ui.menuChangeDisc->exec(QCursor::pos()); });
connect(m_ui.actionChangeDiscFromFile, &QAction::triggered, this, &MainWindow::onChangeDiscFromFileActionTriggered);
connect(m_ui.actionChangeDiscFromDevice, &QAction::triggered, this, &MainWindow::onChangeDiscFromDeviceActionTriggered);
connect(m_ui.actionChangeDiscFromGameList, &QAction::triggered, this, &MainWindow::onChangeDiscFromGameListActionTriggered);
@@ -303,14 +301,22 @@ void MainWindow::connectSignals()
connect(m_ui.menuChangeDisc, &QMenu::aboutToHide, this, &MainWindow::onChangeDiscMenuAboutToHide);
connect(m_ui.actionPowerOff, &QAction::triggered, this, [this]() { requestShutdown(true, true, EmuConfig.SaveStateOnShutdown); });
connect(m_ui.actionPowerOffWithoutSaving, &QAction::triggered, this, [this]() { requestShutdown(false, false, false); });
connect(m_ui.actionLoadState, &QAction::triggered, this, [this]() { m_ui.menuLoadState->exec(QCursor::pos()); });
connect(m_ui.actionSaveState, &QAction::triggered, this, [this]() { m_ui.menuSaveState->exec(QCursor::pos()); });
connect(m_ui.actionToolbarStartFile, &QAction::triggered, this, &MainWindow::onStartFileActionTriggered);
connect(m_ui.actionToolbarStartDisc, &QAction::triggered, this, &MainWindow::onStartDiscActionTriggered);
connect(m_ui.actionToolbarStartBios, &QAction::triggered, this, &MainWindow::onStartBIOSActionTriggered);
connect(m_ui.actionToolbarChangeDisc, &QAction::triggered, [this] { m_ui.menuChangeDisc->exec(QCursor::pos()); });
connect(m_ui.actionToolbarPowerOff, &QAction::triggered, this, [this]() { requestShutdown(true, true, EmuConfig.SaveStateOnShutdown); });
connect(m_ui.actionToolbarLoadState, &QAction::triggered, this, [this]() { m_ui.menuLoadState->exec(QCursor::pos()); });
connect(m_ui.actionToolbarSaveState, &QAction::triggered, this, [this]() { m_ui.menuSaveState->exec(QCursor::pos()); });
connect(m_ui.actionToolbarSettings, &QAction::triggered, this, &MainWindow::onSettingsTriggeredFromToolbar);
connect(m_ui.actionToolbarControllerSettings, &QAction::triggered,
[this]() { doControllerSettings(ControllerSettingsDialog::Category::GlobalSettings); });
connect(m_ui.actionToolbarScreenshot, &QAction::triggered, this, &MainWindow::onScreenshotActionTriggered);
connect(m_ui.actionExit, &QAction::triggered, this, &MainWindow::close);
connect(m_ui.actionScreenshot, &QAction::triggered, this, &MainWindow::onScreenshotActionTriggered);
connect(m_ui.menuLoadState, &QMenu::aboutToShow, this, &MainWindow::onLoadStateMenuAboutToShow);
connect(m_ui.menuSaveState, &QMenu::aboutToShow, this, &MainWindow::onSaveStateMenuAboutToShow);
connect(m_ui.actionSettings, &QAction::triggered, [this]() { doSettings(); });
connect(m_ui.actionSettings2, &QAction::triggered, this, &MainWindow::onSettingsTriggeredFromToolbar);
connect(m_ui.actionInterfaceSettings, &QAction::triggered, [this]() { doSettings("Interface"); });
connect(m_ui.actionGameListSettings, &QAction::triggered, [this]() { doSettings("Game List"); });
connect(m_ui.actionEmulationSettings, &QAction::triggered, [this]() { doSettings("Emulation"); });
@@ -403,7 +409,7 @@ void MainWindow::connectSignals()
void MainWindow::connectVMThreadSignals(EmuThread* thread)
{
connect(m_ui.actionStartFullscreenUI, &QAction::triggered, thread, &EmuThread::startFullscreenUI);
connect(m_ui.actionStartFullscreenUI2, &QAction::triggered, thread, &EmuThread::startFullscreenUI);
connect(m_ui.actionToolbarStartFullscreenUI, &QAction::triggered, thread, &EmuThread::startFullscreenUI);
connect(thread, &EmuThread::messageConfirmed, this, &MainWindow::confirmMessage, Qt::BlockingQueuedConnection);
connect(thread, &EmuThread::onAcquireRenderWindowRequested, this, &MainWindow::acquireRenderWindow, Qt::BlockingQueuedConnection);
connect(thread, &EmuThread::onReleaseRenderWindowRequested, this, &MainWindow::releaseRenderWindow, Qt::BlockingQueuedConnection);
@@ -415,10 +421,15 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
connect(thread, &EmuThread::onVMResumed, this, &MainWindow::onVMResumed);
connect(thread, &EmuThread::onVMStopped, this, &MainWindow::onVMStopped);
connect(thread, &EmuThread::onGameChanged, this, &MainWindow::onGameChanged);
connect(thread, &EmuThread::onCaptureStarted, this, &MainWindow::onCaptureStarted);
connect(thread, &EmuThread::onCaptureStopped, this, &MainWindow::onCaptureStopped);
connect(m_ui.actionReset, &QAction::triggered, thread, &EmuThread::resetVM);
connect(m_ui.actionPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
connect(m_ui.actionFullscreen, &QAction::triggered, thread, &EmuThread::toggleFullscreen);
connect(m_ui.actionToolbarReset, &QAction::triggered, thread, &EmuThread::resetVM);
connect(m_ui.actionToolbarPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
connect(m_ui.actionToolbarFullscreen, &QAction::triggered, thread, &EmuThread::toggleFullscreen);
connect(m_ui.actionToggleSoftwareRendering, &QAction::triggered, thread, &EmuThread::toggleSoftwareRendering);
connect(m_ui.actionDebugger, &QAction::triggered, this, &MainWindow::openDebugger);
connect(m_ui.actionReloadPatches, &QAction::triggered, thread, &EmuThread::reloadPatches);
@@ -577,6 +588,10 @@ void MainWindow::onToolsVideoCaptureToggled(bool checked)
if (!s_vm_valid)
return;
// Reset the checked state, we'll get updated by the GS thread.
QSignalBlocker sb(m_ui.actionToolsVideoCapture);
m_ui.actionToolsVideoCapture->setChecked(!checked);
if (!checked)
{
g_emu_thread->endCapture();
@@ -590,15 +605,29 @@ void MainWindow::onToolsVideoCaptureToggled(bool checked)
QString path(QStringLiteral("%1.%2").arg(QString::fromStdString(GSGetBaseVideoFilename())).arg(container));
path = QFileDialog::getSaveFileName(this, tr("Video Capture"), path, filter);
if (path.isEmpty())
{
QSignalBlocker sb(m_ui.actionToolsVideoCapture);
m_ui.actionToolsVideoCapture->setChecked(false);
return;
}
g_emu_thread->beginCapture(path);
}
void MainWindow::onCaptureStarted(const QString& filename)
{
if (!s_vm_valid)
return;
QSignalBlocker sb(m_ui.actionToolsVideoCapture);
m_ui.actionToolsVideoCapture->setChecked(true);
}
void MainWindow::onCaptureStopped()
{
if (!s_vm_valid)
return;
QSignalBlocker sb(m_ui.actionToolsVideoCapture);
m_ui.actionToolsVideoCapture->setChecked(false);
}
void MainWindow::onSettingsTriggeredFromToolbar()
{
if (s_vm_valid)
@@ -673,18 +702,25 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool stoppi
m_ui.actionStartFile->setDisabled(starting_or_running || stopping);
m_ui.actionStartDisc->setDisabled(starting_or_running || stopping);
m_ui.actionStartBios->setDisabled(starting_or_running || stopping);
m_ui.actionToolbarStartFile->setDisabled(starting_or_running || stopping);
m_ui.actionToolbarStartDisc->setDisabled(starting_or_running || stopping);
m_ui.actionToolbarStartBios->setDisabled(starting_or_running || stopping);
m_ui.actionPowerOff->setEnabled(running);
m_ui.actionPowerOffWithoutSaving->setEnabled(running);
m_ui.actionReset->setEnabled(running);
m_ui.actionPause->setEnabled(running);
m_ui.actionChangeDisc->setEnabled(running);
m_ui.actionScreenshot->setEnabled(running);
m_ui.menuChangeDisc->setEnabled(running);
m_ui.actionSaveState->setEnabled(running);
m_ui.menuSaveState->setEnabled(running);
m_ui.actionToolbarPowerOff->setEnabled(running);
m_ui.actionToolbarReset->setEnabled(running);
m_ui.actionToolbarPause->setEnabled(running);
m_ui.actionToolbarScreenshot->setEnabled(running);
m_ui.actionToolbarChangeDisc->setEnabled(running);
m_ui.actionToolbarSaveState->setEnabled(running);
m_ui.actionViewGameProperties->setEnabled(running);
m_ui.actionToolsVideoCapture->setEnabled(running);
@@ -698,8 +734,15 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool stoppi
if (!starting && !running)
{
QSignalBlocker sb(m_ui.actionPause);
m_ui.actionPause->setChecked(false);
{
QSignalBlocker sb(m_ui.actionPause);
m_ui.actionPause->setChecked(false);
}
{
QSignalBlocker sb(m_ui.actionToolbarPause);
m_ui.actionToolbarPause->setChecked(false);
}
}
// scanning needs to be disabled while running
@@ -713,11 +756,17 @@ void MainWindow::updateDisplayRelatedActions(bool has_surface, bool render_to_ma
m_ui.actionViewSystemDisplay->setEnabled((has_surface && render_to_main) || (!has_surface && MTGS::IsOpen()));
m_ui.menuWindowSize->setEnabled(has_surface && !fullscreen);
m_ui.actionFullscreen->setEnabled(has_surface);
m_ui.actionToolbarFullscreen->setEnabled(has_surface);
{
QSignalBlocker blocker(m_ui.actionFullscreen);
m_ui.actionFullscreen->setChecked(fullscreen);
}
{
QSignalBlocker blocker(m_ui.actionToolbarFullscreen);
m_ui.actionToolbarFullscreen->setChecked(fullscreen);
}
}
void MainWindow::updateStatusBarWidgetVisibility()
@@ -1424,6 +1473,7 @@ void MainWindow::onInputRecNewActionTriggered()
m_ui.actionInputRecNew->setEnabled(false);
m_ui.actionInputRecStop->setEnabled(true);
m_ui.actionReset->setEnabled(!g_InputRecording.isTypeSavestate());
m_ui.actionToolbarReset->setEnabled(!g_InputRecording.isTypeSavestate());
});
}
});
@@ -1476,6 +1526,7 @@ void MainWindow::onInputRecPlayActionTriggered()
m_ui.actionInputRecNew->setEnabled(false);
m_ui.actionInputRecStop->setEnabled(true);
m_ui.actionReset->setEnabled(!g_InputRecording.isTypeSavestate());
m_ui.actionToolbarReset->setEnabled(!g_InputRecording.isTypeSavestate());
});
}
});
@@ -1492,6 +1543,7 @@ void MainWindow::onInputRecStopActionTriggered()
m_ui.actionInputRecNew->setEnabled(true);
m_ui.actionInputRecStop->setEnabled(false);
m_ui.actionReset->setEnabled(true);
m_ui.actionToolbarReset->setEnabled(true);
});
});
}
@@ -1555,6 +1607,10 @@ void MainWindow::onVMPaused()
QSignalBlocker sb(m_ui.actionPause);
m_ui.actionPause->setChecked(true);
}
{
QSignalBlocker sb(m_ui.actionToolbarPause);
m_ui.actionToolbarPause->setChecked(true);
}
s_vm_paused = true;
updateWindowTitle();
@@ -1572,6 +1628,10 @@ void MainWindow::onVMResumed()
QSignalBlocker sb(m_ui.actionPause);
m_ui.actionPause->setChecked(false);
}
{
QSignalBlocker sb(m_ui.actionToolbarPause);
m_ui.actionToolbarPause->setChecked(false);
}
s_vm_paused = false;
m_was_disc_change_request = false;
@@ -1833,7 +1893,7 @@ std::optional<WindowInfo> MainWindow::acquireRenderWindow(bool recreate_window,
updateWindowState();
m_ui.actionStartFullscreenUI->setEnabled(false);
m_ui.actionStartFullscreenUI2->setEnabled(false);
m_ui.actionToolbarStartFullscreenUI->setEnabled(false);
updateDisplayWidgetCursor();
m_display_widget->setFocus();
@@ -1953,7 +2013,7 @@ void MainWindow::releaseRenderWindow()
m_ui.actionViewSystemDisplay->setEnabled(false);
m_ui.actionFullscreen->setEnabled(false);
m_ui.actionStartFullscreenUI->setEnabled(true);
m_ui.actionStartFullscreenUI2->setEnabled(true);
m_ui.actionToolbarStartFullscreenUI->setEnabled(true);
}
void MainWindow::destroyDisplayWidget(bool show_game_list)
@@ -2433,9 +2493,9 @@ void MainWindow::updateSaveStateMenusEnableState(bool enable)
const bool load_enabled = enable;
const bool save_enabled = enable && s_vm_valid;
m_ui.menuLoadState->setEnabled(load_enabled);
m_ui.actionLoadState->setEnabled(load_enabled);
m_ui.actionToolbarLoadState->setEnabled(load_enabled);
m_ui.menuSaveState->setEnabled(save_enabled);
m_ui.actionSaveState->setEnabled(save_enabled);
m_ui.actionToolbarSaveState->setEnabled(save_enabled);
}
void MainWindow::doStartFile(std::optional<CDVD_SourceType> source, const QString& path)

View File

@@ -183,6 +183,9 @@ private Q_SLOTS:
void onGameChanged(const QString& title, const QString& elf_override, const QString& disc_path,
const QString& serial, quint32 disc_crc, quint32 crc);
void onCaptureStarted(const QString& filename);
void onCaptureStopped();
protected:
void showEvent(QShowEvent* event) override;
void closeEvent(QCloseEvent* event) override;

View File

@@ -16,6 +16,11 @@
<property name="windowTitle">
<string>PCSX2</string>
</property>
<property name="windowIcon">
<iconset>
<normalon>:/icons/AppIcon64.png</normalon>
</iconset>
</property>
<widget class="QStackedWidget" name="mainContainer"/>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
@@ -126,10 +131,10 @@
<property name="title">
<string>Switch Renderer</string>
</property>
<property name="icon">
<iconset theme="brush-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="icon">
<iconset theme="brush-line">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
<addaction name="menuDebugSwitchRenderer"/>
<addaction name="separator"/>
@@ -234,24 +239,24 @@
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionStartFile"/>
<addaction name="actionStartDisc"/>
<addaction name="actionStartBios"/>
<addaction name="actionStartFullscreenUI2"/>
<addaction name="actionToolbarStartFile"/>
<addaction name="actionToolbarStartDisc"/>
<addaction name="actionToolbarStartBios"/>
<addaction name="actionToolbarStartFullscreenUI"/>
<addaction name="separator"/>
<addaction name="actionPowerOff"/>
<addaction name="actionReset"/>
<addaction name="actionPause"/>
<addaction name="actionChangeDisc"/>
<addaction name="actionScreenshot"/>
<addaction name="actionToolbarPowerOff"/>
<addaction name="actionToolbarReset"/>
<addaction name="actionToolbarPause"/>
<addaction name="actionToolbarChangeDisc"/>
<addaction name="actionToolbarScreenshot"/>
<addaction name="separator"/>
<addaction name="actionLoadState"/>
<addaction name="actionSaveState"/>
<addaction name="actionToolbarLoadState"/>
<addaction name="actionToolbarSaveState"/>
<addaction name="separator"/>
<addaction name="actionFullscreen"/>
<addaction name="actionToolbarFullscreen"/>
<addaction name="separator"/>
<addaction name="actionSettings2"/>
<addaction name="actionControllerSettings"/>
<addaction name="actionToolbarSettings"/>
<addaction name="actionToolbarControllerSettings"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<action name="actionStartFile">
@@ -263,6 +268,15 @@
<string>Start &amp;File...</string>
</property>
</action>
<action name="actionToolbarStartFile">
<property name="icon">
<iconset theme="file-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">Start &amp;File...</string>
</property>
</action>
<action name="actionStartDisc">
<property name="icon">
<iconset theme="disc-2-line">
@@ -272,6 +286,15 @@
<string>Start &amp;Disc...</string>
</property>
</action>
<action name="actionToolbarStartDisc">
<property name="icon">
<iconset theme="disc-2-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">Start &amp;Disc...</string>
</property>
</action>
<action name="actionStartBios">
<property name="icon">
<iconset theme="chip-line">
@@ -281,6 +304,15 @@
<string>Start &amp;BIOS</string>
</property>
</action>
<action name="actionToolbarStartBios">
<property name="icon">
<iconset theme="chip-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">Start &amp;BIOS</string>
</property>
</action>
<action name="actionScanForNewGames">
<property name="icon">
<iconset theme="file-search-line">
@@ -308,6 +340,15 @@
<string>Shut &amp;Down</string>
</property>
</action>
<action name="actionToolbarPowerOff">
<property name="icon">
<iconset theme="shut-down-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">Shut &amp;Down</string>
</property>
</action>
<action name="actionPowerOffWithoutSaving">
<property name="icon">
<iconset theme="close-line">
@@ -326,6 +367,15 @@
<string>&amp;Reset</string>
</property>
</action>
<action name="actionToolbarReset">
<property name="icon">
<iconset theme="restart-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">&amp;Reset</string>
</property>
</action>
<action name="actionPause">
<property name="checkable">
<bool>true</bool>
@@ -338,22 +388,34 @@
<string>&amp;Pause</string>
</property>
</action>
<action name="actionLoadState">
<action name="actionToolbarPause">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset theme="pause-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">&amp;Pause</string>
</property>
</action>
<action name="actionToolbarLoadState">
<property name="icon">
<iconset theme="floppy-out-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Load State</string>
<string comment="In Toolbar">&amp;Load State</string>
</property>
</action>
<action name="actionSaveState">
<action name="actionToolbarSaveState">
<property name="icon">
<iconset theme="floppy-in-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Save State</string>
<string comment="In Toolbar">&amp;Save State</string>
</property>
</action>
<action name="actionExit">
@@ -392,6 +454,15 @@
<string>&amp;Controllers</string>
</property>
</action>
<action name="actionToolbarControllerSettings">
<property name="icon">
<iconset theme="controller-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">&amp;Controllers</string>
</property>
</action>
<action name="actionHotkeySettings">
<property name="icon">
<iconset theme="keyboard-line">
@@ -433,37 +504,46 @@
<string>Fullscreen</string>
</property>
</action>
<action name="actionToolbarFullscreen">
<property name="icon">
<iconset theme="fullscreen-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">Fullscreen</string>
</property>
</action>
<action name="actionResolution_Scale">
<property name="text">
<string>Resolution Scale</string>
</property>
</action>
<action name="actionGitHubRepository">
<property name="text">
<string>&amp;GitHub Repository...</string>
</property>
<property name="icon">
<iconset theme="github">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;GitHub Repository...</string>
</property>
</action>
<action name="actionSupportForums">
<property name="text">
<string>Support &amp;Forums...</string>
</property>
<property name="icon">
<iconset theme="at">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Support &amp;Forums...</string>
</property>
</action>
<action name="actionDiscordServer">
<property name="text">
<string>&amp;Discord Server...</string>
</property>
<property name="icon">
<iconset theme="discord">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Discord Server...</string>
</property>
</action>
<action name="actionCheckForUpdates">
<property name="icon">
@@ -484,21 +564,21 @@
</property>
</action>
<action name="actionAbout">
<property name="icon">
<iconset resource="resources/resources.qrc">
<normaloff>:/icons/AppIcon64.png</normaloff>:/icons/AppIcon64.png</iconset>
</property>
<property name="text">
<string>&amp;About PCSX2...</string>
</property>
<property name="icon">
<iconset resource="resources/resources.qrc">
<normaloff>:/icons/AppIcon.png</normaloff>:/icons/AppIcon.png</iconset>
</property>
</action>
<action name="actionChangeDisc">
<action name="actionToolbarChangeDisc">
<property name="icon">
<iconset theme="disc-eject-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Change Disc...</string>
<string comment="In Toolbar">Change Disc...</string>
</property>
</action>
<action name="actionAudioSettings">
@@ -549,13 +629,13 @@
<enum>QAction::PreferencesRole</enum>
</property>
</action>
<action name="actionSettings2">
<action name="actionToolbarSettings">
<property name="icon">
<iconset theme="settings-3-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Settings</string>
<string comment="In Toolbar">&amp;Settings</string>
</property>
<property name="menuRole">
<enum>QAction::PreferencesRole</enum>
@@ -595,6 +675,15 @@
<string>&amp;Screenshot</string>
</property>
</action>
<action name="actionToolbarScreenshot">
<property name="icon">
<iconset theme="screenshot-2-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string comment="In Toolbar">&amp;Screenshot</string>
</property>
</action>
<action name="actionMemoryCardSettings">
<property name="icon">
<iconset theme="memcard-line">
@@ -720,55 +809,55 @@
</property>
</action>
<action name="actionGridViewZoomIn">
<property name="icon">
<iconset theme="zoom-in-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Zoom &amp;In (Grid View)</string>
</property>
<property name="shortcut">
<string>Ctrl++</string>
</property>
<property name="icon">
<iconset theme="zoom-in-line">
<normaloff>.</normaloff>.</iconset>
</property>
</action>
<action name="actionGridViewZoomOut">
<property name="icon">
<iconset theme="zoom-out-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Zoom &amp;Out (Grid View)</string>
</property>
<property name="shortcut">
<string>Ctrl+-</string>
</property>
<property name="icon">
<iconset theme="zoom-out-line">
<normaloff>.</normaloff>.</iconset>
</property>
</action>
<action name="actionGridViewRefreshCovers">
<property name="text">
<string>Refresh &amp;Covers (Grid View)</string>
</property>
<property name="icon">
<iconset theme="refresh-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Refresh &amp;Covers (Grid View)</string>
</property>
</action>
<action name="actionOpen_Memory_Card_Directory">
<property name="text">
<string>Open Memory Card Directory...</string>
</property>
<property name="icon">
<iconset theme="memcard-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Open Memory Card Directory...</string>
</property>
</action>
<action name="actionOpenDataDirectory">
<property name="text">
<string>Open Data Directory...</string>
</property>
<property name="icon">
<iconset theme="folder-open-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Open Data Directory...</string>
</property>
</action>
<action name="actionToggleSoftwareRendering">
<property name="text">
@@ -776,13 +865,13 @@
</property>
</action>
<action name="actionDebugger">
<property name="text">
<string>Open Debugger</string>
</property>
<property name="icon">
<iconset theme="heart-circle-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Open Debugger</string>
</property>
</action>
<action name="actionReloadPatches">
<property name="text">
@@ -920,23 +1009,23 @@
<string>Start Big Picture Mode</string>
</property>
</action>
<action name="actionStartFullscreenUI2">
<action name="actionToolbarStartFullscreenUI">
<property name="icon">
<iconset theme="tv-2-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Big Picture</string>
<string comment="In Toolbar">Big Picture</string>
</property>
</action>
<action name="actionCoverDownloader">
<property name="text">
<string>Cover Downloader...</string>
</property>
<property name="icon">
<iconset theme="artboard-2-line">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Cover Downloader...</string>
</property>
</action>
<action name="actionShowAdvancedSettings">
<property name="checkable">

View File

@@ -42,12 +42,12 @@
#include "pcsx2/MTGS.h"
#include "pcsx2/PAD/Host/PAD.h"
#include "pcsx2/PerformanceMetrics.h"
#include "pcsx2/SysForwardDefs.h"
#include "pcsx2/VMManager.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/CrashHandler.h"
#include "common/Exceptions.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include "common/SettingsWrapper.h"
@@ -1186,6 +1186,16 @@ void Host::SetFullscreen(bool enabled)
g_emu_thread->setFullscreen(enabled, true);
}
void Host::OnCaptureStarted(const std::string& filename)
{
emit g_emu_thread->onCaptureStarted(QString::fromStdString(filename));
}
void Host::OnCaptureStopped()
{
emit g_emu_thread->onCaptureStopped();
}
bool QtHost::InitializeConfig()
{
if (!EmuFolders::InitializeCriticalFolders())

View File

@@ -158,6 +158,10 @@ Q_SIGNALS:
/// Called when achievements are reloaded/refreshed (e.g. game change, login, option change).
void onAchievementsRefreshed(quint32 id, const QString& game_info_string, quint32 total, quint32 points);
/// Called when video capture starts/stops.
void onCaptureStarted(const QString& filename);
void onCaptureStopped();
protected:
void run();

View File

@@ -931,14 +931,18 @@ namespace SettingWidgetBinder
template <typename WidgetType>
static inline void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
const char** enum_names, const char** enum_values, const char* default_value)
const char** enum_names, const char** enum_values, const char* default_value, const char* translation_ctx = nullptr)
{
using Accessor = SettingAccessor<WidgetType>;
const std::string value = Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value);
for (int i = 0; enum_names[i] != nullptr; i++)
widget->addItem(QString::fromUtf8(enum_names[i]));
{
widget->addItem(translation_ctx ?
qApp->translate(translation_ctx, enum_names[i]) :
QString::fromUtf8(enum_names[i]));
}
int enum_index = -1;
for (int i = 0; enum_values[i] != nullptr; i++)

View File

@@ -9,22 +9,10 @@
<rect>
<x>0</x>
<y>0</y>
<width>410</width>
<height>215</height>
<width>447</width>
<height>196</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>410</width>
<height>215</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>410</width>
<height>215</height>
</size>
</property>
<property name="windowTitle">
<string comment="Window title">RetroAchievements Login</string>
</property>

View File

@@ -39,20 +39,6 @@ static constexpr s32 DEFAULT_SOUNDTOUCH_SEQUENCE_LENGTH = 30;
static constexpr s32 DEFAULT_SOUNDTOUCH_SEEK_WINDOW = 20;
static constexpr s32 DEFAULT_SOUNDTOUCH_OVERLAP = 10;
static const char* s_output_module_entries[] = {QT_TRANSLATE_NOOP("AudioSettingsWidget", "No Sound (Emulate SPU2 only)"),
//: Cubeb is an audio engine name. Leave as-is.
QT_TRANSLATE_NOOP("AudioSettingsWidget", "Cubeb (Cross-platform)"),
#ifdef _WIN32
//: XAudio2 is an audio engine name. Leave as-is.
QT_TRANSLATE_NOOP("AudioSettingsWidget", "XAudio2"),
#endif
nullptr};
static const char* s_output_module_values[] = {"nullout", "cubeb",
#ifdef _WIN32
"xaudio2",
#endif
nullptr};
AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent)
: QWidget(parent)
, m_dialog(dialog)
@@ -60,6 +46,7 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent
SettingsInterface* sif = dialog->getSettingsInterface();
m_ui.setupUi(this);
populateOutputModules();
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.syncMode, "SPU2/Output", "SynchMode", DEFAULT_SYNCHRONIZATION_MODE);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.expansionMode, "SPU2/Output", "SpeakerConfiguration", DEFAULT_EXPANSION_MODE);
@@ -69,8 +56,7 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent
updateTargetLatencyRange();
expansionModeChanged();
SettingWidgetBinder::BindWidgetToEnumSetting(
sif, m_ui.outputModule, "SPU2/Output", "OutputModule", s_output_module_entries, s_output_module_values, DEFAULT_OUTPUT_MODULE);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.outputModule, "SPU2/Output", "OutputModule", DEFAULT_OUTPUT_MODULE);
SettingWidgetBinder::BindSliderToIntSetting(
//: Measuring unit that will appear after the number selected in its option. Adapt the space depending on your language's rules.
sif, m_ui.targetLatency, m_ui.targetLatencyLabel, tr(" ms"), "SPU2/Output", "Latency", DEFAULT_TARGET_LATENCY);
@@ -156,6 +142,12 @@ void AudioSettingsWidget::expansionModeChanged()
m_ui.dplLevel->setDisabled(!expansion51);
}
void AudioSettingsWidget::populateOutputModules()
{
for (const SndOutModule* mod : GetSndOutModules())
m_ui.outputModule->addItem(qApp->translate("SPU2", mod->GetDisplayName()), QString::fromUtf8(mod->GetIdent()));
}
void AudioSettingsWidget::outputModuleChanged()
{
const std::string module_name(m_dialog->getEffectiveStringValue("SPU2/Output", "OutputModule", DEFAULT_OUTPUT_MODULE));

View File

@@ -42,6 +42,7 @@ private Q_SLOTS:
void resetTimestretchDefaults();
private:
void populateOutputModules();
void updateVolumeLabel();
SettingsDialog* m_dialog;

View File

@@ -1027,7 +1027,7 @@ void USBDeviceWidget::onAutomaticBindingClicked()
void USBDeviceWidget::onClearBindingsClicked()
{
if (QMessageBox::question(QtUtils::GetRootWidget(this), tr("Clear Bindings"),
tr("Are you sure you want to clear all bindings for this controller? This action cannot be undone.")) != QMessageBox::Yes)
tr("Are you sure you want to clear all bindings for this device? This action cannot be undone.")) != QMessageBox::Yes)
{
return;
}

View File

@@ -136,10 +136,10 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsDialog* dialog, QWidget* parent)
if (m_dialog->isPerGameSettings())
m_ui.ethDevType->addItem(tr("Use Global Setting [%1]").arg(QString::fromUtf8(Pcsx2Config::DEV9Options::NetApiNames[static_cast<u32>(m_global_api)])));
else
m_ui.ethDevType->addItem(QString::fromUtf8(m_api_namelist[0]));
m_ui.ethDevType->addItem(qApp->translate("DEV9SettingsWidget", m_api_namelist[0]));
for (int i = 1; m_api_namelist[i] != nullptr; i++)
m_ui.ethDevType->addItem(QString::fromUtf8(m_api_namelist[i]));
m_ui.ethDevType->addItem(qApp->translate("DEV9SettingsWidget", m_api_namelist[i]));
const std::string value = m_dialog->getStringValue("DEV9/Eth", "EthApi", Pcsx2Config::DEV9Options::NetApiNames[static_cast<int>(Pcsx2Config::DEV9Options::NetApi::Unset)]).value();
@@ -212,12 +212,12 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsDialog* dialog, QWidget* parent)
connect(m_ui.ethGatewayAuto, QOverload<int>::of(&QCheckBox::stateChanged), this, [&](int state) { onEthAutoChanged(m_ui.ethGatewayAuto, state, m_ui.ethGatewayAddr, "DEV9/Eth", "AutoGateway"); });
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.ethDNS1Mode, "DEV9/Eth", "ModeDNS1",
s_dns_name, Pcsx2Config::DEV9Options::DnsModeNames, Pcsx2Config::DEV9Options::DnsModeNames[static_cast<int>(Pcsx2Config::DEV9Options::DnsMode::Auto)]);
s_dns_name, Pcsx2Config::DEV9Options::DnsModeNames, Pcsx2Config::DEV9Options::DnsModeNames[static_cast<int>(Pcsx2Config::DEV9Options::DnsMode::Auto)], "DEV9SettingsWidget");
onEthDNSModeChanged(m_ui.ethDNS1Mode, m_ui.ethDNS1Mode->currentIndex(), m_ui.ethDNS1Addr, "DEV9/Eth", "ModeDNS1");
connect(m_ui.ethDNS1Mode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [&](int index) { onEthDNSModeChanged(m_ui.ethDNS1Mode, index, m_ui.ethDNS1Addr, "DEV9/Eth", "ModeDNS1"); });
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.ethDNS2Mode, "DEV9/Eth", "ModeDNS2",
s_dns_name, Pcsx2Config::DEV9Options::DnsModeNames, Pcsx2Config::DEV9Options::DnsModeNames[static_cast<int>(Pcsx2Config::DEV9Options::DnsMode::Auto)]);
s_dns_name, Pcsx2Config::DEV9Options::DnsModeNames, Pcsx2Config::DEV9Options::DnsModeNames[static_cast<int>(Pcsx2Config::DEV9Options::DnsMode::Auto)], "DEV9SettingsWidget");
onEthDNSModeChanged(m_ui.ethDNS2Mode, m_ui.ethDNS2Mode->currentIndex(), m_ui.ethDNS2Addr, "DEV9/Eth", "ModeDNS2");
connect(m_ui.ethDNS2Mode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [&](int index) { onEthDNSModeChanged(m_ui.ethDNS2Mode, index, m_ui.ethDNS2Addr, "DEV9/Eth", "ModeDNS2"); });

View File

@@ -59,7 +59,7 @@
<item row="0" column="0" colspan="4">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Used for storing shaders, gzip indices, and game list data.</string>
<string>Used for storing shaders, game list, and achievement data.</string>
</property>
</widget>
</item>

View File

@@ -10,9 +10,6 @@
<height>361</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>

View File

@@ -16,9 +16,6 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">

View File

@@ -10,9 +10,6 @@
<height>392</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>

View File

@@ -268,6 +268,11 @@
<string extracomment="Leave the code as-is, translate the country's name.">PAL-P (Portugal)</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="Leave the code as-is, translate the country's name.">PAL-PL (Poland)</string>
</property>
</item>
<item>
<property name="text">
<string extracomment="Leave the code as-is, translate the country's name.">PAL-R (Russia)</string>

View File

@@ -554,8 +554,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
"Helps Harry Potter and Stuntman games. It has a big impact on performance."));
dialog->registerWidgetHelp(m_ui.preloadFrameData, tr("Preload Frame Data"), tr("Unchecked"),
tr("Uploads GS data when rendering a new frame to reproduce some effects accurately. "
"Fixes black screen issues in games like Armored Core: Last Raven."));
tr("Uploads GS data when rendering a new frame to reproduce some effects accurately. "));
dialog->registerWidgetHelp(m_ui.textureInsideRt, tr("Texture Inside RT"), tr("Disabled"),
tr("Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer."));

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>720</width>
<height>492</height>
<height>463</height>
</rect>
</property>
<property name="windowTitle">
@@ -29,7 +29,7 @@
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Renderer</string>
<string/>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">

View File

@@ -92,7 +92,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
connect(m_ui.renderToSeparateWindow, &QCheckBox::stateChanged, this, &InterfaceSettingsWidget::onRenderToSeparateWindowChanged);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.theme, "UI", "Theme", THEME_NAMES, THEME_VALUES,
QtHost::GetDefaultThemeName());
QtHost::GetDefaultThemeName(), "InterfaceSettingsWidget");
connect(m_ui.theme, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() { emit themeChanged(); });
populateLanguages();

View File

@@ -30,6 +30,13 @@ MemoryCardConvertDialog::MemoryCardConvertDialog(QWidget* parent, QString select
: QDialog(parent)
{
m_ui.setupUi(this);
// For some reason, setting these in the .ui doesn't work..
m_ui.conversionTypeDescription->setFrameStyle(QFrame::Sunken);
m_ui.conversionTypeDescription->setFrameShape(QFrame::WinPanel);
m_ui.note->setFrameStyle(QFrame::Sunken);
m_ui.note->setFrameShape(QFrame::WinPanel);
m_selectedCard = selectedCard;
std::optional<AvailableMcdInfo> srcCardInfo = FileMcd_GetCardInfo(m_selectedCard.toStdString());
@@ -49,22 +56,22 @@ MemoryCardConvertDialog::MemoryCardConvertDialog(QWidget* parent, QString select
switch (m_srcCardInfo.type)
{
case MemoryCardType::File:
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, "Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card.");
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, tr("Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card."));
break;
case MemoryCardType::Folder:
switch (m_ui.conversionTypeSelect->currentData().toInt())
{
case 8:
SetType(MemoryCardType::File, MemoryCardFileType::PS2_8MB, "A standard, 8 MB Memory Card. Most compatible, but smallest capacity.");
SetType(MemoryCardType::File, MemoryCardFileType::PS2_8MB, tr("A standard, 8 MB Memory Card. Most compatible, but smallest capacity."));
break;
case 16:
SetType(MemoryCardType::File, MemoryCardFileType::PS2_16MB, "2x larger than a standard Memory Card. May have some compatibility issues.");
SetType(MemoryCardType::File, MemoryCardFileType::PS2_16MB, tr("2x larger than a standard Memory Card. May have some compatibility issues."));
break;
case 32:
SetType(MemoryCardType::File, MemoryCardFileType::PS2_32MB, "4x larger than a standard Memory Card. Likely to have compatibility issues.");
SetType(MemoryCardType::File, MemoryCardFileType::PS2_32MB, tr("4x larger than a standard Memory Card. Likely to have compatibility issues."));
break;
case 64:
SetType(MemoryCardType::File, MemoryCardFileType::PS2_64MB, "8x larger than a standard Memory Card. Likely to have compatibility issues.");
SetType(MemoryCardType::File, MemoryCardFileType::PS2_64MB, tr("8x larger than a standard Memory Card. Likely to have compatibility issues."));
break;
default:
//: MemoryCardType should be left as-is.
@@ -153,7 +160,7 @@ bool MemoryCardConvertDialog::SetupPicklist()
{
case MemoryCardType::File:
m_ui.conversionTypeSelect->addItems({"Folder"});
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, "Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card.");
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, tr("Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card."));
break;
case MemoryCardType::Folder:
// Compute which file types should be allowed.
@@ -183,7 +190,7 @@ bool MemoryCardConvertDialog::SetupPicklist()
if (sizeBytes < CardCapacity::_8_MB)
{
m_ui.conversionTypeSelect->addItem("8 MB File", 8);
m_ui.conversionTypeSelect->addItem(tr("8 MB File"), 8);
if (!typeSet)
{
@@ -194,7 +201,7 @@ bool MemoryCardConvertDialog::SetupPicklist()
if (sizeBytes < CardCapacity::_16_MB)
{
m_ui.conversionTypeSelect->addItem("16 MB File", 16);
m_ui.conversionTypeSelect->addItem(tr("16 MB File"), 16);
if (!typeSet)
{
@@ -205,7 +212,7 @@ bool MemoryCardConvertDialog::SetupPicklist()
if (sizeBytes < CardCapacity::_32_MB)
{
m_ui.conversionTypeSelect->addItem("32 MB File", 32);
m_ui.conversionTypeSelect->addItem(tr("32 MB File"), 32);
if (!typeSet)
{
@@ -216,7 +223,7 @@ bool MemoryCardConvertDialog::SetupPicklist()
if (sizeBytes < CardCapacity::_64_MB)
{
m_ui.conversionTypeSelect->addItem("64 MB File", 64);
m_ui.conversionTypeSelect->addItem(tr("64 MB File"), 64);
if (!typeSet)
{
@@ -284,30 +291,30 @@ void MemoryCardConvertDialog::SetType(MemoryCardType type, MemoryCardFileType fi
{
m_type = type;
m_fileType = fileType;
m_ui.conversionTypeDescription->setPlainText(description);
m_ui.conversionTypeDescription->setText(QStringLiteral("<center>%1</center>").arg(description));
}
void MemoryCardConvertDialog::SetType_8()
{
SetType(MemoryCardType::File, MemoryCardFileType::PS2_8MB, "A standard, 8 MB Memory Card. Most compatible, but smallest capacity.");
SetType(MemoryCardType::File, MemoryCardFileType::PS2_8MB, tr("A standard, 8 MB Memory Card. Most compatible, but smallest capacity."));
}
void MemoryCardConvertDialog::SetType_16()
{
SetType(MemoryCardType::File, MemoryCardFileType::PS2_16MB, "2x larger as a standard Memory Card. May have some compatibility issues.");
SetType(MemoryCardType::File, MemoryCardFileType::PS2_16MB, tr("2x larger as a standard Memory Card. May have some compatibility issues."));
}
void MemoryCardConvertDialog::SetType_32()
{
SetType(MemoryCardType::File, MemoryCardFileType::PS2_32MB, "4x larger than a standard Memory Card. Likely to have compatibility issues.");
SetType(MemoryCardType::File, MemoryCardFileType::PS2_32MB, tr("4x larger than a standard Memory Card. Likely to have compatibility issues."));
}
void MemoryCardConvertDialog::SetType_64()
{
SetType(MemoryCardType::File, MemoryCardFileType::PS2_64MB, "8x larger than a standard Memory Card. Likely to have compatibility issues.");
SetType(MemoryCardType::File, MemoryCardFileType::PS2_64MB, tr("8x larger than a standard Memory Card. Likely to have compatibility issues."));
}
void MemoryCardConvertDialog::SetType_Folder()
{
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, "Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card.");
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, tr("Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card."));
}

View File

@@ -10,27 +10,9 @@
<x>0</x>
<y>0</y>
<width>440</width>
<height>320</height>
<height>282</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>440</width>
<height>320</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>440</width>
<height>320</height>
</size>
</property>
<property name="windowTitle">
<string>Convert Memory Card</string>
</property>
@@ -40,141 +22,117 @@
<property name="modal">
<bool>false</bool>
</property>
<widget class="QGroupBox" name="conversionTypeGroup">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>421</width>
<height>61</height>
</rect>
</property>
<property name="title">
<string>Conversion Type</string>
</property>
<widget class="QComboBox" name="conversionTypeSelect">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>401</width>
<height>22</height>
</rect>
</property>
<item>
<property name="text">
<string>8 MB File</string>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="conversionTypeGroup">
<property name="title">
<string>Conversion Type</string>
</property>
</item>
<item>
<property name="text">
<string>16 MB File</string>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QComboBox" name="conversionTypeSelect">
<item>
<property name="text">
<string>8 MB File</string>
</property>
</item>
<item>
<property name="text">
<string>16 MB File</string>
</property>
</item>
<item>
<property name="text">
<string>32 MB File</string>
</property>
</item>
<item>
<property name="text">
<string>64 MB File</string>
</property>
</item>
<item>
<property name="text">
<string>Folder</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="conversionTypeDescription">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
</item>
<item>
<property name="text">
<string>32 MB File</string>
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="note">
<property name="minimumSize">
<size>
<width>0</width>
<height>35</height>
</size>
</property>
</item>
<item>
<property name="text">
<string>64 MB File</string>
<string>&lt;center&gt;&lt;strong&gt;Note:&lt;/strong&gt; Converting a Memory Card creates a &lt;strong&gt;COPY&lt;/strong&gt; of your existing Memory Card. It does &lt;strong&quot;&gt;NOT delete, modify, or replace&lt;/strong&gt; your existing Memory Card.&lt;/center&gt;</string>
</property>
</item>
<item>
<property name="text">
<string>Folder</string>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</item>
</widget>
</widget>
<widget class="QTextBrowser" name="note">
<property name="geometry">
<rect>
<x>10</x>
<y>150</y>
<width>421</width>
<height>61</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Note: Converting a Memory Card creates a COPY of your existing Memory Card. It does NOT delete, modify, or replace your existing Memory Card.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QTextBrowser" name="conversionTypeDescription">
<property name="geometry">
<rect>
<x>10</x>
<y>80</y>
<width>421</width>
<height>61</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p align=&quot;center&quot; style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
<rect>
<x>270</x>
<y>290</y>
<width>156</width>
<height>24</height>
</rect>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QGroupBox" name="progressGroup">
<property name="geometry">
<rect>
<x>10</x>
<y>220</y>
<width>421</width>
<height>61</height>
</rect>
</property>
<property name="title">
<string>Progress</string>
</property>
<widget class="QProgressBar" name="progressBar">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>401</width>
<height>23</height>
</rect>
</property>
<property name="value">
<number>24</number>
</property>
</widget>
</widget>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="progressGroup">
<property name="title">
<string>Progress</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>24</number>
</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>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>

View File

@@ -22,12 +22,12 @@
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QPushButton>
#include "Settings/CreateMemoryCardDialog.h"
#include "Settings/MemoryCardCreateDialog.h"
#include "pcsx2/MemoryCardFile.h"
#include "pcsx2/System.h"
CreateMemoryCardDialog::CreateMemoryCardDialog(QWidget* parent /* = nullptr */)
MemoryCardCreateDialog::MemoryCardCreateDialog(QWidget* parent /* = nullptr */)
: QDialog(parent)
{
m_ui.setupUi(this);
@@ -35,7 +35,7 @@ CreateMemoryCardDialog::CreateMemoryCardDialog(QWidget* parent /* = nullptr */)
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
connect(m_ui.name, &QLineEdit::textChanged, this, &CreateMemoryCardDialog::nameTextChanged);
connect(m_ui.name, &QLineEdit::textChanged, this, &MemoryCardCreateDialog::nameTextChanged);
connect(m_ui.size8MB, &QRadioButton::clicked, this, [this]() { setType(MemoryCardType::File, MemoryCardFileType::PS2_8MB); });
connect(m_ui.size16MB, &QRadioButton::clicked, this, [this]() { setType(MemoryCardType::File, MemoryCardFileType::PS2_16MB); });
@@ -46,9 +46,9 @@ CreateMemoryCardDialog::CreateMemoryCardDialog(QWidget* parent /* = nullptr */)
disconnect(m_ui.buttonBox, &QDialogButtonBox::accepted, this, nullptr);
connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &CreateMemoryCardDialog::createCard);
connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &CreateMemoryCardDialog::close);
connect(m_ui.buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &CreateMemoryCardDialog::restoreDefaults);
connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &MemoryCardCreateDialog::createCard);
connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &MemoryCardCreateDialog::close);
connect(m_ui.buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &MemoryCardCreateDialog::restoreDefaults);
#ifndef _WIN32
m_ui.ntfsCompression->setEnabled(false);
@@ -57,9 +57,9 @@ CreateMemoryCardDialog::CreateMemoryCardDialog(QWidget* parent /* = nullptr */)
updateState();
}
CreateMemoryCardDialog::~CreateMemoryCardDialog() = default;
MemoryCardCreateDialog::~MemoryCardCreateDialog() = default;
void CreateMemoryCardDialog::nameTextChanged()
void MemoryCardCreateDialog::nameTextChanged()
{
QString controlName(m_ui.name->text());
const int cursorPos = m_ui.name->cursorPosition();
@@ -76,14 +76,14 @@ void CreateMemoryCardDialog::nameTextChanged()
updateState();
}
void CreateMemoryCardDialog::setType(MemoryCardType type, MemoryCardFileType fileType)
void MemoryCardCreateDialog::setType(MemoryCardType type, MemoryCardFileType fileType)
{
m_type = type;
m_fileType = fileType;
updateState();
}
void CreateMemoryCardDialog::restoreDefaults()
void MemoryCardCreateDialog::restoreDefaults()
{
setType(MemoryCardType::File, MemoryCardFileType::PS2_8MB);
m_ui.size8MB->setChecked(true);
@@ -94,7 +94,7 @@ void CreateMemoryCardDialog::restoreDefaults()
m_ui.sizeFolder->setChecked(false);
}
void CreateMemoryCardDialog::updateState()
void MemoryCardCreateDialog::updateState()
{
const bool okay = (m_ui.name->text().length() > 0);
@@ -104,30 +104,27 @@ void CreateMemoryCardDialog::updateState()
#endif
}
void CreateMemoryCardDialog::createCard()
void MemoryCardCreateDialog::createCard()
{
QString name(m_ui.name->text());
std::string nameStr;
if (m_fileType == MemoryCardFileType::PS1)
const QString name = m_ui.name->text();
const std::string name_str = QStringLiteral("%1.%2").arg(name)
.arg((m_fileType == MemoryCardFileType::PS1) ? QStringLiteral("mcr") : QStringLiteral("ps2"))
.toStdString();
if (!Path::IsValidFileName(name_str, false))
{
name += QStringLiteral(".mcr");
}
else
{
name += QStringLiteral(".ps2");
QMessageBox::critical(this, tr("Create Memory Card"),
tr("Failed to create the Memory Card, because the name '%1' contains one or more invalid characters.").arg(name));
return;
}
nameStr = name.toStdString();
if (FileMcd_GetCardInfo(nameStr).has_value())
if (FileMcd_GetCardInfo(name_str).has_value())
{
QMessageBox::critical(this, tr("Create Memory Card"),
tr("Failed to create the Memory Card, because another card with the name '%1' already exists.").arg(name));
return;
}
if (!FileMcd_CreateNewCard(nameStr, m_type, m_fileType))
if (!FileMcd_CreateNewCard(name_str, m_type, m_fileType))
{
QMessageBox::critical(this, tr("Create Memory Card"),
tr("Failed to create the Memory Card, the log may contain more information."));
@@ -137,7 +134,7 @@ void CreateMemoryCardDialog::createCard()
#ifdef _WIN32
if (m_ui.ntfsCompression->isChecked() && m_type == MemoryCardType::File)
{
const std::string fullPath(Path::Combine(EmuFolders::MemoryCards, nameStr));
const std::string fullPath(Path::Combine(EmuFolders::MemoryCards, name_str));
FileSystem::SetPathCompression(fullPath.c_str(), true);
}
#endif

View File

@@ -17,17 +17,17 @@
#include <QtWidgets/QDialog>
#include "ui_CreateMemoryCardDialog.h"
#include "ui_MemoryCardCreateDialog.h"
#include "pcsx2/Config.h"
class CreateMemoryCardDialog final : public QDialog
class MemoryCardCreateDialog final : public QDialog
{
Q_OBJECT
public:
explicit CreateMemoryCardDialog(QWidget* parent = nullptr);
~CreateMemoryCardDialog();
explicit MemoryCardCreateDialog(QWidget* parent = nullptr);
~MemoryCardCreateDialog();
private Q_SLOTS:
void nameTextChanged();
@@ -38,7 +38,7 @@ private:
void restoreDefaults();
void updateState();
Ui::CreateMemoryCardDialog m_ui;
Ui::MemoryCardCreateDialog m_ui;
MemoryCardType m_type = MemoryCardType::File;
MemoryCardFileType m_fileType = MemoryCardFileType::PS2_8MB;

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CreateMemoryCardDialog</class>
<widget class="QDialog" name="CreateMemoryCardDialog">
<class>MemoryCardCreateDialog</class>
<widget class="QDialog" name="MemoryCardCreateDialog">
<property name="geometry">
<rect>
<x>0</x>
@@ -285,7 +285,7 @@
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>CreateMemoryCardDialog</receiver>
<receiver>MemoryCardCreateDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
@@ -301,7 +301,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>CreateMemoryCardDialog</receiver>
<receiver>MemoryCardCreateDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">

View File

@@ -24,8 +24,8 @@
#include "common/StringUtil.h"
#include "CreateMemoryCardDialog.h"
#include "MemoryCardConvertDialog.h"
#include "MemoryCardCreateDialog.h"
#include "MemoryCardSettingsWidget.h"
#include "QtHost.h"
#include "QtUtils.h"
@@ -186,7 +186,7 @@ void MemoryCardSettingsWidget::ejectSlot(u32 slot)
void MemoryCardSettingsWidget::createCard()
{
CreateMemoryCardDialog dialog(QtUtils::GetRootWidget(this));
MemoryCardCreateDialog dialog(QtUtils::GetRootWidget(this));
if (dialog.exec() == QDialog::Accepted)
refresh();
}

View File

@@ -10,9 +10,6 @@
<height>112</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">

View File

@@ -169,10 +169,10 @@ void SetupWizardDialog::confirmCancel()
void SetupWizardDialog::setupUi()
{
setWindowIcon(QIcon(QStringLiteral("%1/icons/AppIconLarge.png").arg(QtHost::GetResourcesBasePath())));
m_ui.setupUi(this);
m_ui.logo->setPixmap(QPixmap(QStringLiteral("%1/icons/AppIconLarge.png").arg(QtHost::GetResourcesBasePath())));
m_ui.pages->setCurrentIndex(0);
m_page_labels[Page_Language] = m_ui.labelLanguage;
@@ -194,7 +194,7 @@ void SetupWizardDialog::setupUi()
void SetupWizardDialog::setupLanguagePage()
{
SettingWidgetBinder::BindWidgetToEnumSetting(nullptr, m_ui.theme, "UI", "Theme",
InterfaceSettingsWidget::THEME_NAMES, InterfaceSettingsWidget::THEME_VALUES, QtHost::GetDefaultThemeName());
InterfaceSettingsWidget::THEME_NAMES, InterfaceSettingsWidget::THEME_VALUES, QtHost::GetDefaultThemeName(), "InterfaceSettingsWidget");
connect(m_ui.theme, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SetupWizardDialog::themeChanged);
for (const std::pair<QString, QString>& it : QtHost::GetAvailableLanguageList())

View File

@@ -13,6 +13,11 @@
<property name="windowTitle">
<string>PCSX2 Setup Wizard</string>
</property>
<property name="windowIcon">
<iconset>
<normalon>:/icons/AppIcon64.png</normalon>
</iconset>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="horizontalSpacing">
<number>10</number>
@@ -20,7 +25,7 @@
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="logo">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -33,12 +38,15 @@
<height>128</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>128</width>
<height>128</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources/resources.qrc">:/icons/AppIcon.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>

View File

@@ -238,7 +238,7 @@ void QtHost::SetStyleFromSettings()
standardPalette.setColor(QPalette::Text, Qt::black);
standardPalette.setColor(QPalette::Button, extr);
standardPalette.setColor(QPalette::ButtonText, Qt::black);
standardPalette.setColor(QPalette::Link, Qt::black);
standardPalette.setColor(QPalette::Link, highlight.darker());
standardPalette.setColor(QPalette::Highlight, highlight);
standardPalette.setColor(QPalette::HighlightedText, Qt::white);
standardPalette.setColor(QPalette::Active, QPalette::Button, extr);
@@ -332,6 +332,7 @@ void QtHost::SetStyleFromSettings()
const QColor royalBlue(29, 41, 81);
const QColor darkishBlue(17, 30, 108);
const QColor highlight(36, 93, 218);
const QColor link(0, 202, 255);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, royalBlue);
@@ -343,7 +344,7 @@ void QtHost::SetStyleFromSettings()
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, darkishBlue);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, Qt::white);
darkPalette.setColor(QPalette::Link, link);
darkPalette.setColor(QPalette::Highlight, highlight);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);

View File

@@ -17,6 +17,7 @@
#include "QtHost.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/StringUtil.h"
@@ -40,9 +41,20 @@
namespace QtHost
{
static const ImWchar* GetGlyphRangesJapanese();
static const ImWchar* GetGlyphRangesChinese();
static std::string GetFontPath(const char* name);
struct GlyphInfo
{
const char* language;
const char* windows_font_name;
const char* linux_font_name;
const char* mac_font_name;
const char16_t* used_glyphs;
};
static std::string GetFontPath(const GlyphInfo* gi);
static void UpdateGlyphRanges(const std::string_view& language);
static const GlyphInfo* GetGlyphInfo(const std::string_view& language);
static std::vector<ImWchar> s_glyph_ranges;
} // namespace QtHost
static std::vector<QTranslator*> s_translators;
@@ -60,7 +72,7 @@ void QtHost::InstallTranslator()
QString::fromStdString(Host::GetBaseStringSettingValue("UI", "Language", GetDefaultLanguage()));
// Install the base qt translation first.
const QString base_dir = QStringLiteral("%1/translations").arg(qApp->applicationDirPath());
const QString base_dir = QStringLiteral("%1/translations").arg(qApp->applicationDirPath());
QString base_path = QStringLiteral("%1/qt_%2.qm").arg(base_dir).arg(language);
bool has_base_ts = QFile::exists(base_path);
if (!has_base_ts)
@@ -90,65 +102,67 @@ void QtHost::InstallTranslator()
}
const QString path = QStringLiteral("%1/pcsx2-qt_%3.qm").arg(base_dir).arg(language);
if (!QFile::exists(path))
QTranslator* translator = nullptr;
if (QFile::exists(path))
{
translator = new QTranslator(qApp);
if (translator->load(path))
{
Console.WriteLn(
Color_StrongYellow, "Loaded translation file for language %s", language.toUtf8().constData());
}
else
{
QMessageBox::warning(nullptr, QStringLiteral("Translation Error"),
QStringLiteral("Failed to load translation file for language '%1':\n%2").arg(language).arg(path));
delete translator;
translator = nullptr;
}
}
else
{
#ifdef PCSX2_DEVBUILD
// For now, until we're sure this works on all platforms, we won't block users from starting if they're missing.
QMessageBox::warning(nullptr, QStringLiteral("Translation Error"),
QStringLiteral("Failed to find translation file for language '%1':\n%2").arg(language).arg(path));
#endif
return;
}
QTranslator* translator = new QTranslator(qApp);
if (!translator->load(path))
if (translator)
{
QMessageBox::warning(nullptr, QStringLiteral("Translation Error"),
QStringLiteral("Failed to load translation file for language '%1':\n%2").arg(language).arg(path));
delete translator;
return;
qApp->installTranslator(translator);
s_translators.push_back(translator);
}
Console.WriteLn(Color_StrongYellow, "Loaded translation file for language %s", language.toUtf8().constData());
qApp->installTranslator(translator);
s_translators.push_back(translator);
UpdateGlyphRanges(language.toStdString());
#ifdef _WIN32
if (language == QStringLiteral("ja"))
{
ImGuiManager::SetFontPath(GetFontPath("msgothic.ttc"));
ImGuiManager::SetFontRange(GetGlyphRangesJapanese());
}
else if (language == QStringLiteral("zh-cn"))
{
ImGuiManager::SetFontPath(GetFontPath("msyh.ttc"));
ImGuiManager::SetFontRange(GetGlyphRangesChinese());
}
#endif
// Clear translation cache after installing translators, to prevent races.
Host::ClearTranslationCache();
}
static std::string QtHost::GetFontPath(const char* name)
static std::string QtHost::GetFontPath(const GlyphInfo* gi)
{
#ifdef _WIN32
PWSTR folder_path;
if (FAILED(SHGetKnownFolderPath(FOLDERID_Fonts, 0, nullptr, &folder_path)))
return fmt::format("C:\\Windows\\Fonts\\%s", name);
std::string font_path;
#ifdef _WIN32
if (gi->windows_font_name)
{
PWSTR folder_path;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Fonts, 0, nullptr, &folder_path)))
{
font_path = StringUtil::WideStringToUTF8String(folder_path);
CoTaskMemFree(folder_path);
font_path += "\\";
font_path += gi->windows_font_name;
}
else
{
font_path = fmt::format("C:\\Windows\\Fonts\\%s", gi->windows_font_name);
}
}
#endif
std::string font_path(StringUtil::WideStringToUTF8String(folder_path));
CoTaskMemFree(folder_path);
font_path += "\\";
font_path += name;
return font_path;
#else
return name;
#endif
}
std::vector<std::pair<QString, QString>> QtHost::GetAvailableLanguageList()
{
return {
{QStringLiteral("English"), QStringLiteral("en")},
};
}
const char* QtHost::GetDefaultLanguage()
@@ -173,46 +187,134 @@ s32 Host::Internal::GetTranslatedStringImpl(
return static_cast<s32>(translated_size);
}
static const ImWchar* QtHost::GetGlyphRangesJapanese()
std::vector<std::pair<QString, QString>> QtHost::GetAvailableLanguageList()
{
// clang-format off
// auto update by generate_update_glyph_ranges.py with pcsx2-qt_ja.ts
static const char16_t chars[] = u"、。あいかがきこさしすずせたってでとなにのはべまみらりるれをんァィイェエカキクグゲシジスセタダチッデトドバパフブプボポミムメモャュョラリルレロンー一中了今件体使信入出制効動取口可変始定実度強後得態択挿易更有本検無状獲用画的索終績能自行覧解設読起送速選開除難面高";
const int chars_length = sizeof(chars) / sizeof(chars[0]);
// clang-format on
static ImWchar base_ranges[] = {
0x0020, 0x007E, // Basic Latin
return {
{QStringLiteral("Afrikaans (af-ZA)"), QStringLiteral("af-ZA")},
{QStringLiteral("عربي (ar-SA)"), QStringLiteral("ar-SA")},
{QStringLiteral("Català (ca-ES)"), QStringLiteral("ca-ES")},
{QStringLiteral("Čeština (cs-CZ)"), QStringLiteral("cs-CZ")},
{QStringLiteral("Dansk (da-DK)"), QStringLiteral("da-DK")},
{QStringLiteral("Deutsch (de-DE)"), QStringLiteral("de-DE")},
{QStringLiteral("Ελληνικά (el-GR)"), QStringLiteral("el-GR")},
{QStringLiteral("English (en) [Default]"), QStringLiteral("en")},
{QStringLiteral("Español (Hispanoamérica) (es-419)"), QStringLiteral("es-419")},
{QStringLiteral("Español (España) (es-ES)"), QStringLiteral("es-ES")},
{QStringLiteral("فارسی (fa-IR)"), QStringLiteral("fa-IR")},
{QStringLiteral("Suomi (fi-FI)"), QStringLiteral("fi-FI")},
{QStringLiteral("Français (fr-FR)"), QStringLiteral("fr-FR")},
{QStringLiteral("עִבְרִית (he-IL)"), QStringLiteral("he-IL")},
{QStringLiteral("Magyar (hu-HU)"), QStringLiteral("hu-HU")},
{QStringLiteral("Bahasa Indonesia (id-ID)"), QStringLiteral("id-ID")},
{QStringLiteral("Italiano (it-IT)"), QStringLiteral("it-IT")},
{QStringLiteral("日本語 (ja-JP)"), QStringLiteral("ja-JP")},
{QStringLiteral("한국어 (ko-KR)"), QStringLiteral("ko-KR")},
{QStringLiteral("Nederlands (nl-NL)"), QStringLiteral("nl-NL")},
{QStringLiteral("Norsk (no-NO)"), QStringLiteral("no-NO")},
{QStringLiteral("Polski (pl-PL)"), QStringLiteral("pl-PL")},
{QStringLiteral("Português (Brasil) (pt-BR)"), QStringLiteral("pt-BR")},
{QStringLiteral("Português (Portugal) (pt-PT)"), QStringLiteral("pt-PT")},
{QStringLiteral("Limba română (ro-RO)"), QStringLiteral("ro-RO")},
{QStringLiteral("Русский (ru-RU)"), QStringLiteral("ru-RU")},
{QStringLiteral("Српски језик (sr-SP)"), QStringLiteral("sr-SP")},
{QStringLiteral("Svenska (sv-SE)"), QStringLiteral("sv-SE")},
{QStringLiteral("Türkçe (tr-TR)"), QStringLiteral("tr-TR")},
{QStringLiteral("Українська мова (uk-UA)"), QStringLiteral("uk-UA")},
{QStringLiteral("Tiếng Việt (vi-VN)"), QStringLiteral("vi-VN")},
{QStringLiteral("简体中文 (zh-CN)"), QStringLiteral("zh-CN")},
{QStringLiteral("繁體中文 (zh-TW)"), QStringLiteral("zh-TW")},
};
const int base_length = sizeof(base_ranges) / sizeof(base_ranges[0]);
static ImWchar full_ranges[base_length + chars_length * 2 + 1] = {0};
memcpy(full_ranges, base_ranges, sizeof(base_ranges));
for (int i = 0; i < chars_length; i++)
{
full_ranges[base_length + i * 2] = full_ranges[base_length + i * 2 + 1] = chars[i];
}
return full_ranges;
}
static const ImWchar* QtHost::GetGlyphRangesChinese()
static constexpr const ImWchar s_base_latin_range[] = {
0x0020, 0x00FF, // Basic Latin + Latin Supplement
};
static constexpr const ImWchar s_central_european_ranges[] = {
0x0100, 0x017F, // Central European diacritics
};
void QtHost::UpdateGlyphRanges(const std::string_view& language)
{
// clang-format off
// auto update by generate_update_glyph_ranges.py with pcsx2-qt_zh-cn.ts
static const char16_t chars[] = u"";
const int chars_length = sizeof(chars) / sizeof(chars[0]);
// clang-format on
const GlyphInfo* gi = GetGlyphInfo(language);
static ImWchar base_ranges[] = {
0x0020, 0x007E, // Basic Latin
};
const int base_length = sizeof(base_ranges) / sizeof(base_ranges[0]);
std::string font_path;
s_glyph_ranges.clear();
static ImWchar full_ranges[base_length + chars_length * 2 + 1] = {0};
memcpy(full_ranges, base_ranges, sizeof(base_ranges));
for (int i = 0; i < chars_length; i++)
// Base Latin range is always included.
s_glyph_ranges.insert(s_glyph_ranges.begin(), std::begin(s_base_latin_range), std::end(s_base_latin_range));
if (gi)
{
full_ranges[base_length + i * 2] = full_ranges[base_length + i * 2 + 1] = chars[i];
if (gi->used_glyphs)
{
const char16_t* ptr = gi->used_glyphs;
while (*ptr != 0)
{
// Always should be in pairs.
pxAssert(ptr[0] != 0 && ptr[1] != 0);
s_glyph_ranges.push_back(*(ptr++));
s_glyph_ranges.push_back(*(ptr++));
}
}
font_path = GetFontPath(gi);
}
return full_ranges;
// If we don't have any specific glyph range, assume Central European, except if English, then keep the size down.
if ((!gi || !gi->used_glyphs) && language != "en")
{
s_glyph_ranges.insert(
s_glyph_ranges.begin(), std::begin(s_central_european_ranges), std::end(s_central_european_ranges));
}
// List terminator.
s_glyph_ranges.push_back(0);
s_glyph_ranges.push_back(0);
ImGuiManager::SetFontPath(std::move(font_path));
ImGuiManager::SetFontRange(s_glyph_ranges.data());
}
// clang-format off
static constexpr const char16_t s_cyrillic_ranges[] = {
/* Cyrillic + Cyrillic Supplement */ 0x0400, 0x052F, /* Extended-A */ 0x2DE0, 0x2DFF, /* Extended-B */ 0xA640, 0xA69F, 0, 0
};
static constexpr const QtHost::GlyphInfo s_glyph_info[] = {
// Cyrillic languages
{ "ru-RU", nullptr, nullptr, nullptr, s_cyrillic_ranges },
{ "sr-SP", nullptr, nullptr, nullptr, s_cyrillic_ranges },
{ "uk-UA", nullptr, nullptr, nullptr, s_cyrillic_ranges },
{
"ja-JP", "msgothic.ttc", nullptr, nullptr,
// auto update by update_glyph_ranges.py with pcsx2-qt_ja-JP.ts
u"​​□□△△◯◯✕✕、。〜〜ああいいううええおきくぐここささしすせせそそただっつてにのはびびへべほほまみめもややよれわわをんァイウコサソタチッツテニネパビロワワンンーー一一上下不不中中丸丸了了互互今今他他代代仮仮作作使使保保信信修修倍倍値値停停備備像像入入全全公公内内再再出出切切別別利利制制削削副副割割力力加加効効動動勧勧化化十十南南参参反収取取古古可台右右合合同名向向回回固固国国在在報報場場境境壊壊変変外外大大失失奨奨始始字存完完定定実実左左帰帰常常幅幅度度式式張張形形待待後後御御性性情情想想意意感感態態成成投投択択拡拡推推提提換換敗敗数数整整新新方方既既日日明明時時更更書書替最有有期期本本果果検検標標橙橙機機止正毎毎比比況況注注消消港港湾湾準準無無照照状状率率現現璧璧環環生生用用画画異異的的直直知知確確示示種種稿稿空空索索終終緑緑編編績績能能自自般般行行表表製製複複視視覧覧解解言言設設認認語語読読赤赤起起跡跡転転軸軸込込近近追追送送通通速速進進遅遅遊遊適適選選部部長長閉閉開開関関防防限限除除隅隅集集青青非非面面韓韓音音類類香香高高黄黄++??"
},
{
"ko-KR", "malgun.ttf", nullptr, nullptr,
// auto update by update_glyph_ranges.py with pcsx2-qt_ko-KR.ts
u""
},
{
"zh-CN", "msyh.ttc", nullptr, nullptr,
// auto update by update_glyph_ranges.py with pcsx2-qt_zh-CN.ts
u"‘’□□△△○○、。一丁三下不与且且世世丢丢两两个个中中丰丰串串为主么义之之乎乎乐乐乘乘也也了了事二于于互互亚些交交产产享享亮亮亲亲人人什什仅仅介介仍从他他代以们们件价任任份份伍伍休休优优会会传传估估伸伸似似但但位住佑佑体体何何余余作作佣佣佳佳使使例例供供侧侧便便俄俄保保信信修修倍倍值值倾倾假假偏偏做做停停储储像像儿儿允允元元充充先光克克免免入入全全六六兰共关关兵典兼兼内内册再写写冲决况况净净准准减减几几出击函函刀刀刃刃分切列列则则创创删删利利别别到到制刷刹刹前前剪剪副副力力功务动助势势勿勿包包化化匹区十十升升半半协协单单南南占卡卫卫印印即即压压原原去去参参及及双反发发取变叠叠口古另另只只可台右右号号各各合吉同后向向吗吗否否含含启启呈呈告告员员味味命命和和哈哈响响哪哪唤唤商商善善器器四四回回因因团团围围国图圈圈在在地地场场址址均均坏坐块块坛坛垂垂型型域域基基堆堆堪堪塔塔填填增增士士声声处处备备复复外外多多够够大大天太失失头头夹夹奇奇奏奏套套奥奥奶奶好好如如始始威威娱娱婴婴媒媒子子字存它它安安完完宏宏官官定定宝实害害家家容容宽宽宿宿寄寄密密富富寸对导导封封射射将将小小少少尔尔尚尚尝尝就就尺尺尼尾局局层层屏屏展展属属崩崩工左巨巨差差己已巴巴希希带帧帮帮常常幅幅幕幕平平并并幸幸序序库底度度延延建建开开异弃弊弊式式引引张张弹强归当录录形形彩彩影影径待很很得得循循微微德德心心必忆志志忙忙快快忽忽态态性性怪怪恢恢息息您您悬悬情情惑惑惯惯意意感感慢慢戏我或或战战截截戳戳户户所扁手手打打托托执执扩扩扫扬扳扳找找技技抑抑抖抗护护拆拆拉拉拍拍拒拒拟拟拦拦择择括括拳拳持持指指按按挑挑挡挡挪挪振振捕捕损损换换据据掌掌排排接接控掩描提插插握握搜搜摇摇撕撕撤撤播播操擎支支收收改改放放故故效效敏敏散散数数整整文文断断斯新方方旋旋无无日日旧旧时时明明易易星映是是显显晕晕普普晰晰暂暂暗暗曲曲更更替最有有服服期期未未本本机机权权杆杆束束条条来来板板极极果果柄柄某某染染查查栅栅标栈栏栏校校样根格格框框案案档档桥桥检检棕棕榜榜模模橙橙次次欧欧止步死死殊殊段段每每比比毫毫水水求求汇汇没没油油法法波波注注泻泻洲洲活活流流浅浅测测浏浏浪浪浮浮海海消消深深混混添添清清港港渲渲游游湖湖湾湾溃溃源源溢溢滑滑满满滤滤演演澳澳激激灰灰灵灵点点烈烈热热焦焦然然煞煞照照片版牌牌牙牙特特状状狂狂独独狼狼猎猎猩猩率率王王玩玩环现班班理理瑞瑞甚甚生生用用由甲电电画画畅畅界界留留略略疤疤登登白百的的皇皇盖盘目目直直相相省省看看真眠着着知知短短石石码码破破础础硬硬确确碌碌磁磁示示神神禁禁离离种种秒秒积称移移程程稍稍稳稳空空突突窗窗立立站站端端符符第第等等筛筛签签简简算算管管类类粉粉粘粘精精糊糊系系素素索索紫紫纠纠红红级级纯纯纳纳纹纹线线组组细终经经绑绑结结绕绕绘给络绝统统继继绪绪续续维维绿缀缓缓编编缩缩网网罗罗置置美美翻翻考考者者而而耗耗耳耳联联肩肩胖胖能能腊腊自自至致舍舍良良色色节节芬芬英英范范荐荐荷荷莱莱获获菜菜萄萄著著葡葡蓝蓝藏藏虑虑虚虚融融行行衡衡补补表表被被裁裂装装西西要要覆覆观观规规视视览觉角角解解触触言言警警计计认认让让议议记记许许论论设访证证诊诊译译试试询询该详语语误误说说请诸读读调调谍谍豹豹负负败账质质贴贴费费赛赛起起超超越越足足跟跟跨跨路路跳跳踏踏踪踪身身车车轨轨转转轮软轴轴轻轻载载较较辅辅辑辑输输辨辨边边达达过过运近还这进进连迟述述追追退适选选逐逐递递通通速造遇遇道道避避那那部部都都配配醒醒采采释释里重量量针针钮钮铁铁铺铺链链销锁锐锐错错键锯镜镜长长门门闭问闲闲间间队队防防阴阴附附陆陆降降限限除除险险随隐隔隔隙隙障障雄雄集集零零雾雾需需震震静静非非靠靠面面韩韩音音顶顶项须顿顿预预频频题题颜额风风饱饱馈馈首首香香马马驱驱验验高高鬼鬼魂魂魔魔麦麦黄黄黑黑默默鼓鼓鼠鼠齐齐齿齿,,??"
},
{
"zh-TW", "msyh.ttc", nullptr, nullptr,
// auto update by update_glyph_ranges.py with pcsx2-qt_zh-TW.ts
u""
},
};
// clang-format on
const QtHost::GlyphInfo* QtHost::GetGlyphInfo(const std::string_view& language)
{
for (const GlyphInfo& it : s_glyph_info)
{
if (language == it.language)
return &it;
}
return nullptr;
}

View File

@@ -1,44 +0,0 @@
#!/usr/bin/env python3
import sys
import os
import re
import xml.etree.ElementTree as ET
src_path = os.path.join(os.path.dirname(__file__), "..", "Translations.cpp")
def parse_xml(path):
translations = ""
tree = ET.parse(path)
root = tree.getroot()
for node in root.findall("context/message/translation"):
if node.text:
translations += node.text
chars = list(set([ord(ch) for ch in translations if ord(ch) >= 0x2000]))
chars.sort()
chars = "".join([chr(ch) for ch in chars])
return chars
def update_src_file(ts_file, chars):
ts_name = os.path.basename(ts_file)
pattern = re.compile('(// auto update.*' + ts_name + '.*\n[^"]+")[^"]*(".*)')
with open(src_path, "r", encoding="utf-8") as f:
original = f.read()
update = pattern.sub("\\1" + chars + "\\2", original)
if original != update:
with open(src_path, "w", encoding="utf-8") as f:
f.write(update)
print("Updated character list.")
else:
print("Character list is unchanged.")
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"usage: {sys.argv[0]} <pcsx2-qt_*.ts path>")
sys.exit(1)
chars = parse_xml(sys.argv[1])
#print(chars)
print(f"{len(chars)} character(s) detected.")
update_src_file(sys.argv[1], chars)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env python3
import os
import re
import xml.etree.ElementTree as ET
languages_to_update = [
"ja-JP",
"ko-KR",
"zh-CN",
"zh-TW"
]
src_path = os.path.join(os.path.dirname(__file__), "..", "Translations.cpp")
ts_dir = os.path.join(os.path.dirname(__file__))
def parse_xml(path):
tree = ET.parse(path)
root = tree.getroot()
translations = ""
for node in root.findall("context/message/translation"):
if node.text:
translations += node.text
ords = list(set([ord(ch) for ch in translations if ord(ch) >= 0x2000]))
if len(ords) == 0:
return ""
# Try to organize it into ranges
ords.sort()
ord_pairs = []
start_ord = None
last_ord = None
for nord in ords:
if start_ord is not None and nord == (last_ord + 1):
last_ord = nord
continue
if start_ord is not None:
ord_pairs.append(start_ord)
ord_pairs.append(last_ord)
start_ord = nord
last_ord = nord
if start_ord is not None:
ord_pairs.append(start_ord)
ord_pairs.append(last_ord)
chars = "".join([chr(ch) for ch in ord_pairs])
return chars
def update_src_file(ts_file, chars):
ts_name = os.path.basename(ts_file)
pattern = re.compile('(// auto update.*' + ts_name + '.*\n[^"]+")[^"]*(".*)')
with open(src_path, "r", encoding="utf-8") as f:
original = f.read()
update = pattern.sub("\\1" + chars + "\\2", original)
if original != update:
with open(src_path, "w", encoding="utf-8") as f:
f.write(update)
print(f"Updated character list for {ts_file}.")
else:
print(f"Character list is unchanged for {ts_file}.")
if __name__ == "__main__":
for language in languages_to_update:
ts_file = os.path.join(ts_dir, f"pcsx2-qt_{language}.ts")
chars = parse_xml(ts_file)
print(f"{language}: {len(chars)} character(s) detected.")
update_src_file(ts_file, chars)

View File

@@ -49,6 +49,7 @@
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
<PreprocessorDefinitions>LZMA_API_STATIC;BUILD_DX=1;ENABLE_RAINTEGRATION;ENABLE_ACHIEVEMENTS;ENABLE_DISCORD_PRESENCE;ENABLE_OPENGL;ENABLE_VULKAN;SDL_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>QT_NO_EXCEPTIONS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<!-- Current Qt debug builds assert on RTTI. Remove this once we next build Qt. -->
<RuntimeTypeInfo Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(Debug))">true</RuntimeTypeInfo>
</ClCompile>
@@ -104,7 +105,7 @@
<ClCompile Include="Settings\BIOSSettingsWidget.cpp" />
<ClCompile Include="Settings\ControllerBindingWidgets.cpp" />
<ClCompile Include="Settings\ControllerGlobalSettingsWidget.cpp" />
<ClCompile Include="Settings\CreateMemoryCardDialog.cpp" />
<ClCompile Include="Settings\MemoryCardCreateDialog.cpp" />
<ClCompile Include="Settings\EmulationSettingsWidget.cpp" />
<ClCompile Include="Settings\GameListSettingsWidget.cpp" />
<ClCompile Include="Settings\GraphicsSettingsWidget.cpp" />
@@ -171,7 +172,7 @@
<QtMoc Include="Settings\GamePatchSettingsWidget.h" />
<ClInclude Include="Settings\HddCreateQt.h" />
<QtMoc Include="Settings\GameSummaryWidget.h" />
<QtMoc Include="Settings\CreateMemoryCardDialog.h" />
<QtMoc Include="Settings\MemoryCardCreateDialog.h" />
<QtMoc Include="Settings\AchievementLoginDialog.h" />
<QtMoc Include="Settings\AchievementSettingsWidget.h" />
<QtMoc Include="GameList\GameListModel.h" />
@@ -211,7 +212,7 @@
<ClCompile Include="$(IntDir)Settings\moc_ControllerBindingWidgets.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_ControllerGlobalSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_ControllerSettingsDialog.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_CreateMemoryCardDialog.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_MemoryCardCreateDialog.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_EmulationSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_GameListSettingsWidget.cpp" />
<ClCompile Include="$(IntDir)Settings\moc_GraphicsSettingsWidget.cpp" />
@@ -311,7 +312,7 @@
<QtUi Include="Settings\ControllerGlobalSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\CreateMemoryCardDialog.ui">
<QtUi Include="Settings\MemoryCardCreateDialog.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\AudioSettingsWidget.ui">

View File

@@ -190,10 +190,10 @@
<ClCompile Include="Settings\AudioSettingsWidget.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Settings\moc_CreateMemoryCardDialog.cpp">
<ClCompile Include="$(IntDir)Settings\moc_MemoryCardCreateDialog.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="Settings\CreateMemoryCardDialog.cpp">
<ClCompile Include="Settings\MemoryCardCreateDialog.cpp">
<Filter>Settings</Filter>
</ClCompile>
<ClCompile Include="Settings\DEV9DnsHostDialog.cpp">
@@ -423,7 +423,7 @@
<QtMoc Include="Settings\AudioSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\CreateMemoryCardDialog.h">
<QtMoc Include="Settings\MemoryCardCreateDialog.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\DEV9DnsHostDialog.h">
@@ -549,7 +549,7 @@
<QtUi Include="Settings\AudioSettingsWidget.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\CreateMemoryCardDialog.ui">
<QtUi Include="Settings\MemoryCardCreateDialog.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\DEV9DnsHostDialog.ui">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

View File

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -1,6 +1,6 @@
<RCC>
<qresource>
<file>icons/AppIcon.png</file>
<file>icons/AppIcon64.png</file>
<file>icons/applications-system-24.png</file>
<file>icons/black/index.theme</file>
<file>icons/black/svg/arrow-left-right-line.svg</file>

View File

@@ -30,6 +30,7 @@
#include "MTGS.h"
#include "VMManager.h"
#include "svnrev.h"
#include "SysForwardDefs.h"
#include "vtlb.h"
#include "common/Assertions.h"
@@ -1357,42 +1358,40 @@ std::string_view Achievements::GetELFNameForHash(const std::string& elf_path)
std::optional<std::vector<u8>> Achievements::ReadELFFromCurrentDisc(const std::string& elf_path)
{
// This CDVD stuff is super nasty and full of exceptions..
std::optional<std::vector<u8>> ret;
try
// ELF suffix hack. Taken from CDVD::loadElf
// MLB2k6 has an elf whose suffix is actually ;2
std::string filepath(elf_path);
const std::string::size_type semi_pos = filepath.rfind(';');
if (semi_pos != std::string::npos && std::string_view(filepath).substr(semi_pos) != ";1")
{
// ELF suffix hack. Taken from CDVD::loadElf
// MLB2k6 has an elf whose suffix is actually ;2
std::string filepath(elf_path);
const std::string::size_type semi_pos = filepath.rfind(';');
if (semi_pos != std::string::npos && std::string_view(filepath).substr(semi_pos) != ";1")
{
Console.Warning("(Achievements) Non-conforming version suffix (%s) detected and replaced.", elf_path.c_str());
filepath.erase(semi_pos);
filepath += ";1";
}
IsoFSCDVD isofs;
IsoFile file(isofs, filepath);
const u32 size = file.getLength();
ret = std::vector<u8>();
ret->resize(size);
if (size > 0)
{
const s32 bytes_read = file.read(ret->data(), static_cast<s32>(size));
if (bytes_read != static_cast<s32>(size))
{
Console.Error("(Achievements) Only read %d of %u bytes of ELF '%s'", bytes_read, size, elf_path.c_str());
ret.reset();
}
}
Console.Warning(fmt::format("(Achievements) Non-conforming version suffix ({}) detected and replaced.", elf_path));
filepath.erase(semi_pos);
filepath += ";1";
}
catch (...)
IsoFSCDVD isofs;
IsoFile file(isofs);
Error error;
if (!file.open(filepath, &error))
{
Console.Error("(Achievements) Caught exception while trying to read ELF '%s'.", elf_path.c_str());
ret.reset();
Console.Error(fmt::format("(Achievements) Failed to open ELF '{}' on disc: {}", elf_path, error.GetDescription()));
return ret;
}
const u32 size = file.getLength();
ret = std::vector<u8>();
ret->resize(size);
if (size > 0)
{
const s32 bytes_read = file.read(ret->data(), static_cast<s32>(size));
if (bytes_read != static_cast<s32>(size))
{
Console.Error(fmt::format("(Achievements) Only read {} of {} bytes of ELF '{}'", bytes_read, size, elf_path));
ret.reset();
}
}
return ret;

View File

@@ -19,6 +19,7 @@
#include "IopHw.h"
#include "IopDma.h"
#include "VMManager.h"
#include "Sio.h"
#include <cctype>
#include <ctime>
@@ -382,140 +383,118 @@ s32 cdvdWriteConfig(const u8* config)
return 0;
}
// Sets ElfCRC to the CRC of the game bound to the CDVD source.
std::unique_ptr<ElfObject> cdvdLoadElf(std::string filename, bool isPSXElf)
bool cdvdLoadElf(ElfObject* elfo, std::string elfpath, bool isPSXElf, Error* error)
{
if (StringUtil::StartsWith(filename, "host:"))
if (StringUtil::StartsWith(elfpath, "host:"))
{
std::string host_filename(filename.substr(5));
s64 host_size = FileSystem::GetPathFileSize(host_filename.c_str());
return std::make_unique<ElfObject>(std::move(host_filename), static_cast<u32>(std::max<s64>(host_size, 0)), isPSXElf);
std::string host_filename(elfpath.substr(5));
if (!elfo->OpenFile(host_filename, isPSXElf, error))
return false;
}
else
{
// Mimic PS2 behavior!
// Much trial-and-error with changing the ISOFS and BOOT2 contents of an image have shown that
// the PS2 BIOS performs the peculiar task of *ignoring* the version info from the parsed BOOT2
// filename *and* the ISOFS, when loading the game's ELF image. What this means is:
//
// 1. a valid PS2 ELF can have any version (ISOFS), and the version need not match the one in SYSTEM.CNF.
// 2. the version info on the file in the BOOT2 parameter of SYSTEM.CNF can be missing, 10 chars long,
// or anything else. Its all ignored.
// 3. Games loading their own files do *not* exhibit this behavior; likely due to using newer IOP modules
// or lower level filesystem APIs (fortunately that doesn't affect us).
//
// FIXME: Properly mimicing this behavior is troublesome since we need to add support for "ignoring"
// version information when doing file searches. I'll add this later. For now, assuming a ;1 should
// be sufficient (no known games have their ELF binary as anything but version ;1)
const std::string::size_type semi_pos = elfpath.rfind(';');
if (semi_pos != std::string::npos && std::string_view(elfpath).substr(semi_pos) != ";1")
{
Console.WriteLn(Color_Blue, "(LoadELF) Non-conforming version suffix (%s) detected and replaced.", elfpath.c_str());
elfpath.erase(semi_pos);
elfpath += ";1";
}
// Fix cdrom:path, the iso reader doesn't like it.
if (StringUtil::StartsWith(elfpath, "cdrom:") && elfpath[6] != '\\' && elfpath[6] != '/')
elfpath.insert(6, 1, '\\');
IsoFSCDVD isofs;
IsoFile file(isofs);
if (!file.open(elfpath, error) || !elfo->OpenIsoFile(elfpath, file, isPSXElf, error))
return false;
}
// Mimic PS2 behavior!
// Much trial-and-error with changing the ISOFS and BOOT2 contents of an image have shown that
// the PS2 BIOS performs the peculiar task of *ignoring* the version info from the parsed BOOT2
// filename *and* the ISOFS, when loading the game's ELF image. What this means is:
//
// 1. a valid PS2 ELF can have any version (ISOFS), and the version need not match the one in SYSTEM.CNF.
// 2. the version info on the file in the BOOT2 parameter of SYSTEM.CNF can be missing, 10 chars long,
// or anything else. Its all ignored.
// 3. Games loading their own files do *not* exhibit this behavior; likely due to using newer IOP modules
// or lower level filesystem APIs (fortunately that doesn't affect us).
//
// FIXME: Properly mimicing this behavior is troublesome since we need to add support for "ignoring"
// version information when doing file searches. I'll add this later. For now, assuming a ;1 should
// be sufficient (no known games have their ELF binary as anything but version ;1)
const std::string::size_type semi_pos = filename.rfind(';');
if (semi_pos != std::string::npos && std::string_view(filename).substr(semi_pos) != ";1")
{
Console.WriteLn(Color_Blue, "(LoadELF) Non-conforming version suffix (%s) detected and replaced.", filename.c_str());
filename.erase(semi_pos);
filename += ";1";
}
// Fix cdrom:path, the iso reader doesn't like it.
if (StringUtil::StartsWith(filename, "cdrom:") && filename[6] != '\\' && filename[6] != '/')
filename.insert(6, 1, '\\');
IsoFSCDVD isofs;
IsoFile file(isofs, filename);
return std::make_unique<ElfObject>(std::move(filename), file, isPSXElf);
return true;
}
u32 cdvdGetElfCRC(const std::string& path)
{
try
{
// Yay for write-after-read here. Isn't our ELF parser great....
const s64 host_size = FileSystem::GetPathFileSize(path.c_str());
if (host_size <= 0)
return 0;
std::unique_ptr<ElfObject> elfptr(std::make_unique<ElfObject>(path, static_cast<u32>(std::max<s64>(host_size, 0)), false));
elfptr->loadHeaders();
return elfptr->getCRC();
}
catch ([[maybe_unused]] Exception::FileNotFound& e)
{
ElfObject elfo;
if (!elfo.OpenFile(path, false, nullptr))
return 0;
}
return elfo.GetCRC();
}
// return value:
// 0 - Invalid or unknown disc.
// 1 - PS1 CD
// 2 - PS2 CD
static CDVDDiscType GetPS2ElfName(std::string* name, std::string* version)
{
CDVDDiscType retype = CDVDDiscType::Other;
name->clear();
version->clear();
try {
IsoFSCDVD isofs;
IsoFile file( isofs, "SYSTEM.CNF;1");
Error error;
IsoFSCDVD isofs;
IsoFile file(isofs);
if (!file.open("SYSTEM.CNF;1", &error))
{
Console.Error(fmt::format("(GetElfName) Failed to open SYSTEM.CNF: {}", error.GetDescription()));
return CDVDDiscType::Other;
}
int size = file.getLength();
if( size == 0 ) return CDVDDiscType::Other;
const int size = file.getLength();
if (size == 0)
return CDVDDiscType::Other;
while( !file.eof() )
{
const std::string line(file.readLine());
std::string_view key, value;
if (!StringUtil::ParseAssignmentString(line, &key, &value))
continue;
while (!file.eof())
{
const std::string line(file.readLine());
std::string_view key, value;
if (!StringUtil::ParseAssignmentString(line, &key, &value))
continue;
if( value.empty() && file.getLength() != file.getSeekPos() )
{ // Some games have a character on the last line of the file, don't print the error in those cases.
Console.Warning( "(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:" );
Console.Indent().WriteLn(line);
continue;
}
if( key == "BOOT2" )
{
Console.WriteLn( Color_StrongBlue, "(SYSTEM.CNF) Detected PS2 Disc = %.*s",
static_cast<int>(value.size()), value.data());
*name = value;
retype = CDVDDiscType::PS2Disc;
}
else if( key == "BOOT" )
{
Console.WriteLn( Color_StrongBlue, "(SYSTEM.CNF) Detected PSX/PSone Disc = %.*s",
static_cast<int>(value.size()), value.data());
*name = value;
retype = CDVDDiscType::PS1Disc;
}
else if( key == "VMODE" )
{
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Disc region type = %.*s",
static_cast<int>(value.size()), value.data());
}
else if( key == "VER" )
{
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Software version = %.*s",
static_cast<int>(value.size()), value.data());
*version = value;
}
if (value.empty() && file.getLength() != file.getSeekPos())
{ // Some games have a character on the last line of the file, don't print the error in those cases.
Console.Warning("(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:");
Console.Indent().WriteLn(line);
continue;
}
if( retype == CDVDDiscType::Other )
if (key == "BOOT2")
{
Console.Error("(GetElfName) Disc image is *not* a PlayStation or PS2 game!");
return CDVDDiscType::Other;
Console.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PS2 Disc = {}", value));
*name = value;
retype = CDVDDiscType::PS2Disc;
}
else if (key == "BOOT")
{
Console.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PSX/PSone Disc = {}", value));
*name = value;
retype = CDVDDiscType::PS1Disc;
}
else if (key == "VMODE")
{
Console.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Disc region type = {}", value));
}
else if (key == "VER")
{
Console.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Software version = {}", value));
*version = value;
}
}
catch( Exception::FileNotFound& )
{
//Console.Warning(ex.FormatDiagnosticMessage());
return CDVDDiscType::Other; // no SYSTEM.CNF, not a PS1/PS2 disc.
}
catch (Exception::BadStream& ex)
{
Console.Error(ex.FormatDiagnosticMessage());
return CDVDDiscType::Other; // ISO error
}
if (retype == CDVDDiscType::Other)
Console.Error("(GetElfName) Disc image is *not* a PlayStation or PS2 game!");
return retype;
}
@@ -585,21 +564,13 @@ void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::st
if (disc_type == CDVDDiscType::PS2Disc || disc_type == CDVDDiscType::PS1Disc)
{
try
{
const bool isPSXElf = (disc_type == CDVDDiscType::PS1Disc);
std::unique_ptr<ElfObject> elfptr(cdvdLoadElf(elfpath, isPSXElf));
elfptr->loadHeaders();
crc = elfptr->getCRC();
}
catch ([[maybe_unused]] Exception::FileNotFound& e)
{
Console.Error(fmt::format("Failed to load ELF info for {}", elfpath));
}
catch (Exception::BadStream& ex)
{
Console.Error(ex.FormatDiagnosticMessage());
}
Error error;
ElfObject elfo;
const bool isPSXElf = (disc_type == CDVDDiscType::PS1Disc);
if (!cdvdLoadElf(&elfo, elfpath, isPSXElf, &error))
Console.Error(fmt::format("Failed to load ELF info for {}: {}", elfpath, error.GetDescription()));
else
crc = elfo.GetCRC();
}
*out_crc = crc;
@@ -963,10 +934,14 @@ void cdvdReset()
cdvdCtrlTrayClose();
}
void SaveStateBase::cdvdFreeze()
bool SaveStateBase::cdvdFreeze()
{
FreezeTag("cdvd");
if (!FreezeTag("cdvd"))
return false;
Freeze(cdvd);
if (!IsOkay())
return false;
if (IsLoading())
{
@@ -977,6 +952,8 @@ void SaveStateBase::cdvdFreeze()
if (cdvd.Reading)
cdvd.RErr = DoCDVDreadTrack(cdvd.Readed ? cdvd.Sector : cdvd.SeekToSector, cdvd.ReadMode);
}
return true;
}
void cdvdNewDiskCB()
@@ -1528,6 +1505,7 @@ void cdvdVsync()
cdvd.RTCcount = 0;
cdvdUpdateTrayState();
AutoEject::CountDownTicks();
cdvd.RTC.second++;
if (cdvd.RTC.second < 60)

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